chore(variable): move json schema logic from variable core to materials (#256)

This commit is contained in:
Yiwei Mao 2025-05-22 22:17:23 +08:00 committed by GitHub
parent f2abdd8cca
commit 11dda65150
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 248 additions and 228 deletions

View File

@ -1,3 +1,4 @@
import { JsonSchemaUtils } from '@flowgram.ai/form-materials';
import { import {
definePluginCreator, definePluginCreator,
FlowNodeVariableData, FlowNodeVariableData,
@ -37,7 +38,7 @@ export const createSyncVariablePlugin: PluginCreator<SyncVariablePluginOptions>
// Create an Type AST from the output data's JSON schema // Create an Type AST from the output data's JSON schema
// NOTICE: You can create a new function to generate an AST based on YOUR CUSTOM DSL // NOTICE: You can create a new function to generate an AST based on YOUR CUSTOM DSL
const typeAST = ASTFactory.createTypeASTFromSchema(value); const typeAST = JsonSchemaUtils.schemaToAST(value);
if (typeAST) { if (typeAST) {
// Use the node's title or its ID as the title for the variable // Use the node's title or its ID as the title for the variable

View File

@ -1,4 +1,4 @@
import type { VarJSONSchema } from '@flowgram.ai/fixed-layout-editor'; import type { IJsonSchema, IBasicJsonSchema } from '@flowgram.ai/form-materials';
export type BasicType = VarJSONSchema.BasicType; export type BasicType = IBasicJsonSchema;
export type JsonSchema = VarJSONSchema.ISchema; export type JsonSchema = IJsonSchema;

View File

@ -6,6 +6,7 @@ import {
FreeLayoutPluginContext, FreeLayoutPluginContext,
ASTFactory, ASTFactory,
} from '@flowgram.ai/free-layout-editor'; } from '@flowgram.ai/free-layout-editor';
import { JsonSchemaUtils } from '@flowgram.ai/form-materials';
export interface SyncVariablePluginOptions {} export interface SyncVariablePluginOptions {}
@ -37,7 +38,7 @@ export const createSyncVariablePlugin: PluginCreator<SyncVariablePluginOptions>
// Create an Type AST from the output data's JSON schema // Create an Type AST from the output data's JSON schema
// NOTICE: You can create a new function to generate an AST based on YOUR CUSTOM DSL // NOTICE: You can create a new function to generate an AST based on YOUR CUSTOM DSL
const typeAST = ASTFactory.createTypeASTFromSchema(value); const typeAST = JsonSchemaUtils.schemaToAST(value);
if (typeAST) { if (typeAST) {
// Use the node's title or its ID as the title for the variable // Use the node's title or its ID as the title for the variable

View File

@ -1,4 +1,4 @@
import type { VarJSONSchema } from '@flowgram.ai/free-layout-editor'; import type { IJsonSchema, IBasicJsonSchema } from '@flowgram.ai/form-materials';
export type BasicType = VarJSONSchema.BasicType; export type BasicType = IBasicJsonSchema;
export type JsonSchema = VarJSONSchema.ISchema; export type JsonSchema = IJsonSchema;

View File

@ -1,10 +1,11 @@
import React from 'react'; import React from 'react';
import { PrivateScopeProvider, VarJSONSchema } from '@flowgram.ai/editor'; import { PrivateScopeProvider } from '@flowgram.ai/editor';
import { VariableSelector, VariableSelectorProps } from '../variable-selector'; import { VariableSelector, VariableSelectorProps } from '../variable-selector';
import { IJsonSchema } from '../../typings';
const batchVariableSchema: VarJSONSchema.ISchema = { const batchVariableSchema: IJsonSchema = {
type: 'array', type: 'array',
extra: { weak: true }, extra: { weak: true },
}; };

View File

@ -1,7 +1,7 @@
import { VarJSONSchema } from '@flowgram.ai/editor'; import { IJsonSchema } from '../../typings';
export interface Strategy<Value = any> { export interface Strategy<Value = any> {
hit: (schema: VarJSONSchema.ISchema) => boolean; hit: (schema: IJsonSchema) => boolean;
Renderer: React.FC<RendererProps<Value>>; Renderer: React.FC<RendererProps<Value>>;
} }
@ -12,7 +12,7 @@ export interface RendererProps<Value = any> {
} }
export interface PropsType extends RendererProps { export interface PropsType extends RendererProps {
schema: VarJSONSchema.ISchema; schema: IJsonSchema;
strategies?: Strategy[]; strategies?: Strategy[];
[key: string]: any; [key: string]: any;
} }

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { VarJSONSchema } from '@flowgram.ai/editor';
import { IconButton } from '@douyinfe/semi-ui'; import { IconButton } from '@douyinfe/semi-ui';
import { IconSetting } from '@douyinfe/semi-icons'; import { IconSetting } from '@douyinfe/semi-icons';
@ -9,6 +8,7 @@ import { ConstantInput } from '../constant-input';
import { IFlowConstantRefValue } from '../../typings/flow-value'; import { IFlowConstantRefValue } from '../../typings/flow-value';
import { UIContainer, UIMain, UITrigger } from './styles'; import { UIContainer, UIMain, UITrigger } from './styles';
import { VariableSelector } from '../variable-selector'; import { VariableSelector } from '../variable-selector';
import { IJsonSchema } from '../../typings';
interface PropsType { interface PropsType {
value?: IFlowConstantRefValue; value?: IFlowConstantRefValue;
@ -16,7 +16,7 @@ interface PropsType {
readonly?: boolean; readonly?: boolean;
hasError?: boolean; hasError?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;
schema?: VarJSONSchema.ISchema; schema?: IJsonSchema;
constantProps?: { constantProps?: {
strategies?: Strategy[]; strategies?: Strategy[];
[key: string]: any; [key: string]: any;

View File

@ -1,5 +1,5 @@
{ {
"name": "json-schema-editor", "name": "json-schema-editor",
"depMaterials": ["type-selector"], "depMaterials": ["type-selector", "typings/json-schema"],
"depPackages": ["@douyinfe/semi-ui", "@douyinfe/semi-icons", "styled-components"] "depPackages": ["@douyinfe/semi-ui", "@douyinfe/semi-icons", "styled-components"]
} }

View File

@ -1,7 +1,7 @@
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import { IJsonSchema } from '../../typings';
import { PropertyValueType } from './types'; import { PropertyValueType } from './types';
import { JsonSchema } from '../type-selector';
let _id = 0; let _id = 0;
function genId() { function genId() {
@ -100,7 +100,7 @@ export function usePropertiesEdit(
const next = updater(_list); const next = updater(_list);
// onChange to parent // onChange to parent
const nextProperties: Record<string, JsonSchema> = {}; const nextProperties: Record<string, IJsonSchema> = {};
const nextRequired: string[] = []; const nextRequired: string[] = [];
for (const _property of next) { for (const _property of next) {

View File

@ -10,8 +10,8 @@ import {
IconMinus, IconMinus,
} from '@douyinfe/semi-icons'; } from '@douyinfe/semi-icons';
import { JsonSchema } from '../type-selector/types';
import { TypeSelector } from '../type-selector'; import { TypeSelector } from '../type-selector';
import { IJsonSchema } from '../../typings';
import { ConfigType, PropertyValueType } from './types'; import { ConfigType, PropertyValueType } from './types';
import { import {
IconAddChildren, IconAddChildren,
@ -33,8 +33,8 @@ import { UIRow } from './styles';
import { usePropertiesEdit } from './hooks'; import { usePropertiesEdit } from './hooks';
export function JsonSchemaEditor(props: { export function JsonSchemaEditor(props: {
value?: JsonSchema; value?: IJsonSchema;
onChange?: (value: JsonSchema) => void; onChange?: (value: IJsonSchema) => void;
config?: ConfigType; config?: ConfigType;
}) { }) {
const { value = { type: 'object' }, config = {}, onChange: onChangeProps } = props; const { value = { type: 'object' }, config = {}, onChange: onChangeProps } = props;

View File

@ -1,6 +1,6 @@
import { JsonSchema } from '../type-selector/types'; import { IJsonSchema } from '../../typings';
export interface PropertyValueType extends JsonSchema { export interface PropertyValueType extends IJsonSchema {
name?: string; name?: string;
key?: number; key?: number;
isPropertyRequired?: boolean; isPropertyRequired?: boolean;
@ -8,7 +8,7 @@ export interface PropertyValueType extends JsonSchema {
export type PropertiesValueType = Pick<PropertyValueType, 'properties' | 'required'>; export type PropertiesValueType = Pick<PropertyValueType, 'properties' | 'required'>;
export type JsonSchemaProperties = JsonSchema['properties']; export type JsonSchemaProperties = IJsonSchema['properties'];
export interface ConfigType { export interface ConfigType {
placeholder?: string; placeholder?: string;

View File

@ -1,5 +1,5 @@
{ {
"name": "type-selector", "name": "type-selector",
"depMaterials": [], "depMaterials": ["typings/json-schema"],
"depPackages": ["@douyinfe/semi-ui", "@douyinfe/semi-icons"] "depPackages": ["@douyinfe/semi-ui", "@douyinfe/semi-icons"]
} }

View File

@ -3,7 +3,7 @@ import React from 'react';
import { CascaderData } from '@douyinfe/semi-ui/lib/es/cascader'; import { CascaderData } from '@douyinfe/semi-ui/lib/es/cascader';
import Icon from '@douyinfe/semi-icons'; import Icon from '@douyinfe/semi-icons';
import { JsonSchema } from './types'; import { IJsonSchema } from '../../typings';
export const VariableTypeIcons: { [key: string]: React.ReactNode } = { export const VariableTypeIcons: { [key: string]: React.ReactNode } = {
custom: ( custom: (
@ -271,7 +271,7 @@ export const ArrayIcons: { [key: string]: React.ReactNode } = {
), ),
}; };
export const getSchemaIcon = (value?: Partial<JsonSchema>) => { export const getSchemaIcon = (value?: Partial<IJsonSchema>) => {
if (value?.type === 'array') { if (value?.type === 'array') {
return ArrayIcons[value.items?.type || 'object']; return ArrayIcons[value.items?.type || 'object'];
} }

View File

@ -2,17 +2,17 @@ import React, { useMemo } from 'react';
import { Button, Cascader } from '@douyinfe/semi-ui'; import { Button, Cascader } from '@douyinfe/semi-ui';
import { JsonSchema } from './types'; import { IJsonSchema } from '../../typings';
import { ArrayIcons, VariableTypeIcons, getSchemaIcon, options } from './constants'; import { ArrayIcons, VariableTypeIcons, getSchemaIcon, options } from './constants';
interface PropTypes { interface PropTypes {
value?: Partial<JsonSchema>; value?: Partial<IJsonSchema>;
onChange: (value?: Partial<JsonSchema>) => void; onChange: (value?: Partial<IJsonSchema>) => void;
disabled?: boolean; disabled?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;
} }
export const getTypeSelectValue = (value?: Partial<JsonSchema>): string[] | undefined => { export const getTypeSelectValue = (value?: Partial<IJsonSchema>): string[] | undefined => {
if (value?.type === 'array' && value?.items) { if (value?.type === 'array' && value?.items) {
return [value.type, ...(getTypeSelectValue(value.items) || [])]; return [value.type, ...(getTypeSelectValue(value.items) || [])];
} }
@ -20,7 +20,7 @@ export const getTypeSelectValue = (value?: Partial<JsonSchema>): string[] | unde
return value?.type ? [value.type] : undefined; return value?.type ? [value.type] : undefined;
}; };
export const parseTypeSelectValue = (value?: string[]): Partial<JsonSchema> | undefined => { export const parseTypeSelectValue = (value?: string[]): Partial<IJsonSchema> | undefined => {
const [type, ...subTypes] = value || []; const [type, ...subTypes] = value || [];
if (type === 'array') { if (type === 'array') {
@ -54,4 +54,4 @@ export function TypeSelector(props: PropTypes) {
); );
} }
export { JsonSchema, VariableTypeIcons, ArrayIcons, getSchemaIcon }; export { VariableTypeIcons, ArrayIcons, getSchemaIcon };

View File

@ -1,5 +0,0 @@
import { VarJSONSchema } from '@flowgram.ai/editor';
export type BasicType = VarJSONSchema.BasicType;
export type JsonSchema = VarJSONSchema.ISchema;

View File

@ -1,5 +1,5 @@
{ {
"name": "variable-selector", "name": "variable-selector",
"depMaterials": ["type-selector"], "depMaterials": ["type-selector", "utils/json-schema", "typings/json-schema"],
"depPackages": ["@douyinfe/semi-ui", "styled-components"] "depPackages": ["@douyinfe/semi-ui", "styled-components"]
} }

View File

@ -1,10 +1,10 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { VarJSONSchema } from '@flowgram.ai/editor';
import { TriggerRenderProps } from '@douyinfe/semi-ui/lib/es/treeSelect'; import { TriggerRenderProps } from '@douyinfe/semi-ui/lib/es/treeSelect';
import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree'; import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
import { IconChevronDownStroked, IconIssueStroked } from '@douyinfe/semi-icons'; import { IconChevronDownStroked, IconIssueStroked } from '@douyinfe/semi-icons';
import { IJsonSchema } from '../../typings/json-schema';
import { useVariableTree } from './use-variable-tree'; import { useVariableTree } from './use-variable-tree';
import { UIRootTitle, UITag, UITreeSelect } from './styles'; import { UIRootTitle, UITag, UITreeSelect } from './styles';
@ -15,8 +15,8 @@ interface PropTypes {
notFoundContent?: string; notFoundContent?: string;
}; };
onChange: (value?: string[]) => void; onChange: (value?: string[]) => void;
includeSchema?: VarJSONSchema.ISchema | VarJSONSchema.ISchema[]; includeSchema?: IJsonSchema | IJsonSchema[];
excludeSchema?: VarJSONSchema.ISchema | VarJSONSchema.ISchema[]; excludeSchema?: IJsonSchema | IJsonSchema[];
readonly?: boolean; readonly?: boolean;
hasError?: boolean; hasError?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;

View File

@ -1,16 +1,18 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useScopeAvailable, ASTMatch, BaseVariableField, VarJSONSchema } from '@flowgram.ai/editor'; import { useScopeAvailable, ASTMatch, BaseVariableField } from '@flowgram.ai/editor';
import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree'; import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
import { Icon } from '@douyinfe/semi-ui'; import { Icon } from '@douyinfe/semi-ui';
import { ArrayIcons, VariableTypeIcons } from '../type-selector/constants'; import { ArrayIcons, VariableTypeIcons } from '../type-selector/constants';
import { JsonSchemaUtils } from '../../utils/json-schema';
import { IJsonSchema } from '../../typings/json-schema';
type VariableField = BaseVariableField<{ icon?: string | JSX.Element; title?: string }>; type VariableField = BaseVariableField<{ icon?: string | JSX.Element; title?: string }>;
export function useVariableTree(params: { export function useVariableTree(params: {
includeSchema?: VarJSONSchema.ISchema | VarJSONSchema.ISchema[]; includeSchema?: IJsonSchema | IJsonSchema[];
excludeSchema?: VarJSONSchema.ISchema | VarJSONSchema.ISchema[]; excludeSchema?: IJsonSchema | IJsonSchema[];
}): TreeNodeData[] { }): TreeNodeData[] {
const { includeSchema, excludeSchema } = params; const { includeSchema, excludeSchema } = params;
@ -68,8 +70,12 @@ export function useVariableTree(params: {
const keyPath = [...parentFields.map((_field) => _field.key), variable.key]; const keyPath = [...parentFields.map((_field) => _field.key), variable.key];
const key = keyPath.join('.'); const key = keyPath.join('.');
const isSchemaInclude = includeSchema ? type.isEqualWithJSONSchema(includeSchema) : true; const isSchemaInclude = includeSchema
const isSchemaExclude = excludeSchema ? type.isEqualWithJSONSchema(excludeSchema) : false; ? JsonSchemaUtils.isASTMatchSchema(type, includeSchema)
: true;
const isSchemaExclude = excludeSchema
? JsonSchemaUtils.isASTMatchSchema(type, excludeSchema)
: false;
const isSchemaMatch = isSchemaInclude && !isSchemaExclude; const isSchemaMatch = isSchemaInclude && !isSchemaExclude;
// If not match, and no children, return null // If not match, and no children, return null

View File

@ -1 +1,2 @@
export * from './flow-value'; export * from './flow-value';
export * from './json-schema';

View File

@ -0,0 +1,5 @@
{
"name": "json-schema",
"depMaterials": [],
"depPackages": []
}

View File

@ -0,0 +1,31 @@
export type JsonSchemaBasicType =
| 'boolean'
| 'string'
| 'integer'
| 'number'
| 'object'
| 'array'
| 'map';
export interface IJsonSchema<T = string> {
type?: T;
default?: any;
title?: string;
description?: string;
enum?: (string | number)[];
properties?: Record<string, IJsonSchema<T>>;
additionalProperties?: IJsonSchema<T>;
items?: IJsonSchema<T>;
required?: string[];
$ref?: string;
extra?: {
index?: number;
// Used in BaseType.isEqualWithJSONSchema, the type comparison will be weak
weak?: boolean;
// Set the render component
formComponent?: string;
[key: string]: any;
};
}
export type IBasicJsonSchema = IJsonSchema<JsonSchemaBasicType>;

View File

@ -1 +1,2 @@
export * from './format-legacy-refs'; export * from './format-legacy-refs';
export * from './json-schema';

View File

@ -0,0 +1,5 @@
{
"name": "json-schema",
"depMaterials": ["typings/json-schema"],
"depPackages": ["lodash"]
}

View File

@ -0,0 +1,154 @@
import { get } from 'lodash';
import { ASTFactory, ASTKind, ASTMatch, ASTNode, ASTNodeJSON, BaseType } from '@flowgram.ai/editor';
import { IJsonSchema } from '../../typings/json-schema';
export namespace JsonSchemaUtils {
/**
* Converts a JSON schema to an Abstract Syntax Tree (AST) representation.
* This function recursively processes the JSON schema and creates corresponding AST nodes.
*
* For more information on JSON Schema, refer to the official documentation:
* https://json-schema.org/
*
* @param jsonSchema - The JSON schema to convert.
* @returns An AST node representing the JSON schema, or undefined if the schema type is not recognized.
*/
export function schemaToAST(jsonSchema: IJsonSchema): ASTNodeJSON | undefined {
const { type, extra } = jsonSchema || {};
const { weak = false } = extra || {};
if (!type) {
return undefined;
}
switch (type) {
case 'object':
if (weak) {
return { kind: ASTKind.Object, weak: true };
}
return ASTFactory.createObject({
properties: Object.entries(jsonSchema.properties || {})
/**
* Sorts the properties of a JSON schema based on the 'extra.index' field.
* If the 'extra.index' field is not present, the property will be treated as having an index of 0.
*/
.sort((a, b) => (get(a?.[1], 'extra.index') || 0) - (get(b?.[1], 'extra.index') || 0))
.map(([key, _property]) => ({
key,
type: schemaToAST(_property),
meta: { description: _property.description },
})),
});
case 'array':
if (weak) {
return { kind: ASTKind.Array, weak: true };
}
return ASTFactory.createArray({
items: schemaToAST(jsonSchema.items!),
});
case 'map':
if (weak) {
return { kind: ASTKind.Map, weak: true };
}
return ASTFactory.createMap({
valueType: schemaToAST(jsonSchema.additionalProperties!),
});
case 'string':
return ASTFactory.createString();
case 'number':
return ASTFactory.createNumber();
case 'boolean':
return ASTFactory.createBoolean();
case 'integer':
return ASTFactory.createInteger();
default:
// If the type is not recognized, return CustomType
return ASTFactory.createCustomType({ typeName: type });
}
}
/**
* Convert AST To JSON Schema
* @param typeAST
* @returns
*/
export function astToSchema(typeAST: ASTNode): IJsonSchema | undefined {
if (ASTMatch.isString(typeAST)) {
return {
type: 'string',
};
}
if (ASTMatch.isBoolean(typeAST)) {
return {
type: 'boolean',
};
}
if (ASTMatch.isNumber(typeAST)) {
return {
type: 'number',
};
}
if (ASTMatch.isInteger(typeAST)) {
return {
type: 'integer',
};
}
if (ASTMatch.isObject(typeAST)) {
return {
type: 'object',
properties: Object.fromEntries(
Object.entries(typeAST.properties).map(([key, value]) => [key, astToSchema(value)!])
),
};
}
if (ASTMatch.isArray(typeAST)) {
return {
type: 'array',
items: astToSchema(typeAST.items),
};
}
if (ASTMatch.isMap(typeAST)) {
return {
type: 'map',
items: astToSchema(typeAST.valueType),
};
}
if (ASTMatch.isCustomType(typeAST)) {
return {
type: typeAST.typeName,
};
}
return undefined;
}
/**
* Check if the AST type is match the JSON Schema
* @param typeAST
* @param schema
* @returns
*/
export function isASTMatchSchema(
typeAST: BaseType,
schema: IJsonSchema | IJsonSchema[]
): boolean {
if (Array.isArray(schema)) {
return typeAST.isTypeEqual(
ASTFactory.createUnion({
types: schema.map((_schema) => schemaToAST(_schema)!).filter(Boolean),
})
);
}
return typeAST.isTypeEqual(schemaToAST(schema));
}
}

View File

@ -1,8 +1,5 @@
import { get } from 'lodash';
import { ASTKind, ASTNodeJSON } from './types'; import { ASTKind, ASTNodeJSON } from './types';
import { MapJSON } from './type/map'; import { MapJSON } from './type/map';
import { VarJSONSchema } from './type/json-schema';
import { ArrayJSON } from './type/array'; import { ArrayJSON } from './type/array';
import { CustomTypeJSON, ObjectJSON, UnionJSON } from './type'; import { CustomTypeJSON, ObjectJSON, UnionJSON } from './type';
import { import {
@ -77,74 +74,6 @@ export namespace ASTFactory {
...json, ...json,
}); });
/**
* Converts a JSON schema to an Abstract Syntax Tree (AST) representation.
* This function recursively processes the JSON schema and creates corresponding AST nodes.
*
* For more information on JSON Schema, refer to the official documentation:
* https://json-schema.org/
*
*
* @param jsonSchema - The JSON schema to convert.
* @returns An AST node representing the JSON schema, or undefined if the schema type is not recognized.
*/
export function createTypeASTFromSchema(
jsonSchema: VarJSONSchema.ISchema
): ASTNodeJSON | undefined {
const { type, extra } = jsonSchema || {};
const { weak = false } = extra || {};
if (!type) {
return undefined;
}
switch (type) {
case 'object':
if (weak) {
return { kind: ASTKind.Object, weak: true };
}
return ASTFactory.createObject({
properties: Object.entries(jsonSchema.properties || {})
/**
* Sorts the properties of a JSON schema based on the 'extra.index' field.
* If the 'extra.index' field is not present, the property will be treated as having an index of 0.
*/
.sort((a, b) => (get(a?.[1], 'extra.index') || 0) - (get(b?.[1], 'extra.index') || 0))
.map(([key, _property]) => ({
key,
type: createTypeASTFromSchema(_property),
meta: { description: _property.description },
})),
});
case 'array':
if (weak) {
return { kind: ASTKind.Array, weak: true };
}
return ASTFactory.createArray({
items: createTypeASTFromSchema(jsonSchema.items!),
});
case 'map':
if (weak) {
return { kind: ASTKind.Map, weak: true };
}
return ASTFactory.createMap({
valueType: createTypeASTFromSchema(jsonSchema.additionalProperties!),
});
case 'string':
return ASTFactory.createString();
case 'number':
return ASTFactory.createNumber();
case 'boolean':
return ASTFactory.createBoolean();
case 'integer':
return ASTFactory.createInteger();
default:
// If the type is not recognized, return CustomType
return ASTFactory.createCustomType({ typeName: type });
}
}
/** /**
* AST Class * AST Class
*/ */

View File

@ -1,11 +1,9 @@
import { parseTypeJsonOrKind } from '../utils/helpers'; import { parseTypeJsonOrKind } from '../utils/helpers';
import { VarJSONSchema } from './json-schema';
import { ASTKind, ASTNodeJSON, ASTNodeJSONOrKind } from '../types'; import { ASTKind, ASTNodeJSON, ASTNodeJSONOrKind } from '../types';
import { ASTNodeFlags } from '../flags'; import { ASTNodeFlags } from '../flags';
import { BaseVariableField } from '../declaration'; import { BaseVariableField } from '../declaration';
import { ASTNode } from '../ast-node'; import { ASTNode } from '../ast-node';
import { UnionJSON } from './union'; import { UnionJSON } from './union';
import { ASTFactory } from '../factory';
export abstract class BaseType<JSON extends ASTNodeJSON = any, InjectOpts = any> extends ASTNode< export abstract class BaseType<JSON extends ASTNodeJSON = any, InjectOpts = any> extends ASTNode<
JSON, JSON,
@ -47,31 +45,4 @@ export abstract class BaseType<JSON extends ASTNodeJSON = any, InjectOpts = any>
kind: this.kind, kind: this.kind,
}; };
} }
/**
* Get Standard JSON Schema for current base type
* @returns
*/
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: this.kind.toLowerCase() as VarJSONSchema.BasicType,
};
}
/**
* Check if the type is equal with json schema
*/
isEqualWithJSONSchema(schema: VarJSONSchema.ISchema | VarJSONSchema.ISchema[]): boolean {
if (Array.isArray(schema)) {
return this.isTypeEqual(
ASTFactory.createUnion({
types: schema
.map((_schema) => ASTFactory.createTypeASTFromSchema(_schema)!)
.filter(Boolean),
})
);
}
return this.isTypeEqual(ASTFactory.createTypeASTFromSchema(schema));
}
} }

View File

@ -1,4 +1,3 @@
import { VarJSONSchema } from './json-schema';
import { ASTKind } from '../types'; import { ASTKind } from '../types';
import { BaseType } from './base-type'; import { BaseType } from './base-type';
@ -8,10 +7,4 @@ export class BooleanType extends BaseType {
fromJSON(): void { fromJSON(): void {
// noop // noop
} }
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: 'boolean',
};
}
} }

View File

@ -1,5 +1,4 @@
import { parseTypeJsonOrKind } from '../utils/helpers'; import { parseTypeJsonOrKind } from '../utils/helpers';
import { VarJSONSchema } from './json-schema';
import { ASTKind, ASTNodeJSONOrKind } from '../types'; import { ASTKind, ASTNodeJSONOrKind } from '../types';
import { type UnionJSON } from './union'; import { type UnionJSON } from './union';
import { BaseType } from './base-type'; import { BaseType } from './base-type';
@ -36,10 +35,4 @@ export class CustomType extends BaseType<CustomTypeJSON> {
return targetTypeJSON?.kind === this.kind && targetTypeJSON?.typeName === this.typeName; return targetTypeJSON?.kind === this.kind && targetTypeJSON?.typeName === this.typeName;
} }
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: this._typeName,
};
}
} }

View File

@ -12,4 +12,3 @@ export {
export { BaseType } from './base-type'; export { BaseType } from './base-type';
export { type UnionJSON } from './union'; export { type UnionJSON } from './union';
export { CustomType, type CustomTypeJSON } from './custom-type'; export { CustomType, type CustomTypeJSON } from './custom-type';
export { VarJSONSchema } from './json-schema';

View File

@ -1,4 +1,3 @@
import { VarJSONSchema } from './json-schema';
import { ASTKind } from '../types'; import { ASTKind } from '../types';
import { ASTNodeFlags } from '../flags'; import { ASTNodeFlags } from '../flags';
import { BaseType } from './base-type'; import { BaseType } from './base-type';
@ -11,10 +10,4 @@ export class IntegerType extends BaseType {
fromJSON(): void { fromJSON(): void {
// noop // noop
} }
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: 'integer',
};
}
} }

View File

@ -1,26 +0,0 @@
export namespace VarJSONSchema {
export type BasicType = 'boolean' | 'string' | 'integer' | 'number' | 'object' | 'array' | 'map';
export interface ISchema<T = string> {
type?: T;
default?: any;
title?: string;
description?: string;
enum?: (string | number)[];
properties?: Record<string, ISchema<T>>;
additionalProperties?: ISchema<T>;
items?: ISchema<T>;
required?: string[];
$ref?: string;
extra?: {
index?: number;
// Used in BaseType.isEqualWithJSONSchema, the type comparison will be weak
weak?: boolean;
// Set the render component
formComponent?: string;
[key: string]: any;
};
}
export type IBasicSchema = ISchema<BasicType>;
}

View File

@ -1,5 +1,4 @@
import { parseTypeJsonOrKind } from '../utils/helpers'; import { parseTypeJsonOrKind } from '../utils/helpers';
import { VarJSONSchema } from './json-schema';
import { ASTKind, ASTNodeJSON, ASTNodeJSONOrKind } from '../types'; import { ASTKind, ASTNodeJSON, ASTNodeJSONOrKind } from '../types';
import { BaseType } from './base-type'; import { BaseType } from './base-type';
@ -75,11 +74,4 @@ export class MapType extends BaseType<MapJSON> {
valueType: this.valueType?.toJSON(), valueType: this.valueType?.toJSON(),
}; };
} }
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: 'map',
additionalProperties: this.valueType?.toJSONSchema(),
};
}
} }

View File

@ -1,4 +1,3 @@
import { VarJSONSchema } from './json-schema';
import { ASTKind } from '../types'; import { ASTKind } from '../types';
import { BaseType } from './base-type'; import { BaseType } from './base-type';
@ -8,10 +7,4 @@ export class NumberType extends BaseType {
fromJSON(): void { fromJSON(): void {
// noop // noop
} }
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: 'number',
};
}
} }

