mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-12 19:52:51 +00:00
Merge pull request #212 from alibaba/hotfix/code-gen-import-issue
hotfix: 出码模块 - 解决 componentName 和 exportName 不一致时生成的 import 语句的问题
This commit is contained in:
commit
7cbfadee9d
@ -2,6 +2,27 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [1.0.3](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2...@alilc/lowcode-code-generator@1.0.3) (2022-03-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add getConvertedExtraKey / getOriginalExtraKey to utils ([8e7bb9d](https://github.com/alibaba/lowcode-engine/commit/8e7bb9d4b86454dd77c6928eb769cd764cad8630))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 🐛 出码: 解决 componentName 和 exportName 不一致时生成的 import 语句的问题 ([eefc091](https://github.com/alibaba/lowcode-engine/commit/eefc091ee7e86d6214d20d486212cb5aff237946))
|
||||||
|
* component cannot be redisplayed by configuration after rendering is closed ([c54f369](https://github.com/alibaba/lowcode-engine/commit/c54f369e1860d818479dda9d6429f851c0b08fa6))
|
||||||
|
* fix loop configuration auto fill empty array issue ([d087092](https://github.com/alibaba/lowcode-engine/commit/d087092fd712eff0556adacda692d3ff6f2f9f22))
|
||||||
|
* make important true by default ([c63b6e1](https://github.com/alibaba/lowcode-engine/commit/c63b6e1bfadc3fc87ed41840952e02ffbff24fab))
|
||||||
|
* make insertAfter & insertBefore work ([70fd372](https://github.com/alibaba/lowcode-engine/commit/70fd3720d098d6e227acb9281ee22feee66b9c0b))
|
||||||
|
* npm源 ([437adcc](https://github.com/alibaba/lowcode-engine/commit/437adccf5f2dbb400de6e2bef10cfc4b65286f2b))
|
||||||
|
* prop should return undefined when all items are undefined ([5bb9ec7](https://github.com/alibaba/lowcode-engine/commit/5bb9ec7a1dfaabfdb5369226b54d5f63a7999e59))
|
||||||
|
* should not create new prop while querying fileName ([19c207d](https://github.com/alibaba/lowcode-engine/commit/19c207d29de045f473ba73baaf34e7294d40261a))
|
||||||
|
* variable binding lost after modify the mock value ([ef95b56](https://github.com/alibaba/lowcode-engine/commit/ef95b5683273d8302bde1582de8afe3d87a808d8))
|
||||||
|
* Workbench should receive the original skeleton other than shell skeleton ([d5c3ca1](https://github.com/alibaba/lowcode-engine/commit/d5c3ca1068ce2c2140980bd059d0da333574dc34))
|
||||||
|
|
||||||
### [1.0.2](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2-beta.1...@alilc/lowcode-code-generator@1.0.2) (2022-03-08)
|
### [1.0.2](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2-beta.1...@alilc/lowcode-code-generator@1.0.2) (2022-03-08)
|
||||||
|
|
||||||
### [1.0.2-beta.1](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2-beta.0...@alilc/lowcode-code-generator@1.0.2-beta.1) (2022-03-08)
|
### [1.0.2-beta.1](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2-beta.0...@alilc/lowcode-code-generator@1.0.2-beta.1) (2022-03-08)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@alilc/lowcode-code-generator",
|
"name": "@alilc/lowcode-code-generator",
|
||||||
"version": "1.0.2",
|
"version": "1.0.3",
|
||||||
"description": "出码引擎 for LowCode Engine",
|
"description": "出码引擎 for LowCode Engine",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { flatMap } from 'lodash';
|
import { flatMap, camelCase, get } from 'lodash';
|
||||||
import { COMMON_CHUNK_NAME } from '../../const/generator';
|
import { COMMON_CHUNK_NAME } from '../../const/generator';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -71,6 +71,37 @@ function getDependencyIdentifier(info: IDependencyItem): string {
|
|||||||
return info.aliasName || info.exportName;
|
return info.aliasName || info.exportName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getExportNameOfDep(dep: IDependency): string {
|
||||||
|
if (dep.destructuring) {
|
||||||
|
return (
|
||||||
|
dep.exportName ||
|
||||||
|
dep.componentName ||
|
||||||
|
throwNewError('destructuring dependency must have exportName or componentName')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dep.subName) {
|
||||||
|
return (
|
||||||
|
dep.componentName ||
|
||||||
|
dep.exportName ||
|
||||||
|
throwNewError('dependency item must have componentName or exportName')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
dep.exportName ||
|
||||||
|
`__$${camelCase(
|
||||||
|
get(dep, 'moduleName') ||
|
||||||
|
get(dep, 'package') ||
|
||||||
|
throwNewError('dep.moduleName or dep.package is undefined'),
|
||||||
|
)}_default`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function throwNewError(msg: string): never {
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
function buildPackageImport(
|
function buildPackageImport(
|
||||||
pkg: string,
|
pkg: string,
|
||||||
deps: IDependency[],
|
deps: IDependency[],
|
||||||
@ -90,7 +121,7 @@ function buildPackageImport(
|
|||||||
|
|
||||||
const depsInfo: IDependencyItem[] = deps.map((dep) => {
|
const depsInfo: IDependencyItem[] = deps.map((dep) => {
|
||||||
const info: IDependencyItem = {
|
const info: IDependencyItem = {
|
||||||
exportName: dep.exportName,
|
exportName: getExportNameOfDep(dep),
|
||||||
isDefault: !dep.destructuring,
|
isDefault: !dep.destructuring,
|
||||||
subName: dep.subName || undefined,
|
subName: dep.subName || undefined,
|
||||||
nodeIdentifier: dep.componentName || undefined,
|
nodeIdentifier: dep.componentName || undefined,
|
||||||
@ -171,24 +202,21 @@ function buildPackageImport(
|
|||||||
|
|
||||||
// 发现 nodeIdentifier 与 exportName 或者 aliasName 冲突的场景
|
// 发现 nodeIdentifier 与 exportName 或者 aliasName 冲突的场景
|
||||||
const nodeIdentifiers = depsInfo.map((info) => info.nodeIdentifier).filter(Boolean);
|
const nodeIdentifiers = depsInfo.map((info) => info.nodeIdentifier).filter(Boolean);
|
||||||
const conflictInfos = flatMap(
|
const conflictInfos = flatMap(Object.keys(exportItems), (exportName) => {
|
||||||
Object.keys(exportItems),
|
const exportItem = exportItems[exportName];
|
||||||
(exportName) => {
|
const usedNames = [
|
||||||
const exportItem = exportItems[exportName];
|
...exportItem.aliasNames,
|
||||||
const usedNames = [
|
...(exportItem.needOriginExport || exportItem.aliasNames.length <= 0 ? [exportName] : []),
|
||||||
...exportItem.aliasNames,
|
];
|
||||||
...(exportItem.needOriginExport || exportItem.aliasNames.length <= 0 ? [exportName] : []),
|
const conflictNames = usedNames.filter((n) => nodeIdentifiers.indexOf(n) >= 0);
|
||||||
|
if (conflictNames.length > 0) {
|
||||||
|
return [
|
||||||
|
...(conflictNames.indexOf(exportName) >= 0 ? [[exportName, true, exportItem]] : []),
|
||||||
|
...conflictNames.filter((n) => n !== exportName).map((n) => [n, false, exportItem]),
|
||||||
];
|
];
|
||||||
const conflictNames = usedNames.filter((n) => nodeIdentifiers.indexOf(n) >= 0);
|
}
|
||||||
if (conflictNames.length > 0) {
|
return [];
|
||||||
return [
|
});
|
||||||
...(conflictNames.indexOf(exportName) >= 0 ? [[exportName, true, exportItem]] : []),
|
|
||||||
...conflictNames.filter((n) => n !== exportName).map((n) => [n, false, exportItem]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const conflictExports = conflictInfos.filter((c) => c[1]).map((c) => c[0] as string);
|
const conflictExports = conflictInfos.filter((c) => c[1]).map((c) => c[0] as string);
|
||||||
const conflictAlias = conflictInfos.filter((c) => !c[1]).map((c) => c[0] as string);
|
const conflictAlias = conflictInfos.filter((c) => !c[1]).map((c) => c[0] as string);
|
||||||
@ -282,6 +310,12 @@ function buildPackageImport(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (info.aliasName) {
|
} else if (info.aliasName) {
|
||||||
|
// default 方式的导入会生成单独de import 语句,无需生成赋值语句
|
||||||
|
if (info.isDefault && defaultExportNames.find((n) => n === info.aliasName)) {
|
||||||
|
delete aliasDefineStatements[info.aliasName];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let contentStatement = '';
|
let contentStatement = '';
|
||||||
if (aliasDefineStatements[info.aliasName]) {
|
if (aliasDefineStatements[info.aliasName]) {
|
||||||
contentStatement = aliasDefineStatements[info.aliasName];
|
contentStatement = aliasDefineStatements[info.aliasName];
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import Super, {
|
|||||||
SearchTable as SearchTableExport,
|
SearchTable as SearchTableExport,
|
||||||
} from "@alifd/next";
|
} from "@alifd/next";
|
||||||
|
|
||||||
|
import SuperOther from "@alifd/next";
|
||||||
|
|
||||||
import utils from "../../utils";
|
import utils from "../../utils";
|
||||||
|
|
||||||
import { i18n as _$$i18n } from "../../i18n";
|
import { i18n as _$$i18n } from "../../i18n";
|
||||||
@ -17,8 +19,6 @@ import "./index.css";
|
|||||||
|
|
||||||
const SuperSub = Super.Sub;
|
const SuperSub = Super.Sub;
|
||||||
|
|
||||||
const SuperOther = Super;
|
|
||||||
|
|
||||||
const SelectOption = Select.Option;
|
const SelectOption = Select.Option;
|
||||||
|
|
||||||
const SearchTable = SearchTableExport.default;
|
const SearchTable = SearchTableExport.default;
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"componentsMap": [
|
||||||
|
{
|
||||||
|
"package": "example-package",
|
||||||
|
"version": "1.2.3",
|
||||||
|
"exportName": "Bar",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"destructuring": false,
|
||||||
|
"subName": "",
|
||||||
|
"componentName": "Foo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"componentsTree": [
|
||||||
|
{
|
||||||
|
"componentName": "Page",
|
||||||
|
"id": "node_ocl137q7oc1",
|
||||||
|
"fileName": "test",
|
||||||
|
"props": { "style": {} },
|
||||||
|
"lifeCycles": {},
|
||||||
|
"dataSource": { "list": [] },
|
||||||
|
"state": {},
|
||||||
|
"methods": {},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Foo",
|
||||||
|
"id": "node_ocl137q7oc4",
|
||||||
|
"props": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"i18n": {}
|
||||||
|
}
|
||||||
@ -0,0 +1,221 @@
|
|||||||
|
import CodeGenerator from '../../src';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { ProjectSchema } from '@alilc/lowcode-types';
|
||||||
|
|
||||||
|
const testCaseBaseName = path.basename(__filename, '.test.ts');
|
||||||
|
const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);
|
||||||
|
const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);
|
||||||
|
|
||||||
|
jest.setTimeout(60 * 60 * 1000);
|
||||||
|
|
||||||
|
describe(testCaseBaseName, () => {
|
||||||
|
test('default import', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Bar',
|
||||||
|
main: 'lib/index.js',
|
||||||
|
destructuring: false,
|
||||||
|
subName: '',
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(`import Foo from "example-package/lib/index.js";`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('named import with no alias', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Foo',
|
||||||
|
main: 'lib/index.js',
|
||||||
|
destructuring: true,
|
||||||
|
subName: '',
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(
|
||||||
|
`import { Foo } from "example-package/lib/index.js";`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('named import with alias', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Bar',
|
||||||
|
main: 'lib/index.js',
|
||||||
|
destructuring: true,
|
||||||
|
subName: '',
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(
|
||||||
|
`import { Bar as Foo } from "example-package/lib/index.js";`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('default import with same name', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Foo',
|
||||||
|
main: 'lib/index.js',
|
||||||
|
destructuring: false,
|
||||||
|
subName: '',
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(`import Foo from "example-package/lib/index.js";`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('default import with sub name and export name', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Bar',
|
||||||
|
main: 'lib/index.js',
|
||||||
|
destructuring: false,
|
||||||
|
subName: 'Baz',
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(`import Bar from "example-package/lib/index.js";`);
|
||||||
|
|
||||||
|
expect(generatedPageFileContent).toContain(`const Foo = Bar.Baz;`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('default import with sub name without export name', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
main: 'lib/index.js',
|
||||||
|
destructuring: false,
|
||||||
|
exportName: '',
|
||||||
|
subName: 'Baz',
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(
|
||||||
|
`import __$examplePackage_default from "example-package/lib/index.js";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(generatedPageFileContent).toContain(`const Foo = __$examplePackage_default.Baz;`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('named import with sub name', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Bar',
|
||||||
|
main: 'lib/index.js',
|
||||||
|
destructuring: true,
|
||||||
|
subName: 'Baz',
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(
|
||||||
|
`import { Bar } from "example-package/lib/index.js";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(generatedPageFileContent).toContain(`const Foo = Bar.Baz;`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('default imports with different componentName', async () => {
|
||||||
|
await exportProject(inputSchemaJsonFile, outputDir, {
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Bar',
|
||||||
|
destructuring: false,
|
||||||
|
componentName: 'Foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
package: 'example-package',
|
||||||
|
version: '1.2.3',
|
||||||
|
exportName: 'Bar',
|
||||||
|
destructuring: false,
|
||||||
|
componentName: 'Baz',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
componentsTree: [
|
||||||
|
{
|
||||||
|
componentName: 'Page',
|
||||||
|
fileName: 'test',
|
||||||
|
dataSource: { list: [] },
|
||||||
|
children: [{ componentName: 'Foo' }, { componentName: 'Baz' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
|
||||||
|
expect(generatedPageFileContent).toContain(`import Foo from "example-package";`);
|
||||||
|
expect(generatedPageFileContent).toContain(`import Baz from "example-package";`);
|
||||||
|
|
||||||
|
expect(generatedPageFileContent).not.toContain(`const Foo =`);
|
||||||
|
expect(generatedPageFileContent).not.toContain(`const Baz =`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function exportProject(
|
||||||
|
importPath: string,
|
||||||
|
outputPath: string,
|
||||||
|
mergeSchema?: Partial<ProjectSchema>,
|
||||||
|
) {
|
||||||
|
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
|
||||||
|
const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };
|
||||||
|
const builder = CodeGenerator.solutions.icejs();
|
||||||
|
|
||||||
|
return builder.generateProject(schema).then(async (result) => {
|
||||||
|
// displayResultInConsole(result);
|
||||||
|
const publisher = CodeGenerator.publishers.disk();
|
||||||
|
await publisher.publish({
|
||||||
|
project: result,
|
||||||
|
outputPath,
|
||||||
|
projectSlug: 'demo-project',
|
||||||
|
createProjectFolder: true,
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function readOutputTextFile(outputFilePath: string): string {
|
||||||
|
return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user