fix: 🐛 出码: 解决 componentName 和 exportName 不一致时生成的 import 语句的问题

This commit is contained in:
Clarence-pan 2022-03-29 12:06:13 +08:00
parent d086267990
commit eefc091ee7
4 changed files with 310 additions and 21 deletions

View File

@ -1,4 +1,4 @@
import { flatMap } from 'lodash';
import { flatMap, camelCase, get } from 'lodash';
import { COMMON_CHUNK_NAME } from '../../const/generator';
import {
@ -71,6 +71,37 @@ function getDependencyIdentifier(info: IDependencyItem): string {
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(
pkg: string,
deps: IDependency[],
@ -90,7 +121,7 @@ function buildPackageImport(
const depsInfo: IDependencyItem[] = deps.map((dep) => {
const info: IDependencyItem = {
exportName: dep.exportName,
exportName: getExportNameOfDep(dep),
isDefault: !dep.destructuring,
subName: dep.subName || undefined,
nodeIdentifier: dep.componentName || undefined,
@ -171,9 +202,7 @@ function buildPackageImport(
// 发现 nodeIdentifier 与 exportName 或者 aliasName 冲突的场景
const nodeIdentifiers = depsInfo.map((info) => info.nodeIdentifier).filter(Boolean);
const conflictInfos = flatMap(
Object.keys(exportItems),
(exportName) => {
const conflictInfos = flatMap(Object.keys(exportItems), (exportName) => {
const exportItem = exportItems[exportName];
const usedNames = [
...exportItem.aliasNames,
@ -187,8 +216,7 @@ function buildPackageImport(
];
}
return [];
},
);
});
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);
@ -282,6 +310,12 @@ function buildPackageImport(
},
});
} else if (info.aliasName) {
// default 方式的导入会生成单独de import 语句,无需生成赋值语句
if (info.isDefault && defaultExportNames.find((n) => n === info.aliasName)) {
delete aliasDefineStatements[info.aliasName];
return;
}
let contentStatement = '';
if (aliasDefineStatements[info.aliasName]) {
contentStatement = aliasDefineStatements[info.aliasName];

View File

@ -9,6 +9,8 @@ import Super, {
SearchTable as SearchTableExport,
} from "@alifd/next";
import SuperOther from "@alifd/next";
import utils from "../../utils";
import { i18n as _$$i18n } from "../../i18n";
@ -17,8 +19,6 @@ import "./index.css";
const SuperSub = Super.Sub;
const SuperOther = Super;
const SelectOption = Select.Option;
const SearchTable = SearchTableExport.default;

View File

@ -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": {}
}

View File

@ -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');
}