mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-10 01:48:18 +00:00
feat: 🎸 code generator fix slot support
This commit is contained in:
parent
9061e4b384
commit
e51b9cbf77
@ -11,11 +11,7 @@ import createRecoreProjectBuilder from './solutions/recore';
|
|||||||
|
|
||||||
// 引入说明
|
// 引入说明
|
||||||
import { REACT_CHUNK_NAME } from './plugins/component/react/const';
|
import { REACT_CHUNK_NAME } from './plugins/component/react/const';
|
||||||
import {
|
import { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from './const/generator';
|
||||||
COMMON_CHUNK_NAME,
|
|
||||||
CLASS_DEFINE_CHUNK_NAME,
|
|
||||||
DEFAULT_LINK_AFTER,
|
|
||||||
} from './const/generator';
|
|
||||||
|
|
||||||
// 引入通用插件组
|
// 引入通用插件组
|
||||||
import esmodule from './plugins/common/esmodule';
|
import esmodule from './plugins/common/esmodule';
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
|
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
|
||||||
|
|
||||||
import { handleChildren } from '../utils/nodeToJSX';
|
import { handleSubNodes } from '../utils/nodeToJSX';
|
||||||
import { uniqueArray } from '../utils/common';
|
import { uniqueArray } from '../utils/common';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -198,11 +198,15 @@ class SchemaParser implements ISchemaParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getComponentNames(children: ChildNodeType): string[] {
|
getComponentNames(children: ChildNodeType): string[] {
|
||||||
return handleChildren<string>(children, {
|
return handleSubNodes<string>(
|
||||||
node: (i: IComponentNodeItem) => [i.componentName],
|
children,
|
||||||
}, {
|
{
|
||||||
rerun: true,
|
node: (i: IComponentNodeItem) => [i.componentName],
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
rerun: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,14 +29,11 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
const ir = next.ir as IContainerInfo;
|
const ir = next.ir as IContainerInfo;
|
||||||
if (ir.dataSource) {
|
if (ir.dataSource) {
|
||||||
const { dataSource } = ir;
|
const { dataSource } = ir;
|
||||||
const {
|
const { list, ...rest } = dataSource;
|
||||||
list,
|
|
||||||
...rest
|
|
||||||
} = dataSource;
|
|
||||||
|
|
||||||
let attrs: string[] = [];
|
let attrs: string[] = [];
|
||||||
|
|
||||||
const extConfigs = Object.keys(rest).map(extConfigName => {
|
const extConfigs = Object.keys(rest).map((extConfigName) => {
|
||||||
const value = (rest as Record<string, CompositeValue>)[extConfigName];
|
const value = (rest as Record<string, CompositeValue>)[extConfigName];
|
||||||
const [isString, valueStr] = generateCompositeType(value);
|
const [isString, valueStr] = generateCompositeType(value);
|
||||||
return `${extConfigName}: ${isString ? `'${valueStr}'` : valueStr}`;
|
return `${extConfigName}: ${isString ? `'${valueStr}'` : valueStr}`;
|
||||||
@ -44,9 +41,13 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
|
|
||||||
attrs = [...attrs, ...extConfigs];
|
attrs = [...attrs, ...extConfigs];
|
||||||
|
|
||||||
const listProp = handleStringValueDefault(generateCompositeType(list as unknown as CompositeValue, {
|
const listProp = handleStringValueDefault(
|
||||||
expression: packJsExpression,
|
generateCompositeType((list as unknown) as CompositeValue, {
|
||||||
}));
|
handlers: {
|
||||||
|
expression: packJsExpression,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
attrs.push(`list: ${listProp}`);
|
attrs.push(`list: ${listProp}`);
|
||||||
|
|
||||||
|
|||||||
@ -5,23 +5,26 @@ import {
|
|||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IContainerInfo,
|
IContainerInfo,
|
||||||
IComponentNodeItem,
|
IComponentNodeItem,
|
||||||
|
INodeGeneratorContext,
|
||||||
CodePiece,
|
CodePiece,
|
||||||
PIECE_TYPE,
|
PIECE_TYPE,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
import { COMMON_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
|
import { COMMON_CHUNK_NAME } from '../../../const/generator';
|
||||||
|
|
||||||
import { createNodeGenerator, generateString } from '../../../utils/nodeToJSX';
|
import { createNodeGenerator, generateString } from '../../../utils/nodeToJSX';
|
||||||
import { generateExpression } from '../../../utils/jsExpression';
|
import { generateExpression } from '../../../utils/jsExpression';
|
||||||
import { generateCompositeType, handleStringValueDefault } from '../../../utils/compositeType';
|
import { generateCompositeType, handleStringValueDefault } from '../../../utils/compositeType';
|
||||||
|
|
||||||
const generateGlobalProps = (nodeItem: IComponentNodeItem): CodePiece[] => {
|
const generateGlobalProps = (ctx: INodeGeneratorContext, nodeItem: IComponentNodeItem): CodePiece[] => {
|
||||||
return [{
|
return [
|
||||||
value: `{...globalProps.${nodeItem.componentName}}`,
|
{
|
||||||
type: PIECE_TYPE.ATTR,
|
value: `{...globalProps.${nodeItem.componentName}}`,
|
||||||
}];
|
type: PIECE_TYPE.ATTR,
|
||||||
|
},
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateCtrlLine = (nodeItem: IComponentNodeItem): CodePiece[] => {
|
const generateCtrlLine = (ctx: INodeGeneratorContext, nodeItem: IComponentNodeItem): CodePiece[] => {
|
||||||
const pieces: CodePiece[] = [];
|
const pieces: CodePiece[] = [];
|
||||||
|
|
||||||
if (nodeItem.loop && nodeItem.loopArgs) {
|
if (nodeItem.loop && nodeItem.loopArgs) {
|
||||||
@ -49,13 +52,13 @@ const generateCtrlLine = (nodeItem: IComponentNodeItem): CodePiece[] => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
||||||
const generator = createNodeGenerator({
|
const generator = createNodeGenerator(
|
||||||
string: generateString,
|
{
|
||||||
expression: (input) => [generateExpression(input)],
|
string: generateString,
|
||||||
}, [
|
expression: (input) => [generateExpression(input)],
|
||||||
generateGlobalProps,
|
},
|
||||||
generateCtrlLine,
|
[generateGlobalProps, generateCtrlLine],
|
||||||
]);
|
);
|
||||||
|
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
const next: ICodeStruct = {
|
const next: ICodeStruct = {
|
||||||
|
|||||||
@ -26,10 +26,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
content: `
|
content: `
|
||||||
const constantConfig = ${constantStr};
|
const constantConfig = ${constantStr};
|
||||||
`,
|
`,
|
||||||
linkAfter: [
|
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport],
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
|
|||||||
@ -53,17 +53,12 @@ export interface ICodeStruct extends IBaseCodeStruct {
|
|||||||
chunks: ICodeChunk[];
|
chunks: ICodeChunk[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BuilderComponentPlugin = (
|
export type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise<ICodeStruct>;
|
||||||
initStruct: ICodeStruct,
|
|
||||||
) => Promise<ICodeStruct>;
|
|
||||||
|
|
||||||
export type BuilderComponentPluginFactory<T> = (config?: T) => BuilderComponentPlugin;
|
export type BuilderComponentPluginFactory<T> = (config?: T) => BuilderComponentPlugin;
|
||||||
|
|
||||||
export interface IChunkBuilder {
|
export interface IChunkBuilder {
|
||||||
run(
|
run(ir: any, initialStructure?: ICodeStruct): Promise<{ chunks: ICodeChunk[][] }>;
|
||||||
ir: any,
|
|
||||||
initialStructure?: ICodeStruct,
|
|
||||||
): Promise<{ chunks: ICodeChunk[][] }>;
|
|
||||||
getPlugins(): BuilderComponentPlugin[];
|
getPlugins(): BuilderComponentPlugin[];
|
||||||
addPlugin(plugin: BuilderComponentPlugin): void;
|
addPlugin(plugin: BuilderComponentPlugin): void;
|
||||||
}
|
}
|
||||||
@ -80,10 +75,7 @@ export interface ICompiledModule {
|
|||||||
export interface IModuleBuilder {
|
export interface IModuleBuilder {
|
||||||
generateModule(input: unknown): Promise<ICompiledModule>;
|
generateModule(input: unknown): Promise<ICompiledModule>;
|
||||||
generateModuleCode(schema: IBasicSchema | string): Promise<IResultDir>;
|
generateModuleCode(schema: IBasicSchema | string): Promise<IResultDir>;
|
||||||
linkCodeChunks(
|
linkCodeChunks(chunks: Record<string, ICodeChunk[]>, fileName: string): IResultFile[];
|
||||||
chunks: Record<string, ICodeChunk[]>,
|
|
||||||
fileName: string,
|
|
||||||
): IResultFile[];
|
|
||||||
addPlugin(plugin: BuilderComponentPlugin): void;
|
addPlugin(plugin: BuilderComponentPlugin): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +146,7 @@ export enum PIECE_TYPE {
|
|||||||
ATTR = 'NodeCodePieceAttr',
|
ATTR = 'NodeCodePieceAttr',
|
||||||
CHILDREN = 'NodeCodePieceChildren',
|
CHILDREN = 'NodeCodePieceChildren',
|
||||||
AFTER = 'NodeCodePieceAfter',
|
AFTER = 'NodeCodePieceAfter',
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface CodePiece {
|
export interface CodePiece {
|
||||||
value: string;
|
value: string;
|
||||||
@ -168,14 +160,35 @@ export interface HandlerSet<T> {
|
|||||||
common?: (input: unknown) => T[];
|
common?: (input: unknown) => T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExtGeneratorPlugin = (nodeItem: IComponentNodeItem) => CodePiece[];
|
export type ExtGeneratorPlugin = (ctx: INodeGeneratorContext, nodeItem: IComponentNodeItem) => CodePiece[];
|
||||||
|
|
||||||
export interface INodeGeneratorConfig {
|
export interface INodeGeneratorConfig {
|
||||||
nodeTypeMapping?: Record<string, string>;
|
nodeTypeMapping?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NodeGenerator = (nodeItem: IComponentNodeItem) => string;
|
||||||
|
|
||||||
|
export interface INodeGeneratorContext {
|
||||||
|
generator: NodeGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
// export interface InteratorScope {
|
// export interface InteratorScope {
|
||||||
// [$item: string]: string; // $item 默认取值 "item"
|
// [$item: string]: string; // $item 默认取值 "item"
|
||||||
// [$index: string]: string | number; // $index 默认取值 "index"
|
// [$index: string]: string | number; // $index 默认取值 "index"
|
||||||
// __proto__: BlockInstance;
|
// __proto__: BlockInstance;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
export type CompositeValueCustomHandler = (data: unknown) => string;
|
||||||
|
export interface CompositeValueCustomHandlerSet {
|
||||||
|
boolean?: CompositeValueCustomHandler;
|
||||||
|
number?: CompositeValueCustomHandler;
|
||||||
|
string?: CompositeValueCustomHandler;
|
||||||
|
array?: CompositeValueCustomHandler;
|
||||||
|
object?: CompositeValueCustomHandler;
|
||||||
|
expression?: CompositeValueCustomHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompositeValueGeneratorOptions {
|
||||||
|
handlers?: CompositeValueCustomHandlerSet;
|
||||||
|
nodeGenerator?: NodeGenerator;
|
||||||
|
}
|
||||||
|
|||||||
@ -33,7 +33,8 @@ export interface IJSFunction {
|
|||||||
*/
|
*/
|
||||||
export interface IJSSlot {
|
export interface IJSSlot {
|
||||||
type: 'JSSlot';
|
type: 'JSSlot';
|
||||||
value: IComponentNodeItem;
|
value: IComponentNodeItem[];
|
||||||
|
params?: string[];
|
||||||
[extConfigName: string]: any;
|
[extConfigName: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,25 +1,22 @@
|
|||||||
import { CompositeArray, CompositeValue, ICompositeObject } from '../types';
|
import {
|
||||||
|
CompositeArray,
|
||||||
|
CompositeValue,
|
||||||
|
ICompositeObject,
|
||||||
|
CompositeValueGeneratorOptions,
|
||||||
|
CodeGeneratorError,
|
||||||
|
} from '../types';
|
||||||
import { generateExpression, generateFunction, isJsExpression, isJsFunction } from './jsExpression';
|
import { generateExpression, generateFunction, isJsExpression, isJsFunction } from './jsExpression';
|
||||||
|
import { isJsSlot, generateJsSlot } from './jsSlot';
|
||||||
|
|
||||||
type CustomHandler = (data: unknown) => string;
|
function generateArray(value: CompositeArray, options: CompositeValueGeneratorOptions = {}): string {
|
||||||
interface CustomHandlerSet {
|
const body = value.map((v) => generateUnknownType(v, options)).join(',');
|
||||||
boolean?: CustomHandler;
|
|
||||||
number?: CustomHandler;
|
|
||||||
string?: CustomHandler;
|
|
||||||
array?: CustomHandler;
|
|
||||||
object?: CustomHandler;
|
|
||||||
expression?: CustomHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateArray(value: CompositeArray, handlers: CustomHandlerSet = {}): string {
|
|
||||||
const body = value.map((v) => generateUnknownType(v, handlers)).join(',');
|
|
||||||
return `[${body}]`;
|
return `[${body}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateObject(value: ICompositeObject, handlers: CustomHandlerSet = {}): string {
|
function generateObject(value: ICompositeObject, options: CompositeValueGeneratorOptions = {}): string {
|
||||||
if (isJsExpression(value)) {
|
if (isJsExpression(value)) {
|
||||||
if (handlers.expression) {
|
if (options.handlers && options.handlers.expression) {
|
||||||
return handlers.expression(value);
|
return options.handlers.expression(value);
|
||||||
}
|
}
|
||||||
return generateExpression(value);
|
return generateExpression(value);
|
||||||
}
|
}
|
||||||
@ -28,9 +25,16 @@ function generateObject(value: ICompositeObject, handlers: CustomHandlerSet = {}
|
|||||||
return generateFunction(value, { isArrow: true });
|
return generateFunction(value, { isArrow: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isJsSlot(value)) {
|
||||||
|
if (options.nodeGenerator) {
|
||||||
|
return generateJsSlot(value, options.nodeGenerator);
|
||||||
|
}
|
||||||
|
throw new CodeGeneratorError("Can't find Node Generator");
|
||||||
|
}
|
||||||
|
|
||||||
const body = Object.keys(value)
|
const body = Object.keys(value)
|
||||||
.map((key) => {
|
.map((key) => {
|
||||||
const v = generateUnknownType(value[key], handlers);
|
const v = generateUnknownType(value[key], options);
|
||||||
return `${key}: ${v}`;
|
return `${key}: ${v}`;
|
||||||
})
|
})
|
||||||
.join(',\n');
|
.join(',\n');
|
||||||
@ -38,32 +42,35 @@ function generateObject(value: ICompositeObject, handlers: CustomHandlerSet = {}
|
|||||||
return `{${body}}`;
|
return `{${body}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateUnknownType(value: CompositeValue, handlers: CustomHandlerSet = {}): string {
|
export function generateUnknownType(value: CompositeValue, options: CompositeValueGeneratorOptions = {}): string {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
if (handlers.array) {
|
if (options.handlers && options.handlers.array) {
|
||||||
return handlers.array(value);
|
return options.handlers.array(value);
|
||||||
}
|
}
|
||||||
return generateArray(value as CompositeArray, handlers);
|
return generateArray(value as CompositeArray, options);
|
||||||
} else if (typeof value === 'object') {
|
} else if (typeof value === 'object') {
|
||||||
if (handlers.object) {
|
if (options.handlers && options.handlers.object) {
|
||||||
return handlers.object(value);
|
return options.handlers.object(value);
|
||||||
}
|
}
|
||||||
return generateObject(value as ICompositeObject, handlers);
|
return generateObject(value as ICompositeObject, options);
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
if (handlers.string) {
|
if (options.handlers && options.handlers.string) {
|
||||||
return handlers.string(value);
|
return options.handlers.string(value);
|
||||||
}
|
}
|
||||||
return `'${value}'`;
|
return `'${value}'`;
|
||||||
} else if (typeof value === 'number' && handlers.number) {
|
} else if (typeof value === 'number' && options.handlers && options.handlers.number) {
|
||||||
return handlers.number(value);
|
return options.handlers.number(value);
|
||||||
} else if (typeof value === 'boolean' && handlers.boolean) {
|
} else if (typeof value === 'boolean' && options.handlers && options.handlers.boolean) {
|
||||||
return handlers.boolean(value);
|
return options.handlers.boolean(value);
|
||||||
}
|
}
|
||||||
return `${value}`;
|
return `${value}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateCompositeType(value: CompositeValue, handlers: CustomHandlerSet = {}): [boolean, string] {
|
export function generateCompositeType(
|
||||||
const result = generateUnknownType(value, handlers);
|
value: CompositeValue,
|
||||||
|
options: CompositeValueGeneratorOptions = {},
|
||||||
|
): [boolean, string] {
|
||||||
|
const result = generateUnknownType(value, options);
|
||||||
|
|
||||||
if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") {
|
if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") {
|
||||||
return [true, result.substring(1, result.length - 1)];
|
return [true, result.substring(1, result.length - 1)];
|
||||||
|
|||||||
21
packages/code-generator/src/utils/jsSlot.ts
Normal file
21
packages/code-generator/src/utils/jsSlot.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { CodeGeneratorError, NodeGenerator, IJSSlot } from '../types';
|
||||||
|
|
||||||
|
export function isJsSlot(value: unknown): boolean {
|
||||||
|
return value && typeof value === 'object' && (value as IJSSlot).type === 'JSSlot';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateJsSlot(value: any, generator: NodeGenerator): string {
|
||||||
|
if (isJsSlot(value)) {
|
||||||
|
const slotCfg = value as IJSSlot;
|
||||||
|
if (!slotCfg.value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
const results = slotCfg.value.map((n) => generator(n));
|
||||||
|
if (results.length === 1) {
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
return `[${results.join(',')}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CodeGeneratorError('Not a JSSlot');
|
||||||
|
}
|
||||||
@ -9,6 +9,8 @@ import {
|
|||||||
HandlerSet,
|
HandlerSet,
|
||||||
ExtGeneratorPlugin,
|
ExtGeneratorPlugin,
|
||||||
INodeGeneratorConfig,
|
INodeGeneratorConfig,
|
||||||
|
INodeGeneratorContext,
|
||||||
|
NodeGenerator,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { generateCompositeType } from './compositeType';
|
import { generateCompositeType } from './compositeType';
|
||||||
import { generateExpression, isJsExpression } from './jsExpression';
|
import { generateExpression, isJsExpression } from './jsExpression';
|
||||||
@ -20,7 +22,7 @@ const handleChildrenDefaultOptions = {
|
|||||||
rerun: false,
|
rerun: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function handleChildren<T>(
|
export function handleSubNodes<T>(
|
||||||
children: ChildNodeType,
|
children: ChildNodeType,
|
||||||
handlers: HandlerSet<T>,
|
handlers: HandlerSet<T>,
|
||||||
options?: {
|
options?: {
|
||||||
@ -34,7 +36,7 @@ export function handleChildren<T>(
|
|||||||
|
|
||||||
if (Array.isArray(children)) {
|
if (Array.isArray(children)) {
|
||||||
const list: ChildNodeItem[] = children as ChildNodeItem[];
|
const list: ChildNodeItem[] = children as ChildNodeItem[];
|
||||||
return list.map((child) => handleChildren(child, handlers, opt)).reduce((p, c) => p.concat(c), []);
|
return list.map((child) => handleSubNodes(child, handlers, opt)).reduce((p, c) => p.concat(c), []);
|
||||||
} else if (typeof children === 'string') {
|
} else if (typeof children === 'string') {
|
||||||
const handler = handlers.string || handlers.common || noop;
|
const handler = handlers.string || handlers.common || noop;
|
||||||
return handler(children as string);
|
return handler(children as string);
|
||||||
@ -45,18 +47,53 @@ export function handleChildren<T>(
|
|||||||
const handler = handlers.node || handlers.common || noop;
|
const handler = handlers.node || handlers.common || noop;
|
||||||
let curRes = handler(children as IComponentNodeItem);
|
let curRes = handler(children as IComponentNodeItem);
|
||||||
if (opt.rerun && children.children) {
|
if (opt.rerun && children.children) {
|
||||||
const childRes = handleChildren(children.children, handlers, opt);
|
const childRes = handleSubNodes(children.children, handlers, opt);
|
||||||
curRes = curRes.concat(childRes || []);
|
curRes = curRes.concat(childRes || []);
|
||||||
}
|
}
|
||||||
return curRes;
|
return curRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateAttr(attrName: string, attrValue: any): CodePiece[] {
|
export function handleChildren<T>(
|
||||||
|
ctx: INodeGeneratorContext,
|
||||||
|
children: ChildNodeType,
|
||||||
|
handlers: HandlerSet<T>,
|
||||||
|
options?: {
|
||||||
|
rerun?: boolean;
|
||||||
|
},
|
||||||
|
): T[] {
|
||||||
|
const opt = {
|
||||||
|
...handleChildrenDefaultOptions,
|
||||||
|
...(options || {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(children)) {
|
||||||
|
const list: ChildNodeItem[] = children as ChildNodeItem[];
|
||||||
|
return list.map((child) => handleChildren(ctx, child, handlers, opt)).reduce((p, c) => p.concat(c), []);
|
||||||
|
} else if (typeof children === 'string') {
|
||||||
|
const handler = handlers.string || handlers.common || noop;
|
||||||
|
return handler(children as string);
|
||||||
|
} else if (isJsExpression(children)) {
|
||||||
|
const handler = handlers.expression || handlers.common || noop;
|
||||||
|
return handler(children as IJSExpression);
|
||||||
|
} else {
|
||||||
|
const handler = handlers.node || handlers.common || noop;
|
||||||
|
let curRes = handler(children as IComponentNodeItem);
|
||||||
|
if (opt.rerun && children.children) {
|
||||||
|
const childRes = handleChildren(ctx, children.children, handlers, opt);
|
||||||
|
curRes = curRes.concat(childRes || []);
|
||||||
|
}
|
||||||
|
return curRes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateAttr(ctx: INodeGeneratorContext, attrName: string, attrValue: any): CodePiece[] {
|
||||||
if (attrName === 'initValue') {
|
if (attrName === 'initValue') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const [isString, valueStr] = generateCompositeType(attrValue);
|
const [isString, valueStr] = generateCompositeType(attrValue, {
|
||||||
|
nodeGenerator: ctx.generator,
|
||||||
|
});
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`,
|
value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`,
|
||||||
@ -65,11 +102,13 @@ export function generateAttr(attrName: string, attrValue: any): CodePiece[] {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateAttrs(nodeItem: IComponentNodeItem): CodePiece[] {
|
export function generateAttrs(ctx: INodeGeneratorContext, nodeItem: IComponentNodeItem): CodePiece[] {
|
||||||
const { props } = nodeItem;
|
const { props } = nodeItem;
|
||||||
let pieces: CodePiece[] = [];
|
let pieces: CodePiece[] = [];
|
||||||
|
|
||||||
Object.keys(props).forEach((propName: string) => (pieces = pieces.concat(generateAttr(propName, props[propName]))));
|
Object.keys(props).forEach(
|
||||||
|
(propName: string) => (pieces = pieces.concat(generateAttr(ctx, propName, props[propName]))),
|
||||||
|
);
|
||||||
|
|
||||||
return pieces;
|
return pieces;
|
||||||
}
|
}
|
||||||
@ -81,7 +120,11 @@ function mapNodeName(src: string, mapping: Record<string, string>): string {
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateBasicNode(nodeItem: IComponentNodeItem, mapping: Record<string, string>): CodePiece[] {
|
export function generateBasicNode(
|
||||||
|
ctx: INodeGeneratorContext,
|
||||||
|
nodeItem: IComponentNodeItem,
|
||||||
|
mapping: Record<string, string>,
|
||||||
|
): CodePiece[] {
|
||||||
const pieces: CodePiece[] = [];
|
const pieces: CodePiece[] = [];
|
||||||
pieces.push({
|
pieces.push({
|
||||||
value: mapNodeName(nodeItem.componentName, mapping),
|
value: mapNodeName(nodeItem.componentName, mapping),
|
||||||
@ -91,7 +134,19 @@ export function generateBasicNode(nodeItem: IComponentNodeItem, mapping: Record<
|
|||||||
return pieces;
|
return pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[] {
|
// TODO: 生成文档
|
||||||
|
// 为包裹的代码片段生成子上下文,集成父级上下文,并传入子级上下文新增内容。(如果存在多级上下文怎么处理?)
|
||||||
|
// 创建新的上下文,并从作用域中取对应同名变量塞到作用域里面?
|
||||||
|
// export function createSubContext() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSX 生成逻辑插件。在 React 代码模式下生成 loop 与 condition 相关的逻辑代码
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {IComponentNodeItem} nodeItem 当前 UI 节点
|
||||||
|
* @returns {CodePiece[]} 实现功能的相关代码片段
|
||||||
|
*/
|
||||||
|
export function generateReactCtrlLine(ctx: INodeGeneratorContext, nodeItem: IComponentNodeItem): CodePiece[] {
|
||||||
const pieces: CodePiece[] = [];
|
const pieces: CodePiece[] = [];
|
||||||
|
|
||||||
if (nodeItem.loop && nodeItem.loopArgs) {
|
if (nodeItem.loop && nodeItem.loopArgs) {
|
||||||
@ -112,7 +167,9 @@ export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[]
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nodeItem.condition) {
|
if (nodeItem.condition) {
|
||||||
const [isString, value] = generateCompositeType(nodeItem.condition);
|
const [isString, value] = generateCompositeType(nodeItem.condition, {
|
||||||
|
nodeGenerator: ctx.generator,
|
||||||
|
});
|
||||||
|
|
||||||
pieces.unshift({
|
pieces.unshift({
|
||||||
value: `(${isString ? `'${value}'` : value}) && (`,
|
value: `(${isString ? `'${value}'` : value}) && (`,
|
||||||
@ -177,7 +234,7 @@ export function createNodeGenerator(
|
|||||||
handlers: HandlerSet<string>,
|
handlers: HandlerSet<string>,
|
||||||
plugins: ExtGeneratorPlugin[],
|
plugins: ExtGeneratorPlugin[],
|
||||||
cfg?: INodeGeneratorConfig,
|
cfg?: INodeGeneratorConfig,
|
||||||
) {
|
): NodeGenerator {
|
||||||
let nodeTypeMapping: Record<string, string> = {};
|
let nodeTypeMapping: Record<string, string> = {};
|
||||||
if (cfg && cfg.nodeTypeMapping) {
|
if (cfg && cfg.nodeTypeMapping) {
|
||||||
nodeTypeMapping = cfg.nodeTypeMapping;
|
nodeTypeMapping = cfg.nodeTypeMapping;
|
||||||
@ -185,15 +242,18 @@ export function createNodeGenerator(
|
|||||||
|
|
||||||
const generateNode = (nodeItem: IComponentNodeItem): string => {
|
const generateNode = (nodeItem: IComponentNodeItem): string => {
|
||||||
let pieces: CodePiece[] = [];
|
let pieces: CodePiece[] = [];
|
||||||
|
const ctx: INodeGeneratorContext = {
|
||||||
|
generator: generateNode,
|
||||||
|
};
|
||||||
|
|
||||||
plugins.forEach((p) => {
|
plugins.forEach((p) => {
|
||||||
pieces = pieces.concat(p(nodeItem));
|
pieces = pieces.concat(p(ctx, nodeItem));
|
||||||
});
|
});
|
||||||
pieces = pieces.concat(generateBasicNode(nodeItem, nodeTypeMapping));
|
pieces = pieces.concat(generateBasicNode(ctx, nodeItem, nodeTypeMapping));
|
||||||
pieces = pieces.concat(generateAttrs(nodeItem));
|
pieces = pieces.concat(generateAttrs(ctx, nodeItem));
|
||||||
if (nodeItem.children && (nodeItem.children as unknown[]).length > 0) {
|
if (nodeItem.children && (nodeItem.children as unknown[]).length > 0) {
|
||||||
pieces = pieces.concat(
|
pieces = pieces.concat(
|
||||||
handleChildren<string>(nodeItem.children, handlers).map((l) => ({
|
handleChildren<string>(ctx, nodeItem.children, handlers).map((l) => ({
|
||||||
type: PIECE_TYPE.CHILDREN,
|
type: PIECE_TYPE.CHILDREN,
|
||||||
value: l,
|
value: l,
|
||||||
})),
|
})),
|
||||||
@ -210,7 +270,7 @@ export function createNodeGenerator(
|
|||||||
|
|
||||||
export const generateString = (input: string) => [input];
|
export const generateString = (input: string) => [input];
|
||||||
|
|
||||||
export function createReactNodeGenerator(cfg?: INodeGeneratorConfig) {
|
export function createReactNodeGenerator(cfg?: INodeGeneratorConfig): NodeGenerator {
|
||||||
return createNodeGenerator(
|
return createNodeGenerator(
|
||||||
{
|
{
|
||||||
string: generateString,
|
string: generateString,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user