summaryrefslogtreecommitdiff
path: root/packages/frontend/src/scripts/aiscript
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/scripts/aiscript')
-rw-r--r--packages/frontend/src/scripts/aiscript/api.ts46
-rw-r--r--packages/frontend/src/scripts/aiscript/common.ts15
-rw-r--r--packages/frontend/src/scripts/aiscript/ui.ts139
3 files changed, 138 insertions, 62 deletions
diff --git a/packages/frontend/src/scripts/aiscript/api.ts b/packages/frontend/src/scripts/aiscript/api.ts
index 46aed49330..e203c51bba 100644
--- a/packages/frontend/src/scripts/aiscript/api.ts
+++ b/packages/frontend/src/scripts/aiscript/api.ts
@@ -3,14 +3,24 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { utils, values } from '@syuilo/aiscript';
+import { errors, utils, values } from '@syuilo/aiscript';
import * as Misskey from 'misskey-js';
+import { url, lang } from '@@/js/config.js';
+import { assertStringAndIsIn } from './common.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { $i } from '@/account.js';
import { miLocalStorage } from '@/local-storage.js';
import { customEmojis } from '@/custom-emojis.js';
-import { url, lang } from '@@/js/config.js';
+
+const DIALOG_TYPES = [
+ 'error',
+ 'info',
+ 'success',
+ 'warning',
+ 'waiting',
+ 'question',
+] as const;
export function aiScriptReadline(q: string): Promise<string> {
return new Promise(ok => {
@@ -22,15 +32,20 @@ export function aiScriptReadline(q: string): Promise<string> {
});
}
-export function createAiScriptEnv(opts) {
+export function createAiScriptEnv(opts: { storageKey: string, token?: string }) {
return {
USER_ID: $i ? values.STR($i.id) : values.NULL,
- USER_NAME: $i ? values.STR($i.name) : values.NULL,
+ USER_NAME: $i?.name ? values.STR($i.name) : values.NULL,
USER_USERNAME: $i ? values.STR($i.username) : values.NULL,
CUSTOM_EMOJIS: utils.jsToVal(customEmojis.value),
LOCALE: values.STR(lang),
SERVER_URL: values.STR(url),
'Mk:dialog': values.FN_NATIVE(async ([title, text, type]) => {
+ utils.assertString(title);
+ utils.assertString(text);
+ if (type != null) {
+ assertStringAndIsIn(type, DIALOG_TYPES);
+ }
await os.alert({
type: type ? type.value : 'info',
title: title.value,
@@ -39,6 +54,11 @@ export function createAiScriptEnv(opts) {
return values.NULL;
}),
'Mk:confirm': values.FN_NATIVE(async ([title, text, type]) => {
+ utils.assertString(title);
+ utils.assertString(text);
+ if (type != null) {
+ assertStringAndIsIn(type, DIALOG_TYPES);
+ }
const confirm = await os.confirm({
type: type ? type.value : 'question',
title: title.value,
@@ -48,14 +68,20 @@ export function createAiScriptEnv(opts) {
}),
'Mk:api': values.FN_NATIVE(async ([ep, param, token]) => {
utils.assertString(ep);
- if (ep.value.includes('://')) throw new Error('invalid endpoint');
+ if (ep.value.includes('://')) {
+ throw new errors.AiScriptRuntimeError('invalid endpoint');
+ }
if (token) {
utils.assertString(token);
// バグがあればundefinedもあり得るため念のため
if (typeof token.value !== 'string') throw new Error('invalid token');
}
const actualToken: string|null = token?.value ?? opts.token ?? null;
- return misskeyApi(ep.value, utils.valToJs(param), actualToken).then(res => {
+ if (param == null) {
+ throw new errors.AiScriptRuntimeError('expected param');
+ }
+ utils.assertObject(param);
+ return misskeyApi(ep.value, utils.valToJs(param) as object, actualToken).then(res => {
return utils.jsToVal(res);
}, err => {
return values.ERROR('request_failed', utils.jsToVal(err));
@@ -75,12 +101,18 @@ export function createAiScriptEnv(opts) {
*/
'Mk:save': values.FN_NATIVE(([key, value]) => {
utils.assertString(key);
+ utils.expectAny(value);
miLocalStorage.setItem(`aiscript:${opts.storageKey}:${key.value}`, JSON.stringify(utils.valToJs(value)));
return values.NULL;
}),
'Mk:load': values.FN_NATIVE(([key]) => {
utils.assertString(key);
- return utils.jsToVal(JSON.parse(miLocalStorage.getItem(`aiscript:${opts.storageKey}:${key.value}`)));
+ return utils.jsToVal(miLocalStorage.getItemAsJson(`aiscript:${opts.storageKey}:${key.value}`) ?? null);
+ }),
+ 'Mk:remove': values.FN_NATIVE(([key]) => {
+ utils.assertString(key);
+ miLocalStorage.removeItem(`aiscript:${opts.storageKey}:${key.value}`);
+ return values.NULL;
}),
'Mk:url': values.FN_NATIVE(() => {
return values.STR(window.location.href);
diff --git a/packages/frontend/src/scripts/aiscript/common.ts b/packages/frontend/src/scripts/aiscript/common.ts
new file mode 100644
index 0000000000..de6fa1d633
--- /dev/null
+++ b/packages/frontend/src/scripts/aiscript/common.ts
@@ -0,0 +1,15 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { errors, utils, type values } from '@syuilo/aiscript';
+
+export function assertStringAndIsIn<A extends readonly string[]>(value: values.Value | undefined, expects: A): asserts value is values.VStr & { value: A[number] } {
+ utils.assertString(value);
+ const str = value.value;
+ if (!expects.includes(str)) {
+ const expected = expects.map((expect) => `"${expect}"`).join(', ');
+ throw new errors.AiScriptRuntimeError(`"${value.value}" is not in ${expected}`);
+ }
+}
diff --git a/packages/frontend/src/scripts/aiscript/ui.ts b/packages/frontend/src/scripts/aiscript/ui.ts
index 2b386bebb8..ca92b27ff5 100644
--- a/packages/frontend/src/scripts/aiscript/ui.ts
+++ b/packages/frontend/src/scripts/aiscript/ui.ts
@@ -7,6 +7,15 @@ import { utils, values } from '@syuilo/aiscript';
import { v4 as uuid } from 'uuid';
import { ref, Ref } from 'vue';
import * as Misskey from 'misskey-js';
+import { assertStringAndIsIn } from './common.js';
+
+const ALIGNS = ['left', 'center', 'right'] as const;
+const FONTS = ['serif', 'sans-serif', 'monospace'] as const;
+const BORDER_STYLES = ['hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset'] as const;
+
+type Align = (typeof ALIGNS)[number];
+type Font = (typeof FONTS)[number];
+type BorderStyle = (typeof BORDER_STYLES)[number];
export type AsUiComponentBase = {
id: string;
@@ -21,13 +30,13 @@ export type AsUiRoot = AsUiComponentBase & {
export type AsUiContainer = AsUiComponentBase & {
type: 'container';
children?: AsUiComponent['id'][];
- align?: 'left' | 'center' | 'right';
+ align?: Align;
bgColor?: string;
fgColor?: string;
- font?: 'serif' | 'sans-serif' | 'monospace';
+ font?: Font;
borderWidth?: number;
borderColor?: string;
- borderStyle?: 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
+ borderStyle?: BorderStyle;
borderRadius?: number;
padding?: number;
rounded?: boolean;
@@ -40,7 +49,7 @@ export type AsUiText = AsUiComponentBase & {
size?: number;
bold?: boolean;
color?: string;
- font?: 'serif' | 'sans-serif' | 'monospace';
+ font?: Font;
};
export type AsUiMfm = AsUiComponentBase & {
@@ -49,14 +58,14 @@ export type AsUiMfm = AsUiComponentBase & {
size?: number;
bold?: boolean;
color?: string;
- font?: 'serif' | 'sans-serif' | 'monospace';
- onClickEv?: (evId: string) => void
+ font?: Font;
+ onClickEv?: (evId: string) => Promise<void>;
};
export type AsUiButton = AsUiComponentBase & {
type: 'button';
text?: string;
- onClick?: () => void;
+ onClick?: () => Promise<void>;
primary?: boolean;
rounded?: boolean;
disabled?: boolean;
@@ -69,7 +78,7 @@ export type AsUiButtons = AsUiComponentBase & {
export type AsUiSwitch = AsUiComponentBase & {
type: 'switch';
- onChange?: (v: boolean) => void;
+ onChange?: (v: boolean) => Promise<void>;
default?: boolean;
label?: string;
caption?: string;
@@ -77,7 +86,7 @@ export type AsUiSwitch = AsUiComponentBase & {
export type AsUiTextarea = AsUiComponentBase & {
type: 'textarea';
- onInput?: (v: string) => void;
+ onInput?: (v: string) => Promise<void>;
default?: string;
label?: string;
caption?: string;
@@ -85,7 +94,7 @@ export type AsUiTextarea = AsUiComponentBase & {
export type AsUiTextInput = AsUiComponentBase & {
type: 'textInput';
- onInput?: (v: string) => void;
+ onInput?: (v: string) => Promise<void>;
default?: string;
label?: string;
caption?: string;
@@ -93,7 +102,7 @@ export type AsUiTextInput = AsUiComponentBase & {
export type AsUiNumberInput = AsUiComponentBase & {
type: 'numberInput';
- onInput?: (v: number) => void;
+ onInput?: (v: number) => Promise<void>;
default?: number;
label?: string;
caption?: string;
@@ -105,7 +114,7 @@ export type AsUiSelect = AsUiComponentBase & {
text: string;
value: string;
}[];
- onChange?: (v: string) => void;
+ onChange?: (v: string) => Promise<void>;
default?: string;
label?: string;
caption?: string;
@@ -140,11 +149,15 @@ export type AsUiPostForm = AsUiComponentBase & {
export type AsUiComponent = AsUiRoot | AsUiContainer | AsUiText | AsUiMfm | AsUiButton | AsUiButtons | AsUiSwitch | AsUiTextarea | AsUiTextInput | AsUiNumberInput | AsUiSelect | AsUiFolder | AsUiPostFormButton | AsUiPostForm;
+type Options<T extends AsUiComponent> = T extends AsUiButtons
+ ? Omit<T, 'id' | 'type' | 'buttons'> & { 'buttons'?: Options<AsUiButton>[] }
+ : Omit<T, 'id' | 'type'>;
+
export function patch(id: string, def: values.Value, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>) {
// TODO
}
-function getRootOptions(def: values.Value | undefined): Omit<AsUiRoot, 'id' | 'type'> {
+function getRootOptions(def: values.Value | undefined): Options<AsUiRoot> {
utils.assertObject(def);
const children = def.value.get('children');
@@ -153,30 +166,32 @@ function getRootOptions(def: values.Value | undefined): Omit<AsUiRoot, 'id' | 't
return {
children: children.value.map(v => {
utils.assertObject(v);
- return v.value.get('id').value;
+ const id = v.value.get('id');
+ utils.assertString(id);
+ return id.value;
}),
};
}
-function getContainerOptions(def: values.Value | undefined): Omit<AsUiContainer, 'id' | 'type'> {
+function getContainerOptions(def: values.Value | undefined): Options<AsUiContainer> {
utils.assertObject(def);
const children = def.value.get('children');
if (children) utils.assertArray(children);
const align = def.value.get('align');
- if (align) utils.assertString(align);
+ if (align) assertStringAndIsIn(align, ALIGNS);
const bgColor = def.value.get('bgColor');
if (bgColor) utils.assertString(bgColor);
const fgColor = def.value.get('fgColor');
if (fgColor) utils.assertString(fgColor);
const font = def.value.get('font');
- if (font) utils.assertString(font);
+ if (font) assertStringAndIsIn(font, FONTS);
const borderWidth = def.value.get('borderWidth');
if (borderWidth) utils.assertNumber(borderWidth);
const borderColor = def.value.get('borderColor');
if (borderColor) utils.assertString(borderColor);
const borderStyle = def.value.get('borderStyle');
- if (borderStyle) utils.assertString(borderStyle);
+ if (borderStyle) assertStringAndIsIn(borderStyle, BORDER_STYLES);
const borderRadius = def.value.get('borderRadius');
if (borderRadius) utils.assertNumber(borderRadius);
const padding = def.value.get('padding');
@@ -189,7 +204,9 @@ function getContainerOptions(def: values.Value | undefined): Omit<AsUiContainer,
return {
children: children ? children.value.map(v => {
utils.assertObject(v);
- return v.value.get('id').value;
+ const id = v.value.get('id');
+ utils.assertString(id);
+ return id.value;
}) : [],
align: align?.value,
fgColor: fgColor?.value,
@@ -205,7 +222,7 @@ function getContainerOptions(def: values.Value | undefined): Omit<AsUiContainer,
};
}
-function getTextOptions(def: values.Value | undefined): Omit<AsUiText, 'id' | 'type'> {
+function getTextOptions(def: values.Value | undefined): Options<AsUiText> {
utils.assertObject(def);
const text = def.value.get('text');
@@ -217,7 +234,7 @@ function getTextOptions(def: values.Value | undefined): Omit<AsUiText, 'id' | 't
const color = def.value.get('color');
if (color) utils.assertString(color);
const font = def.value.get('font');
- if (font) utils.assertString(font);
+ if (font) assertStringAndIsIn(font, FONTS);
return {
text: text?.value,
@@ -228,7 +245,7 @@ function getTextOptions(def: values.Value | undefined): Omit<AsUiText, 'id' | 't
};
}
-function getMfmOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiMfm, 'id' | 'type'> {
+function getMfmOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiMfm> {
utils.assertObject(def);
const text = def.value.get('text');
@@ -240,7 +257,7 @@ function getMfmOptions(def: values.Value | undefined, call: (fn: values.VFn, arg
const color = def.value.get('color');
if (color) utils.assertString(color);
const font = def.value.get('font');
- if (font) utils.assertString(font);
+ if (font) assertStringAndIsIn(font, FONTS);
const onClickEv = def.value.get('onClickEv');
if (onClickEv) utils.assertFunction(onClickEv);
@@ -250,13 +267,13 @@ function getMfmOptions(def: values.Value | undefined, call: (fn: values.VFn, arg
bold: bold?.value,
color: color?.value,
font: font?.value,
- onClickEv: (evId: string) => {
- if (onClickEv) call(onClickEv, [values.STR(evId)]);
+ onClickEv: async (evId: string) => {
+ if (onClickEv) await call(onClickEv, [values.STR(evId)]);
},
};
}
-function getTextInputOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiTextInput, 'id' | 'type'> {
+function getTextInputOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiTextInput> {
utils.assertObject(def);
const onInput = def.value.get('onInput');
@@ -269,8 +286,8 @@ function getTextInputOptions(def: values.Value | undefined, call: (fn: values.VF
if (caption) utils.assertString(caption);
return {
- onInput: (v) => {
- if (onInput) call(onInput, [utils.jsToVal(v)]);
+ onInput: async (v) => {
+ if (onInput) await call(onInput, [utils.jsToVal(v)]);
},
default: defaultValue?.value,
label: label?.value,
@@ -278,7 +295,7 @@ function getTextInputOptions(def: values.Value | undefined, call: (fn: values.VF
};
}
-function getTextareaOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiTextarea, 'id' | 'type'> {
+function getTextareaOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiTextarea> {
utils.assertObject(def);
const onInput = def.value.get('onInput');
@@ -291,8 +308,8 @@ function getTextareaOptions(def: values.Value | undefined, call: (fn: values.VFn
if (caption) utils.assertString(caption);
return {
- onInput: (v) => {
- if (onInput) call(onInput, [utils.jsToVal(v)]);
+ onInput: async (v) => {
+ if (onInput) await call(onInput, [utils.jsToVal(v)]);
},
default: defaultValue?.value,
label: label?.value,
@@ -300,7 +317,7 @@ function getTextareaOptions(def: values.Value | undefined, call: (fn: values.VFn
};
}
-function getNumberInputOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiNumberInput, 'id' | 'type'> {
+function getNumberInputOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiNumberInput> {
utils.assertObject(def);
const onInput = def.value.get('onInput');
@@ -313,8 +330,8 @@ function getNumberInputOptions(def: values.Value | undefined, call: (fn: values.
if (caption) utils.assertString(caption);
return {
- onInput: (v) => {
- if (onInput) call(onInput, [utils.jsToVal(v)]);
+ onInput: async (v) => {
+ if (onInput) await call(onInput, [utils.jsToVal(v)]);
},
default: defaultValue?.value,
label: label?.value,
@@ -322,7 +339,7 @@ function getNumberInputOptions(def: values.Value | undefined, call: (fn: values.
};
}
-function getButtonOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiButton, 'id' | 'type'> {
+function getButtonOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiButton> {
utils.assertObject(def);
const text = def.value.get('text');
@@ -338,8 +355,8 @@ function getButtonOptions(def: values.Value | undefined, call: (fn: values.VFn,
return {
text: text?.value,
- onClick: () => {
- if (onClick) call(onClick, []);
+ onClick: async () => {
+ if (onClick) await call(onClick, []);
},
primary: primary?.value,
rounded: rounded?.value,
@@ -347,7 +364,7 @@ function getButtonOptions(def: values.Value | undefined, call: (fn: values.VFn,
};
}
-function getButtonsOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiButtons, 'id' | 'type'> {
+function getButtonsOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiButtons> {
utils.assertObject(def);
const buttons = def.value.get('buttons');
@@ -369,8 +386,8 @@ function getButtonsOptions(def: values.Value | undefined, call: (fn: values.VFn,
return {
text: text.value,
- onClick: () => {
- call(onClick, []);
+ onClick: async () => {
+ await call(onClick, []);
},
primary: primary?.value,
rounded: rounded?.value,
@@ -380,7 +397,7 @@ function getButtonsOptions(def: values.Value | undefined, call: (fn: values.VFn,
};
}
-function getSwitchOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiSwitch, 'id' | 'type'> {
+function getSwitchOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiSwitch> {
utils.assertObject(def);
const onChange = def.value.get('onChange');
@@ -393,8 +410,8 @@ function getSwitchOptions(def: values.Value | undefined, call: (fn: values.VFn,
if (caption) utils.assertString(caption);
return {
- onChange: (v) => {
- if (onChange) call(onChange, [utils.jsToVal(v)]);
+ onChange: async (v) => {
+ if (onChange) await call(onChange, [utils.jsToVal(v)]);
},
default: defaultValue?.value,
label: label?.value,
@@ -402,7 +419,7 @@ function getSwitchOptions(def: values.Value | undefined, call: (fn: values.VFn,
};
}
-function getSelectOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiSelect, 'id' | 'type'> {
+function getSelectOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiSelect> {
utils.assertObject(def);
const items = def.value.get('items');
@@ -428,8 +445,8 @@ function getSelectOptions(def: values.Value | undefined, call: (fn: values.VFn,
value: value ? value.value : text.value,
};
}) : [],
- onChange: (v) => {
- if (onChange) call(onChange, [utils.jsToVal(v)]);
+ onChange: async (v) => {
+ if (onChange) await call(onChange, [utils.jsToVal(v)]);
},
default: defaultValue?.value,
label: label?.value,
@@ -437,7 +454,7 @@ function getSelectOptions(def: values.Value | undefined, call: (fn: values.VFn,
};
}
-function getFolderOptions(def: values.Value | undefined): Omit<AsUiFolder, 'id' | 'type'> {
+function getFolderOptions(def: values.Value | undefined): Options<AsUiFolder> {
utils.assertObject(def);
const children = def.value.get('children');
@@ -450,7 +467,9 @@ function getFolderOptions(def: values.Value | undefined): Omit<AsUiFolder, 'id'
return {
children: children ? children.value.map(v => {
utils.assertObject(v);
- return v.value.get('id').value;
+ const id = v.value.get('id');
+ utils.assertString(id);
+ return id.value;
}) : [],
title: title?.value ?? '',
opened: opened?.value ?? true,
@@ -475,7 +494,7 @@ function getPostFormProps(form: values.VObj): PostFormPropsForAsUi {
};
}
-function getPostFormButtonOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiPostFormButton, 'id' | 'type'> {
+function getPostFormButtonOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiPostFormButton> {
utils.assertObject(def);
const text = def.value.get('text');
@@ -497,7 +516,7 @@ function getPostFormButtonOptions(def: values.Value | undefined, call: (fn: valu
};
}
-function getPostFormOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Omit<AsUiPostForm, 'id' | 'type'> {
+function getPostFormOptions(def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>): Options<AsUiPostForm> {
utils.assertObject(def);
const form = def.value.get('form');
@@ -511,18 +530,26 @@ function getPostFormOptions(def: values.Value | undefined, call: (fn: values.VFn
}
export function registerAsUiLib(components: Ref<AsUiComponent>[], done: (root: Ref<AsUiRoot>) => void) {
+ type OptionsConverter<T extends AsUiComponent, C> = (def: values.Value | undefined, call: C) => Options<T>;
+
const instances = {};
- function createComponentInstance(type: AsUiComponent['type'], def: values.Value | undefined, id: values.Value | undefined, getOptions: (def: values.Value | undefined, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>) => any, call: (fn: values.VFn, args: values.Value[]) => Promise<values.Value>) {
+ function createComponentInstance<T extends AsUiComponent, C>(
+ type: T['type'],
+ def: values.Value | undefined,
+ id: values.Value | undefined,
+ getOptions: OptionsConverter<T, C>,
+ call: C,
+ ) {
if (id) utils.assertString(id);
const _id = id?.value ?? uuid();
const component = ref({
...getOptions(def, call),
type,
id: _id,
- });
+ } as T);
components.push(component);
- const instance = values.OBJ(new Map([
+ const instance = values.OBJ(new Map<string, values.Value>([
['id', values.STR(_id)],
['update', values.FN_NATIVE(([def], opts) => {
utils.assertObject(def);
@@ -547,7 +574,7 @@ export function registerAsUiLib(components: Ref<AsUiComponent>[], done: (root: R
'Ui:patch': values.FN_NATIVE(([id, val], opts) => {
utils.assertString(id);
utils.assertArray(val);
- patch(id.value, val.value, opts.call);
+ // patch(id.value, val.value, opts.call); // TODO
}),
'Ui:get': values.FN_NATIVE(([id], opts) => {
@@ -566,7 +593,9 @@ export function registerAsUiLib(components: Ref<AsUiComponent>[], done: (root: R
rootComponent.value.children = children.value.map(v => {
utils.assertObject(v);
- return v.value.get('id').value;
+ const id = v.value.get('id');
+ utils.assertString(id);
+ return id.value;
});
}),