View File

@ -1,7 +1,6 @@
import { xor } from 'lodash'; import { xor } from 'lodash';
import { parseTypeJsonOrKind } from '../utils/helpers'; import { parseTypeJsonOrKind } from '../utils/helpers';
import { VarJSONSchema } from './json-schema';
import { ASTNodeJSON, ASTKind, ASTNodeJSONOrKind, type GlobalEventActionType } from '../types'; import { ASTNodeJSON, ASTKind, ASTNodeJSONOrKind, type GlobalEventActionType } from '../types';
import { ASTNodeFlags } from '../flags'; import { ASTNodeFlags } from '../flags';
import { Property, type PropertyJSON } from '../declaration/property'; import { Property, type PropertyJSON } from '../declaration/property';
@ -149,14 +148,4 @@ export class ObjectType extends BaseType<ObjectJSON> {
}) })
); );
} }
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: 'object',
properties: this.properties.reduce((acc, _property) => {
acc[_property.key] = _property.type?.toJSONSchema();
return acc;
}, {} as Record<string, VarJSONSchema.ISchema>),
};
}
} }

View File

@ -1,4 +1,3 @@
import { VarJSONSchema } from './json-schema';
import { ASTKind } from '../types'; import { ASTKind } from '../types';
import { ASTNodeFlags } from '../flags'; import { ASTNodeFlags } from '../flags';
import { BaseType } from './base-type'; import { BaseType } from './base-type';
@ -11,10 +10,4 @@ export class StringType extends BaseType {
fromJSON(): void { fromJSON(): void {
// noop // noop
} }
toJSONSchema(): VarJSONSchema.ISchema {
return {
type: 'string',
};
}
} }