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;
-};
+}