diff --git a/.eslintrc b/.eslintrc index 734b559..04f7b6c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,11 +2,12 @@ "extends": ["eslint-config-ali/typescript/react", "prettier"], "ignorePatterns": ["**/dist/**/*", "**/lib/**/*", "**/node_modules/**/*", "scripts/**/*"], "rules": { + "@typescript-eslint/consistent-type-definitions": "off", "@typescript-eslint/dot-notation": "off", "@typescript-eslint/no-unused-vars": "warn", "import/no-cycle": "off", "no-nested-ternary": "off", - "no-useless-return":"off", + "no-useless-return": "off", "no-param-reassign": "off", "prefer-destructuring": "off" } diff --git a/apps/playground/src/mock/project.ts b/apps/playground/src/mock/project.ts index 8f5c2d2..75acbaa 100644 --- a/apps/playground/src/mock/project.ts +++ b/apps/playground/src/mock/project.ts @@ -151,6 +151,7 @@ import { Input, FormilyForm, } from "@music163/antd"; +import { Space } from '@music163/antd'; class App extends React.Component { render() { return ( @@ -158,8 +159,10 @@ class App extends React.Component {
+ +
); diff --git a/packages/core/src/helpers/ast/traverse.ts b/packages/core/src/helpers/ast/traverse.ts index 5b41b02..7272974 100644 --- a/packages/core/src/helpers/ast/traverse.ts +++ b/packages/core/src/helpers/ast/traverse.ts @@ -453,7 +453,7 @@ function getLastExportDeclarationIndex(node: t.Program) { * @param importedSourcePath * @returns */ -export function makeImportDeclaration(importedModule: IImportDeclarationPayload) { +export function makeImportDeclarationLegacy(importedModule: IImportDeclarationPayload) { const specifierNodes = importedModule.specifiers?.map((localName) => t.importSpecifier(t.identifier(localName), t.identifier(localName)), @@ -468,19 +468,28 @@ export function makeImportDeclaration(importedModule: IImportDeclarationPayload) return t.importDeclaration(newSpecifierNodes, t.stringLiteral(importedModule.sourcePath)); } -export function makeImportDeclaration2(source: string, specifiers: IImportSpecifierData[]) { - const specifierNodes = specifiers.map((item) => { - switch (item.type) { - case 'ImportDefaultSpecifier': - return t.importDefaultSpecifier(t.identifier(item.localName)); - case 'ImportSpecifier': - return t.importSpecifier(t.identifier(item.importedName), t.identifier(item.localName)); - case 'ImportNamespaceSpecifier': - return t.importNamespaceSpecifier(t.identifier(item.localName)); - default: - return; - } - }); +function specifierData2node(data: IImportSpecifierData) { + switch (data.type) { + case 'ImportDefaultSpecifier': + return t.importDefaultSpecifier(t.identifier(data.localName)); + case 'ImportSpecifier': + return t.importSpecifier( + t.identifier(data.importedName || data.localName), + t.identifier(data.localName), + ); + case 'ImportNamespaceSpecifier': + return t.importNamespaceSpecifier(t.identifier(data.localName)); + default: + return; + } +} + +function specifierDataList2nodes(specifiers: IImportSpecifierData[]) { + return specifiers.map((item) => specifierData2node(item)).filter((item) => !!item); +} + +export function makeImportDeclaration(source: string, specifiers: IImportSpecifierData[]) { + const specifierNodes = specifierDataList2nodes(specifiers); return t.importDeclaration(specifierNodes, t.stringLiteral(source)); } @@ -515,11 +524,11 @@ function getImportDeclarationData(node: t.ImportDeclaration): IImportDeclaration * @param importedSourcePath * @returns */ -export function addImportDeclaration(ast: t.File, importedModule: IImportDeclarationPayload) { +export function addImportDeclarationLegacy(ast: t.File, importedModule: IImportDeclarationPayload) { traverse(ast, { Program(path) { const lastIndex = getLastImportDeclarationIndex(path.node); - const newImportDeclaration = makeImportDeclaration(importedModule); + const newImportDeclaration = makeImportDeclarationLegacy(importedModule); path.node.body.splice(lastIndex, 0, newImportDeclaration); path.stop(); }, @@ -527,7 +536,7 @@ export function addImportDeclaration(ast: t.File, importedModule: IImportDeclara return ast; } -export function addImportDeclaration2( +export function addImportDeclaration( ast: t.File, source: string, specifiers: IImportSpecifierData[], @@ -535,11 +544,12 @@ export function addImportDeclaration2( traverse(ast, { Program(path) { const lastIndex = getLastImportDeclarationIndex(path.node); - const newImportDeclaration = makeImportDeclaration2(source, specifiers); + const newImportDeclaration = makeImportDeclaration(source, specifiers); path.node.body.splice(lastIndex, 0, newImportDeclaration); path.stop(); }, }); + return ast; } /** @@ -550,12 +560,15 @@ export function addImportDeclaration2( * @param importedSourcePath * @returns */ -export function updateImportDeclaration(ast: t.File, importedModule: IImportDeclarationPayload) { +export function updateImportDeclarationLegacy( + ast: t.File, + importedModule: IImportDeclarationPayload, +) { traverse(ast, { ImportDeclaration(path) { const currentSourcePath = node2value(path.node.source); if (currentSourcePath === importedModule.sourcePath) { - const newImportDeclaration = makeImportDeclaration(importedModule); + const newImportDeclaration = makeImportDeclarationLegacy(importedModule); path.replaceWith(newImportDeclaration); path.stop(); // 只修改匹配到的第一条 } @@ -564,7 +577,7 @@ export function updateImportDeclaration(ast: t.File, importedModule: IImportDecl return ast; } -export function updateImportDeclaration2( +export function updateImportDeclaration( ast: t.File, source: string, specifiers: IImportSpecifierData[], @@ -573,7 +586,7 @@ export function updateImportDeclaration2( ImportDeclaration(path) { const currentSourcePath = node2value(path.node.source); if (currentSourcePath === source) { - const newImportDeclaration = makeImportDeclaration2(source, specifiers); + const newImportDeclaration = makeImportDeclaration(source, specifiers); path.replaceWith(newImportDeclaration); path.stop(); // 只修改匹配到的第一条 } @@ -582,6 +595,32 @@ export function updateImportDeclaration2( return ast; } +/** + * 再已有的导入语句中添加新的导入符号 + * @param ast + * @param source + * @param newSpecifiers + * @returns + */ +export function insertImportSpecifiers( + ast: t.File, + source: string, + newSpecifiers: IImportSpecifierData[], +) { + traverse(ast, { + ImportDeclaration(path) { + const currentSourcePath = node2value(path.node.source); + if (currentSourcePath === source) { + const nodes = specifierDataList2nodes(newSpecifiers); + path.node.specifiers.push(...nodes); + // 只在匹配到的第一个导入声明语句添加即可,不再重复执行 + path.stop(); + } + }, + }); + return ast; +} + /** * 新增类属性 * @param ast @@ -1180,7 +1219,12 @@ export function traverseViewFile(ast: t.File, idGenerator: IdGenerator) { traverse(ast, { ImportDeclaration(path) { const { source, specifiers } = parseImportDeclaration(path.node); - imports[source] = specifiers; + if (imports[source]) { + // 存在重复的导入语句,合并导入符号列表 + imports[source] = imports[source].concat(specifiers); + } else { + imports[source] = specifiers; + } // FIXME: 下面的逻辑兼容旧的逻辑,后续需要移除掉 const declarationData = specifiers.reduce( diff --git a/packages/core/src/helpers/prototype.ts b/packages/core/src/helpers/prototype.ts index eb3f6c9..763b588 100644 --- a/packages/core/src/helpers/prototype.ts +++ b/packages/core/src/helpers/prototype.ts @@ -7,12 +7,47 @@ import { uuid, } from '@music163/tango-helpers'; import { getRelativePath, isFilepath } from './string'; -import type { IImportDeclarationPayload } from '../types'; +import type { IImportDeclarationPayload, IImportSpecifierData } from '../types'; import { code2expression } from './ast'; import { isWrappedByExpressionContainer } from './assert'; +export function prototype2importDeclarationData( + prototype: ComponentPrototypeType, + relativeFilepath?: string, +): { source: string; specifiers: IImportSpecifierData[] } { + let source = prototype.package; + if (relativeFilepath && isFilepath(source)) { + source = getRelativePath(relativeFilepath, source); + } + if (source.endsWith('.js')) { + source = source.slice(0, -3); + } + + const specifiers: IImportSpecifierData[] = []; + + if (prototype.exportType === 'defaultExport') { + specifiers.push({ + localName: prototype.name, + type: 'ImportDefaultSpecifier', + }); + } else { + [prototype.name, ...(prototype.relatedImports || [])].forEach((item) => { + specifiers.push({ + localName: item, + type: 'ImportSpecifier', + }); + }); + } + + return { + source, + specifiers, + }; +} + /** * 根据组件的 prototype 生成 ImportDeclarationPayload + * @deprecated */ export function getImportDeclarationPayloadByPrototype( prototype: ComponentPrototypeType, diff --git a/packages/core/src/models/interfaces.ts b/packages/core/src/models/interfaces.ts index e7f24bc..9095d0f 100644 --- a/packages/core/src/models/interfaces.ts +++ b/packages/core/src/models/interfaces.ts @@ -5,12 +5,12 @@ import { DragSource } from './drag-source'; import { IFileConfig, FileType, - IImportDeclarationPayload, InsertChildPositionType, ITangoConfigPackages, IPageConfigData, IServiceFunctionPayload, IImportSpecifierSourceData, + IImportSpecifierData, } from '../types'; import { TangoFile, TangoJsonFile } from './file'; import { TangoRouteModule } from './route-module'; @@ -33,6 +33,14 @@ export interface IViewFile { update: (code?: string, isFormatCode?: boolean, refreshWorkspace?: boolean) => void; + /** + * 添加新的导入符号 + * @param source 导入来源 + * @param newSpecifiers 新导入符号列表 + * @returns this + */ + addImportSpecifiers: (source: string, newSpecifiers: IImportSpecifierData[]) => IViewFile; + getNode: (targetNodeId: string) => IViewNode; removeNode: (targetNodeId: string) => IViewFile; @@ -41,31 +49,15 @@ export interface IViewFile { targetNodeId: string, newNode: any, position?: InsertChildPositionType, - sourcePrototype?: string | ComponentPrototypeType, ) => IViewFile; - insertAfter: ( - targetNodeId: string, - newNode: any, - sourcePrototype?: string | ComponentPrototypeType, - ) => IViewFile; + insertAfter: (targetNodeId: string, newNode: any) => IViewFile; - insertBefore: ( - targetNodeId: string, - newNode: any, - sourcePrototype?: string | ComponentPrototypeType, - ) => IViewFile; + insertBefore: (targetNodeId: string, newNode: any) => IViewFile; - replaceNode: ( - targetNodeId: string, - newNode: any, - sourcePrototype?: string | ComponentPrototypeType, - ) => IViewFile; + replaceNode: (targetNodeId: string, newNode: any) => IViewFile; - replaceViewChildren: ( - rawNodes: any[], - importDeclarations?: IImportDeclarationPayload[], - ) => IViewFile; + replaceViewChildren: (rawNodes: any[]) => IViewFile; updateNodeAttribute: ( nodeId: string, diff --git a/packages/core/src/models/module.ts b/packages/core/src/models/module.ts index 5e47f92..e355b87 100644 --- a/packages/core/src/models/module.ts +++ b/packages/core/src/models/module.ts @@ -6,8 +6,8 @@ import { ast2code, formatCode, traverseFile, - addImportDeclaration2, - updateImportDeclaration2, + addImportDeclaration, + updateImportDeclaration, } from '../helpers'; import { TangoFile } from './file'; import { IFileConfig, IImportSpecifierData, ImportDeclarationDataType } from '../types'; @@ -52,12 +52,12 @@ export class TangoModule extends TangoFile { } addImportDeclaration(source: string, specifiers: IImportSpecifierData[]) { - addImportDeclaration2(this.ast, source, specifiers); + this.ast = addImportDeclaration(this.ast, source, specifiers); return this; } updateImportDeclaration(source: string, specifiers: IImportSpecifierData[]) { - updateImportDeclaration2(this.ast, source, specifiers); + this.ast = updateImportDeclaration(this.ast, source, specifiers); return this; } diff --git a/packages/core/src/models/view-module.ts b/packages/core/src/models/view-module.ts index 010f902..b84537a 100644 --- a/packages/core/src/models/view-module.ts +++ b/packages/core/src/models/view-module.ts @@ -1,6 +1,6 @@ import * as t from '@babel/types'; import { action, computed, makeObservable, observable, toJS } from 'mobx'; -import { ComponentPrototypeType, Dict } from '@music163/tango-helpers'; +import { Dict } from '@music163/tango-helpers'; import { ast2code, traverseViewFile, @@ -8,15 +8,17 @@ import { insertSiblingAfterJSXElement, appendChildToJSXElement, addImportDeclaration, - updateImportDeclaration, replaceJSXElement, - getImportDeclarationPayloadByPrototype, removeUnusedImportSpecifiers, insertSiblingBeforeJSXElement, replaceRootJSXElementChildren, IdGenerator, updateJSXAttributes, queryXFormItemFields, + prototype2importDeclarationData, + insertImportSpecifiers, + addImportDeclarationLegacy, + updateImportDeclarationLegacy, } from '../helpers'; import { TangoNode } from './node'; import { @@ -26,10 +28,57 @@ import { InsertChildPositionType, IImportSpecifierSourceData, ImportDeclarationDataType, + IImportSpecifierData, } from '../types'; import { IViewFile, IWorkspace } from './interfaces'; import { TangoModule } from './module'; +/** + * 导入信息转为 变量名->来源 的 map 结构 + * @param importedModules + * @returns + */ +function buildImportMap(importedModules: ImportDeclarationDataType) { + const map: Dict = {}; + Object.keys(importedModules).forEach((source) => { + const specifiers = importedModules[source]; + specifiers?.forEach((specifier) => { + map[specifier.localName] = { + source, + isDefault: specifier.type === 'ImportDefaultSpecifier', + }; + }); + }); + return map; +} + +/** + * 将节点列表转换为 tree data 嵌套数组 + * @param list + */ +function nodeListToTreeData(list: ITangoViewNodeData[]) { + const map: Record = {}; + + list.forEach((item) => { + // 如果不存在,则初始化 + if (!map[item.id]) { + map[item.id] = { + ...item, + children: [], + }; + } + + // 是否找到父节点,找到则塞进去 + if (item.parentId && map[item.parentId]) { + map[item.parentId].children.push(map[item.id]); + } + }); + + // 保留根节点 + const ret = Object.values(map).filter((item) => !item.parentId); + return ret; +} + /** * 视图模块 */ @@ -111,7 +160,7 @@ export class TangoViewModule extends TangoModule implements IViewFile { this._importedModules = importedModules; this.imports = imports; - this.importMap = this.buildImportMap(imports); + this.importMap = buildImportMap(imports); this.variables = variables; this._nodes.clear(); @@ -172,27 +221,30 @@ export class TangoViewModule extends TangoModule implements IViewFile { } /** - * 基于组件的 prototype 信息更新导入信息 - * TODO: 和 Module.addImportDeclaration 中的保持一致 - * @deprecated - * @param prototype - * @param shouldUpdateCode + * 添加导入符号 + * @param source + * @param newSpecifiers + * @returns */ - updateImportSpecifiersByPrototype(sourcePrototype: string | ComponentPrototypeType) { - const prototype = this.workspace.getPrototype(sourcePrototype); - if (prototype) { - const importDeclaration = getImportDeclarationPayloadByPrototype(prototype, this.filename); - this.updateImportSpecifiers(importDeclaration); + addImportSpecifiers(source: string, newSpecifiers: IImportSpecifierData[]) { + const existSpecifiers = this.imports[source]; + if (existSpecifiers) { + const insertedSpecifiers = newSpecifiers.filter((item) => { + return !existSpecifiers.find((existItem) => existItem.localName === item.localName); + }); + this.ast = insertImportSpecifiers(this.ast, source, insertedSpecifiers); + } else { + // 不存在导入来源,直接添加新的导入语句 + this.ast = addImportDeclaration(this.ast, source, newSpecifiers); } return this; } /** - * 更新导入的变量(新版) - * TODO: 和 Module.updateImportDeclaration 中的保持一致 - * @deprecated + * 更新导入的变量 + * @deprecated 使用 updateImportDeclaration 代替 */ - updateImportSpecifiers(importDeclaration: IImportDeclarationPayload) { + updateImportSpecifiersLegacy(importDeclaration: IImportDeclarationPayload) { const mods = this._importedModules[importDeclaration.sourcePath]; let ast; // 如果模块已存在,需要去重 @@ -207,12 +259,12 @@ export class TangoViewModule extends TangoModule implements IViewFile { (name) => !specifiers.includes(name), ); - ast = updateImportDeclaration(this.ast, { + ast = updateImportDeclarationLegacy(this.ast, { ...importDeclaration, specifiers: newSpecifiers.concat(targetMod.specifiers), }); } else { - ast = addImportDeclaration(this.ast, importDeclaration); + ast = addImportDeclarationLegacy(this.ast, importDeclaration); } this.ast = ast; return this; @@ -257,7 +309,8 @@ export class TangoViewModule extends TangoModule implements IViewFile { // 导入依赖的组件 relatedImports.forEach((name: string) => { const proto = this.workspace.getPrototype(name); - this.updateImportSpecifiersByPrototype(proto); + const { source, specifiers } = prototype2importDeclarationData(proto, this.filename); + this.addImportSpecifiers(source, specifiers); }); } this.ast = updateJSXAttributes(this.ast, nodeId, config); @@ -268,43 +321,25 @@ export class TangoViewModule extends TangoModule implements IViewFile { * 插入子节点的最后面 * @param targetNodeId * @param newNode - * @param sourceName + * @param position * @returns */ insertChild( targetNodeId: string, newNode: t.JSXElement, position: InsertChildPositionType = 'last', - sourceName: string | ComponentPrototypeType, ) { this.ast = appendChildToJSXElement(this.ast, targetNodeId, newNode, position); - if (sourceName) { - this.updateImportSpecifiersByPrototype(sourceName); - } return this; } - insertAfter( - targetNodeId: string, - newNode: t.JSXElement, - sourceName?: string | ComponentPrototypeType, - ) { + insertAfter(targetNodeId: string, newNode: t.JSXElement) { this.ast = insertSiblingAfterJSXElement(this.ast, targetNodeId, newNode); - if (sourceName) { - this.updateImportSpecifiersByPrototype(sourceName); - } return this; } - insertBefore( - targetNodeId: string, - newNode: t.JSXElement, - sourceName?: string | ComponentPrototypeType, - ) { + insertBefore(targetNodeId: string, newNode: t.JSXElement) { this.ast = insertSiblingBeforeJSXElement(this.ast, targetNodeId, newNode); - if (sourceName) { - this.updateImportSpecifiersByPrototype(sourceName); - } return this; } @@ -312,22 +347,15 @@ export class TangoViewModule extends TangoModule implements IViewFile { * 替换目标节点为新节点 * @param targetNodeId * @param newNode - * @param sourcePrototype */ - replaceNode( - targetNodeId: string, - newNode: t.JSXElement, - sourceName?: string | ComponentPrototypeType, - ) { + replaceNode(targetNodeId: string, newNode: t.JSXElement) { this.ast = replaceJSXElement(this.ast, targetNodeId, newNode); - if (sourceName) { - this.updateImportSpecifiersByPrototype(sourceName); - } return this; } /** * 替换 jsx 跟结点的子元素 + * @deprecated 不推荐使用 */ replaceViewChildren( childrenNodes: t.JSXElement[], @@ -339,51 +367,10 @@ export class TangoViewModule extends TangoModule implements IViewFile { if (importDeclarations?.length) { importDeclarations.forEach((item) => { - this.updateImportSpecifiers(item); + this.updateImportSpecifiersLegacy(item); }); } return this; } - - private buildImportMap(importedModules: ImportDeclarationDataType) { - const map: Dict = {}; - Object.keys(importedModules).forEach((source) => { - const specifiers = importedModules[source]; - specifiers?.forEach((specifier) => { - map[specifier.localName] = { - source, - isDefault: specifier.type === 'ImportDefaultSpecifier', - }; - }); - }); - return map; - } -} - -/** - * 将节点列表转换为 tree data 嵌套数组 - * @param list - */ -function nodeListToTreeData(list: ITangoViewNodeData[]) { - const map: Record = {}; - - list.forEach((item) => { - // 如果不存在,则初始化 - if (!map[item.id]) { - map[item.id] = { - ...item, - children: [], - }; - } - - // 是否找到父节点,找到则塞进去 - if (item.parentId && map[item.parentId]) { - map[item.parentId].children.push(map[item.id]); - } - }); - - // 保留根节点 - const ret = Object.values(map).filter((item) => !item.parentId); - return ret; } diff --git a/packages/core/src/models/workspace.ts b/packages/core/src/models/workspace.ts index 356e568..af4b794 100644 --- a/packages/core/src/models/workspace.ts +++ b/packages/core/src/models/workspace.ts @@ -17,6 +17,7 @@ import { namesToImportDeclarations, getBlockNameByFilename, getPrivilegeCode, + prototype2importDeclarationData, } from '../helpers'; import { DropMethod } from './drop-target'; import { HistoryMessage, TangoHistory } from './history'; @@ -950,7 +951,7 @@ export class Workspace extends EventTarget implements IWorkspace { ); importDeclarations.forEach((importDeclaration) => { - this.activeViewModule.updateImportSpecifiers(importDeclaration); + this.activeViewModule.updateImportSpecifiersLegacy(importDeclaration); }); this.copyTempNodes.forEach((node) => { @@ -1001,7 +1002,11 @@ export class Workspace extends EventTarget implements IWorkspace { const sourcePrototype = this.getPrototype(sourceName); const newNode = prototype2jsxElement(sourcePrototype); const file = this.getNode(targetNodeId).file; - file.insertChild(targetNodeId, newNode, 'last', sourcePrototype).update(); + const { source, specifiers } = prototype2importDeclarationData(sourcePrototype, file.filename); + file + .insertChild(targetNodeId, newNode, 'last') + .addImportSpecifiers(source, specifiers) + .update(); this.history.push({ message: HistoryMessage.InsertNode, data: { @@ -1021,7 +1026,8 @@ export class Workspace extends EventTarget implements IWorkspace { const sourcePrototype = this.getPrototype(sourceName); const newNode = prototype2jsxElement(sourcePrototype); const file = this.getNode(targetNodeId).file; - file.replaceNode(targetNodeId, newNode, sourcePrototype).update(); + const { source, specifiers } = prototype2importDeclarationData(sourcePrototype, file.filename); + file.replaceNode(targetNodeId, newNode).addImportSpecifiers(source, specifiers).update(); this.history.push({ message: HistoryMessage.ReplaceNode, data: { @@ -1039,7 +1045,14 @@ export class Workspace extends EventTarget implements IWorkspace { if (insertedPrototype) { const newNode = prototype2jsxElement(insertedPrototype); const file = this.selectSource.file; - file.insertChild(this.selectSource.first.id, newNode, 'last', insertedPrototype).update(); + const { source, specifiers } = prototype2importDeclarationData( + insertedPrototype, + file.filename, + ); + file + .insertChild(this.selectSource.first.id, newNode, 'last') + .addImportSpecifiers(source, specifiers) + .update(); this.history.push({ message: HistoryMessage.InsertNode, data: { @@ -1095,30 +1108,40 @@ export class Workspace extends EventTarget implements IWorkspace { const targetFile = dropTarget.node?.file; const sourceFile = dragSource.node?.file; + // dragSourcePrototype to importDeclarations + const { source, specifiers } = prototype2importDeclarationData( + dragSourcePrototype, + targetFile.filename, + ); + let isValidOperation = true; switch (dropTarget.method) { // 直接往目标节点的 children 里添加一个节点 case DropMethod.InsertChild: { - targetFile.insertChild(dropTarget.id, newNode, 'last', dragSourcePrototype); + targetFile + .insertChild(dropTarget.id, newNode, 'last') + .addImportSpecifiers(source, specifiers); break; } case DropMethod.InsertFirstChild: { - targetFile.insertChild(dropTarget.id, newNode, 'first', dragSourcePrototype); + targetFile + .insertChild(dropTarget.id, newNode, 'first') + .addImportSpecifiers(source, specifiers); break; } // 往目标节点的后边插入一个节点 case DropMethod.InsertAfter: { - targetFile.insertAfter(dropTarget.id, newNode, dragSourcePrototype); + targetFile.insertAfter(dropTarget.id, newNode).addImportSpecifiers(source, specifiers); break; } // 往目标节点的前方插入一个节点 case DropMethod.InsertBefore: { - targetFile.insertBefore(dropTarget.id, newNode, dragSourcePrototype); + targetFile.insertBefore(dropTarget.id, newNode).addImportSpecifiers(source, specifiers); break; } // 替换目标节点 case DropMethod.ReplaceNode: { - targetFile.replaceNode(dropTarget.id, newNode, dragSourcePrototype); + targetFile.replaceNode(dropTarget.id, newNode).addImportSpecifiers(source, specifiers); break; } default: diff --git a/packages/helpers/src/types/advanced.ts b/packages/helpers/src/types/advanced.ts index f2e7dd8..01fd1db 100644 --- a/packages/helpers/src/types/advanced.ts +++ b/packages/helpers/src/types/advanced.ts @@ -33,94 +33,11 @@ export type OptionType = { relatedImports?: string[]; }; -type TangoSchemaTreeNodePropValueBaseType = { - value: string | number | boolean; - rawCode: string; -}; - -type TangoSchemaTreeNodePropValueSlotType = { - type: 'Slot'; - value: TangoSchemaTreeNodeType; -}; - -type TangoSchemaTreeNodePropValueType = - | string - | number - | boolean - | object - | TangoSchemaTreeNodePropValueBaseType - | TangoSchemaTreeNodePropValueSlotType; - -export type TangoSchemaTreeNodeType = { - /** - * 节点唯一标识 - */ - id?: string; - /** - * 节点组件名 - */ - component?: string; - /** - * 节点属性集合 - */ - props?: Record; - /** - * 节点是否渲染 - * TODO: 支持变量表达式 - */ - isRender?: boolean; - /** - * 子节点 - */ - children?: TangoSchemaTreeNodeType[]; -}; - /** * 服务函数类型 */ export type ServiceFunctionType = (...args: any[]) => Promise; -export type TangoRemoteServicesType = { - /** - * 图片服务 - */ - ImageService?: { - listMy: ServiceFunctionType; - listFav: ServiceFunctionType; - listPub: ServiceFunctionType; - }; - /** - * 数据源服务 - */ - OxService?: { - listApp: ServiceFunctionType; - listBranch: ServiceFunctionType; - listApi: ServiceFunctionType; - listApiByPage: ServiceFunctionType; - }; - /** - * 依赖面板服务 - */ - DependencyService?: { - listBizDependencies: ServiceFunctionType; - listBaseDependencies: ServiceFunctionType; - listPackageVersions: ServiceFunctionType; - }; - RiddleService?: { - listBlock: ServiceFunctionType; - postBlock: ServiceFunctionType; - updateBlock: ServiceFunctionType; - }; - /** - * AIGC 服务 - */ - GptService?: { - codeCompletion?: ServiceFunctionType; - textCompletion?: ServiceFunctionType; - textEmbedding?: ServiceFunctionType; - }; -}; - export type RelatedDependencyType = { name: string; version: string }; /** @@ -163,63 +80,3 @@ export type SetterOnChangeDetailType = { relatedImports?: string[]; isRawCode?: boolean; }; - -/** - * 智能向导生成类型 - */ -export enum WizardType { - NEW = 'new', - REPLACE = 'replace', - PREVIEW = 'preview', -} - -/** - * 智能向导OX模型定义 - */ -export interface IOXModel { - key: string; // 唯一标识 (字段名加哈希值) - name: string; // 字段名 - description: string; // 字段描述 - basicDataModelName: 'List' | 'Integer' | 'int' | 'String' | 'long' | 'boolean' | 'ENUM'; // 字段类型 - dataModelFieldDTOList: IOXModel[]; - type: 'ARRAY' | 'BASIC' | 'CLASS' | 'GENERIC' | 'ENUM' | 'MAP'; - extra: IOXModel; - extras: IOXModel[]; - linkedDataModelName: String; - linkedModelDTO: { - type: 'ARRAY' | 'BASIC' | 'CLASS' | 'GENERIC' | 'ENUM' | 'MAP'; - fieldDTOList: IOXModel[]; - }; - paramType: 'RequestParam' | 'JsonRequestParam'; // 请求传参类型 -} - -/** - * 通用智能向导 - */ -type ChildType = Array>; - -export type IDataProviderFormProps = { - loadData: string; - payload: Record; - model: string; - formatter: (res: any) => any; -}; - -export interface CommonGuideFormValueType { - fatherComponentName: string; - fatherProps: Record; - childComponentName: string; - children: ChildType; - dataProviderProps: IDataProviderFormProps; - childPropsConfig: { - // 字段名对应属性名 - fieldName: string; - // 字段注释对应属性名 - fieldDescriptionName: string; - // 字段值类型对应属性类型 (暂时用不到) - fieldType?: string; - }; -} -/** - * end - */ diff --git a/packages/helpers/src/types/base.ts b/packages/helpers/src/types/base.ts index 7ae1556..7a14c7a 100644 --- a/packages/helpers/src/types/base.ts +++ b/packages/helpers/src/types/base.ts @@ -15,8 +15,8 @@ export type PartialRecord = { [P in K]?: T; }; -export type ReactComponentProps = { +export interface ReactComponentProps { children?: React.ReactNode; style?: React.CSSProperties; className?: string; -}; +}