diff --git a/packages/core/runjs/src/compiler/__tests__/compiler-build-identity.test.ts b/packages/core/runjs/src/compiler/__tests__/compiler-build-identity.test.ts index a3bf7ab96e3..3f17bf1e59f 100644 --- a/packages/core/runjs/src/compiler/__tests__/compiler-build-identity.test.ts +++ b/packages/core/runjs/src/compiler/__tests__/compiler-build-identity.test.ts @@ -21,7 +21,7 @@ describe('RunJS compiler build identity', () => { it('is stable and content-addressed', () => { expect(buildRunJSCompilerBuildIdentity()).toEqual(RUNJS_COMPILER_BUILD_IDENTITY); expect(RUNJS_COMPILER_BUILD_IDENTITY.compilerBuildId).toMatch(/^[a-f0-9]{64}$/u); - expect(RUNJS_COMPILER_BUILD_IDENTITY.components.sourceInspectionPolicy).toBe('runjs.source-inspection.v3'); + expect(RUNJS_COMPILER_BUILD_IDENTITY.components.sourceInspectionPolicy).toBe('runjs.source-inspection.v5'); }); it('changes when any compiler build component changes', () => { diff --git a/packages/core/runjs/src/compiler/build-identity.ts b/packages/core/runjs/src/compiler/build-identity.ts index 537033b25f7..9f4a4cbd8c0 100644 --- a/packages/core/runjs/src/compiler/build-identity.ts +++ b/packages/core/runjs/src/compiler/build-identity.ts @@ -21,7 +21,7 @@ import { export const RUNJS_COMPILER_CONTRACT_VERSION = 'runjs.compiler.v2'; export const RUNJS_COMPILER_ENTRY_ADAPTER_CONTRACT_VERSION = 'runjs.entry-adapter.v2'; export const RUNJS_COMPILER_SOURCE_MAP_CONTRACT_VERSION = 'runjs.source-map.v1'; -export const RUNJS_COMPILER_SOURCE_INSPECTION_POLICY_VERSION = 'runjs.source-inspection.v3'; +export const RUNJS_COMPILER_SOURCE_INSPECTION_POLICY_VERSION = 'runjs.source-inspection.v5'; export interface RunJSCompilerBuildIdentityComponents { compilerContract: string; diff --git a/packages/core/runjs/src/typescript-diagnostic-policy.ts b/packages/core/runjs/src/typescript-diagnostic-policy.ts index 083c8add43b..58efd07b30f 100644 --- a/packages/core/runjs/src/typescript-diagnostic-policy.ts +++ b/packages/core/runjs/src/typescript-diagnostic-policy.ts @@ -47,6 +47,9 @@ export function shouldKeepRunJSTypeScriptDiagnostic( if (policy !== 'runjs-authoring') { return true; } + if (code === 2554) { + return false; + } if (code === 2339 && /^Property .+ does not exist on type ['"]unknown['"]\.$/.test(message)) { return false; } diff --git a/packages/core/runjs/src/typescript-project.ts b/packages/core/runjs/src/typescript-project.ts index 5a472f42aeb..c2c77ffa3f1 100644 --- a/packages/core/runjs/src/typescript-project.ts +++ b/packages/core/runjs/src/typescript-project.ts @@ -46,8 +46,10 @@ interface RunJSLogger { debug(...args: unknown[]): void; child(bindings: Record): RunJSLogger; } +// Values supplied dynamically by the RunJS runtime are permissive; explicit user-authored TypeScript types remain checked. +type RunJSDynamicValue = any; interface RunJSUnknownObject { - [key: string]: unknown; + [key: string]: RunJSDynamicValue; } interface RunJSRecord extends RunJSUnknownObject { id?: string | number; @@ -70,8 +72,8 @@ interface RunJSModel extends RunJSUnknownObject { readonly props?: RunJSUnknownObject; } interface RunJSForm extends RunJSUnknownObject { - getFieldValue(name: string | Array): unknown; - getFieldsValue(): Record; + getFieldValue(name: string | Array): RunJSDynamicValue; + getFieldsValue(): RunJSUnknownObject; setFieldValue(name: string | Array, value: unknown): void; setFieldsValue(values: Record): void; } @@ -98,24 +100,72 @@ interface RunJSNotification { destroy(key?: string): void; } interface RunJSModal { - info(config: Record): unknown; - success(config: Record): unknown; - error(config: Record): unknown; - warning(config: Record): unknown; - confirm(config: Record): unknown; + info(config: Record): RunJSDynamicValue; + success(config: Record): RunJSDynamicValue; + error(config: Record): RunJSDynamicValue; + warning(config: Record): RunJSDynamicValue; + confirm(config: Record): RunJSDynamicValue; } interface RunJSResource extends RunJSUnknownObject { + getData(): RunJSDynamicValue; + setData(value: RunJSDynamicValue): this; + hasData(): boolean; + getMeta(): RunJSUnknownObject; + getMeta(metaKey: string): RunJSDynamicValue; + setMeta(meta: RunJSUnknownObject): this; + getError(): RunJSDynamicValue; + clearError(): this; + on(event: string, callback: (...args: RunJSDynamicValue[]) => void): void; + off(event: string, callback: (...args: RunJSDynamicValue[]) => void): void; +} +interface RunJSAPIResource extends RunJSResource { + refresh(): Promise; +} +interface RunJSRecordResource extends RunJSAPIResource { + setResourceName(resourceName: string): this; + getResourceName(): string; + setSourceId(sourceId: string | number): this; + getSourceId(): string | number; + setDataSourceKey(dataSourceKey: string): this; + getDataSourceKey(): string; + setFilter(filter: RunJSUnknownObject): this; + getFilter(): RunJSDynamicValue; + setFilterByTk(filterByTk: RunJSDynamicValue): this; + runAction(action: string, options?: RunJSUnknownObject): Promise; + refresh(): Promise; +} +interface RunJSMultiRecordResource extends RunJSRecordResource { readonly selectedRows?: RunJSRecord[]; readonly pagination?: RunJSUnknownObject; - getData?(): unknown; - setData?(value: unknown): RunJSResource; - getSelectedRows?(): RunJSRecord[]; - setResourceName?(resourceName: string): RunJSResource; - setFilterByTk?(filterByTk: unknown): RunJSResource; - runAction?(action: string, options?: Record): Promise; - on?(event: string, callback: (...args: unknown[]) => void): void; - off?(event: string, callback: (...args: unknown[]) => void): void; - refresh?: () => Promise; + getData(): RunJSRecord[]; + getSelectedRows(): RunJSRecord[]; + setPage(page: number): this; + getPage(): number; + setPageSize(pageSize: number): this; + getPageSize(): number; + getCount(): number; + getTotalPage(): number; + next(): Promise; + previous(): Promise; + goto(page: number): Promise; +} +interface RunJSSingleRecordResource extends RunJSRecordResource { + save(data: RunJSDynamicValue, options?: RunJSUnknownObject): Promise; + destroy(options?: RunJSUnknownObject): Promise; +} +interface RunJSSQLResource extends RunJSRecordResource { + setPage(page: number): this; + getPage(): number; + setPageSize(pageSize: number): this; + getPageSize(): number; + setDebug(enabled: boolean): this; + setSQLType(type: 'selectRows' | 'selectRow' | 'selectVar'): this; + setSQL(sql: string): this; + setBind(bind: RunJSDynamicValue): this; + setLiquidContext(liquidContext: RunJSUnknownObject): this; + run(): Promise; + runBySQL(): Promise; + runById(): Promise; } interface RunJSApiResponse extends RunJSUnknownObject { data?: RunJSUnknownObject; @@ -136,10 +186,10 @@ interface RunJSAuth { readonly user?: RunJSRecord; } interface RunJSViewer { - dialog(props: Record): unknown; - drawer(props: Record): unknown; - popover(props: Record): unknown; - embed(props: Record): unknown; + dialog(props: Record): RunJSDynamicValue; + drawer(props: Record): RunJSDynamicValue; + popover(props: Record): RunJSDynamicValue; + embed(props: Record): RunJSDynamicValue; } interface RunJSPopup extends RunJSUnknownObject { readonly uid?: string; @@ -149,9 +199,9 @@ interface RunJSPopup extends RunJSUnknownObject { readonly resource?: RunJSUnknownObject; } interface RunJSSQL { - run(sql: string, options?: Record): Promise; + run(sql: string, options?: Record): Promise; save(data: { uid: string; sql: string; dataSourceKey?: string }): Promise; - runById(uid: string, options?: Record): Promise; + runById(uid: string, options?: Record): Promise; destroy(uid: string): Promise; } interface RunJSURLSearchParams { @@ -190,7 +240,7 @@ interface RunJSLibraries { lodash: RunJSLodashLibrary; math: RunJSMathLibrary; formula: RunJSFormulaLibrary; - [libraryName: string]: unknown; + [libraryName: string]: RunJSDynamicValue; } interface RunJSSourceInfo { readonly sourceMode: string; @@ -198,14 +248,14 @@ interface RunJSSourceInfo { readonly sourceMap?: string; readonly context?: RunJSUnknownObject; } -interface RunJSExecutionResult { +interface RunJSExecutionResult { readonly success: boolean; readonly value?: T; - readonly error?: unknown; + readonly error?: RunJSDynamicValue; readonly timeout?: boolean; } interface RunJSSafeElement extends RunJSUnknownObject { - readonly __el: unknown; + readonly __el: RunJSDynamicValue; addEventListener(type: string, listener: (event: RunJSUnknownObject) => void): void; removeEventListener(type: string, listener: (event: RunJSUnknownObject) => void): void; } @@ -247,26 +297,38 @@ interface RunJSContext { model: RunJSModel; render(value: unknown, container?: RunJSSafeElement): void; onRefReady(ref: RunJSRef, callback: (element: RunJSSafeElement) => void, timeout?: number): void; - getVar(path: string): Promise; - getVarInfos(options?: Record): Promise>; - getApiInfos(options?: Record): Promise>; - getEnvInfos(): Promise>; + getVar(path: string): Promise; + getVarInfos(options?: Record): Promise; + getApiInfos(options?: Record): Promise; + getEnvInfos(): Promise; getModel(uid: string, searchInPreviousEngines?: boolean): RunJSUnknownObject | undefined; - request(options: Record): Promise; - runjs( + request(options: Record): Promise; + runjs( code: string, variables?: Record, options?: Record, ): Promise>; loadCSS(href: string): Promise; - openView(uid: string, options?: Record): Promise; - requireAsync(url: string): Promise; - importAsync(url: string): Promise; - makeResource(type: unknown): RunJSResource; - createResource(type: unknown): RunJSResource; - initResource(type: string): RunJSResource; + openView(uid: string, options?: Record): Promise; + requireAsync(url: string): Promise; + importAsync(url: string): Promise; + makeResource(type: 'APIResource'): RunJSAPIResource; + makeResource(type: 'SingleRecordResource'): RunJSSingleRecordResource; + makeResource(type: 'MultiRecordResource'): RunJSMultiRecordResource; + makeResource(type: 'SQLResource'): RunJSSQLResource; + makeResource(type: unknown): T; + createResource(type: 'APIResource'): RunJSAPIResource; + createResource(type: 'SingleRecordResource'): RunJSSingleRecordResource; + createResource(type: 'MultiRecordResource'): RunJSMultiRecordResource; + createResource(type: 'SQLResource'): RunJSSQLResource; + createResource(type: unknown): T; + initResource(type: 'APIResource'): RunJSAPIResource; + initResource(type: 'SingleRecordResource'): RunJSSingleRecordResource; + initResource(type: 'MultiRecordResource'): RunJSMultiRecordResource; + initResource(type: 'SQLResource'): RunJSSQLResource; + initResource(type: string): T; resolveJsonTemplate(template: T): Promise; - runAction(name: string, params?: Record): Promise | unknown; + runAction(name: string, params?: Record): Promise | RunJSDynamicValue; previewRunJS(code: string, version?: string): Promise<{ success: boolean; message: string }>; t(key: string, options?: Record): string; view?: RunJSUnknownObject; @@ -288,12 +350,12 @@ interface RunJSContext { const genericRunJSContextDeclaration = ` interface RunJSContext { element?: RunJSSafeElement; - value?: unknown; + value?: RunJSDynamicValue; record?: RunJSRecord; collection?: RunJSCollection; collectionField?: RunJSCollectionField; form?: RunJSForm; - formValues?: Record; + formValues?: RunJSUnknownObject; namePath?: Array; disabled?: boolean; readOnly?: boolean; @@ -302,7 +364,7 @@ interface RunJSContext { recordIndex?: number; settings?: Record; runJsSource?: RunJSSourceInfo; - getValue?(): unknown; + getValue?(): RunJSDynamicValue; setValue?(value: unknown): void; setProps?(fieldModel: unknown, props: Record): void; refresh?(): Promise; @@ -313,14 +375,14 @@ const runJSContextModelDeclarations: Record = { JSBlockModel: ` interface RunJSContext { element: RunJSSafeElement; - value?: unknown; + value?: RunJSDynamicValue; record?: RunJSRecord; } `, JSFieldModel: ` interface RunJSContext { element: RunJSSafeElement; - value: unknown; + value: RunJSDynamicValue; record?: RunJSRecord; collection?: RunJSCollection; collectionField?: RunJSCollectionField; @@ -329,15 +391,15 @@ interface RunJSContext { JSEditableFieldModel: ` interface RunJSContext { element: RunJSSafeElement; - value: unknown; + value: RunJSDynamicValue; record?: RunJSRecord; collectionField?: RunJSCollectionField; form?: RunJSForm; - formValues?: Record; + formValues?: RunJSUnknownObject; namePath?: Array; disabled: boolean; readOnly: boolean; - getValue(): unknown; + getValue(): RunJSDynamicValue; setValue(value: unknown): void; } `, @@ -346,7 +408,7 @@ interface RunJSContext { element: RunJSSafeElement; record?: RunJSRecord; resource?: RunJSResource; - formValues?: Record; + formValues?: RunJSUnknownObject; item?: RunJSUnknownObject; } `, @@ -355,14 +417,14 @@ interface RunJSContext { element: RunJSSafeElement; record?: RunJSRecord; resource?: RunJSResource; - formValues?: Record; + formValues?: RunJSUnknownObject; item?: RunJSUnknownObject; } `, JSColumnModel: ` interface RunJSContext { element: RunJSSafeElement; - value: unknown; + value: RunJSDynamicValue; record?: RunJSRecord; recordIndex: number; collection?: RunJSCollection; @@ -388,7 +450,7 @@ interface RunJSContext { FilterFormJSActionModel: ` interface RunJSContext { form?: RunJSForm; - formValues?: Record; + formValues?: RunJSUnknownObject; } `, JSActionModel: `