Merge branch 'feat/for-merge' into feat/rax-code-generator

This commit is contained in:
春希 2020-08-14 04:25:13 +08:00
commit a4cf3ccc63
99 changed files with 14974 additions and 1073 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,20 +4,20 @@ const CodeGenerator = require('../lib').default;
function flatFiles(rootName, dir) { function flatFiles(rootName, dir) {
const dirRoot = rootName ? `${rootName}/${dir.name}` : dir.name; const dirRoot = rootName ? `${rootName}/${dir.name}` : dir.name;
const files = dir.files.map(file => ({ const files = dir.files.map((file) => ({
name: `${dirRoot}/${file.name}.${file.ext}`, name: `${dirRoot}/${file.name}.${file.ext}`,
content: file.content, content: file.content,
ext: '', ext: '',
})); }));
const filesInSub = dir.dirs.map(subDir => flatFiles(`${dirRoot}`, subDir)); const filesInSub = dir.dirs.map((subDir) => flatFiles(`${dirRoot}`, subDir));
const result = files.concat.apply(files, filesInSub); const result = files.concat(...filesInSub);
return result; return result;
} }
function displayResultInConsole(root, fileName) { function displayResultInConsole(root, fileName) {
const files = flatFiles('.', root); const files = flatFiles('.', root);
files.forEach(file => { files.forEach((file) => {
if (!fileName || fileName === file.name) { if (!fileName || fileName === file.name) {
console.log(`========== ${file.name} Start ==========`); console.log(`========== ${file.name} Start ==========`);
console.log(file.content); console.log(file.content);
@ -37,20 +37,62 @@ async function writeResultToDisk(root, path) {
}); });
} }
function getComponentsMap() {
const assetJson = fs.readFileSync('./demo/assets.json', { encoding: 'utf8' });
const assets = JSON.parse(assetJson);
const { components } = assets;
const componentsMap = components
.filter((c) => !!c.npm)
.map((c) => ({
componentName: c.componentName,
...(c.npm || {}),
}));
return componentsMap;
}
function main() { function main() {
const schemaJson = fs.readFileSync('./demo/sampleSchema.json', { encoding: 'utf8' }); const schemaJson = fs.readFileSync('./demo/sampleSchema.json', { encoding: 'utf8' });
const createIceJsProjectBuilder = CodeGenerator.solutions.icejs; const createIceJsProjectBuilder = CodeGenerator.solutions.icejs;
const builder = createIceJsProjectBuilder(); const builder = createIceJsProjectBuilder();
builder.generateProject(schemaJson).then(result => { builder.generateProject(schemaJson).then((result) => {
displayResultInConsole(result); displayResultInConsole(result);
writeResultToDisk(result, 'output/lowcodeDemo').then(response => writeResultToDisk(result, 'output/lowcodeDemo').then((response) =>
console.log('Write to disk: ', JSON.stringify(response)), console.log('Write to disk: ', JSON.stringify(response)),
); );
return result; return result;
}); });
} }
function demo() {
const schemaJson = fs.readFileSync('./demo/schema.json', { encoding: 'utf8' });
const createIceJsProjectBuilder = CodeGenerator.solutions.icejs;
const builder = createIceJsProjectBuilder();
const componentsMap = getComponentsMap();
const root = JSON.parse(schemaJson);
const fullSchema = {
version: '1.0.0',
config: {
historyMode: 'hash',
targetRootID: 'J_Container',
},
meta: {
name: 'demoproject',
},
componentsTree: [root],
componentsMap,
};
builder.generateProject(fullSchema).then((result) => {
displayResultInConsole(result);
return result;
});
}
function exportModule() { function exportModule() {
const schemaJson = fs.readFileSync('./demo/shenmaSample.json', { encoding: 'utf8' }); const schemaJson = fs.readFileSync('./demo/shenmaSample.json', { encoding: 'utf8' });
const moduleBuilder = CodeGenerator.createModuleBuilder({ const moduleBuilder = CodeGenerator.createModuleBuilder({
@ -66,13 +108,11 @@ function exportModule() {
CodeGenerator.plugins.react.jsx(), CodeGenerator.plugins.react.jsx(),
CodeGenerator.plugins.style.css(), CodeGenerator.plugins.style.css(),
], ],
postProcessors: [ postProcessors: [CodeGenerator.postprocessor.prettier()],
CodeGenerator.postprocessor.prettier(),
],
mainFileName: 'index', mainFileName: 'index',
}); });
moduleBuilder.generateModuleCode(schemaJson).then(result => { moduleBuilder.generateModuleCode(schemaJson).then((result) => {
displayResultInConsole(result); displayResultInConsole(result);
return result; return result;
}); });
@ -81,7 +121,7 @@ function exportModule() {
function exportProject() { function exportProject() {
const schemaJson = fs.readFileSync('./demo/sampleSchema.json', { encoding: 'utf8' }); const schemaJson = fs.readFileSync('./demo/sampleSchema.json', { encoding: 'utf8' });
const builder = CodeGenerator.createProjectBuilder({ const builder = CodeGenerator.createProjectBuilder({
template: CodeGenerator.solutionParts.icejs.template, template: CodeGenerator.solutionParts.icejs.template,
plugins: { plugins: {
components: [ components: [
@ -108,41 +148,21 @@ function exportProject() {
CodeGenerator.plugins.react.jsx(), CodeGenerator.plugins.react.jsx(),
CodeGenerator.plugins.style.css(), CodeGenerator.plugins.style.css(),
], ],
router: [ router: [CodeGenerator.plugins.common.esmodule(), CodeGenerator.solutionParts.icejs.plugins.router()],
CodeGenerator.plugins.common.esmodule(), entry: [CodeGenerator.solutionParts.icejs.plugins.entry()],
CodeGenerator.solutionParts.icejs.plugins.router(), constants: [CodeGenerator.plugins.project.constants()],
], utils: [CodeGenerator.plugins.common.esmodule(), CodeGenerator.plugins.project.utils()],
entry: [ i18n: [CodeGenerator.plugins.project.i18n()],
CodeGenerator.solutionParts.icejs.plugins.entry(), globalStyle: [CodeGenerator.solutionParts.icejs.plugins.globalStyle()],
], htmlEntry: [CodeGenerator.solutionParts.icejs.plugins.entryHtml()],
constants: [ packageJSON: [CodeGenerator.solutionParts.icejs.plugins.packageJSON()],
CodeGenerator.plugins.project.constants(),
],
utils: [
CodeGenerator.plugins.common.esmodule(),
CodeGenerator.plugins.project.utils(),
],
i18n: [
CodeGenerator.plugins.project.i18n(),
],
globalStyle: [
CodeGenerator.solutionParts.icejs.plugins.globalStyle(),
],
htmlEntry: [
CodeGenerator.solutionParts.icejs.plugins.entryHtml(),
],
packageJSON: [
CodeGenerator.solutionParts.icejs.plugins.packageJSON(),
],
}, },
postProcessors: [ postProcessors: [CodeGenerator.postprocessor.prettier()],
CodeGenerator.postprocessor.prettier(),
],
}); });
builder.generateProject(schemaJson).then(result => { builder.generateProject(schemaJson).then((result) => {
displayResultInConsole(result); displayResultInConsole(result);
writeResultToDisk(result, 'output/lowcodeDemo').then(response => writeResultToDisk(result, 'output/lowcodeDemo').then((response) =>
console.log('Write to disk: ', JSON.stringify(response)), console.log('Write to disk: ', JSON.stringify(response)),
); );
return result; return result;
@ -151,4 +171,5 @@ function exportProject() {
// main(); // main();
// exportModule(); // exportModule();
exportProject(); // exportProject();
demo();

View File

@ -0,0 +1,420 @@
{
"componentName": "Page",
"id": "node_dockcviv8fo1",
"props": {
"ref": "outterView",
"autoLoading": true,
"style": {
"padding": "0 5px 0 5px"
}
},
"fileName": "test",
"dataSource": {
"list": []
},
"state": {
"text": "outter",
"isShowDialog": false
},
"css": "body {font-size: 12px;} .botton{width:100px;color:#ff00ff}",
"lifeCycles": {
"componentDidMount": {
"type": "JSFunction",
"value": "function() {\n console.log('did mount');\n }"
},
"componentWillUnmount": {
"type": "JSFunction",
"value": "function() {\n console.log('will umount');\n }"
}
},
"methods": {
"testFunc": {
"type": "JSFunction",
"value": "function() {\n console.log('test func');\n }"
},
"onClick": {
"type": "JSFunction",
"value": "function(){\n this.setState({\n isShowDialog:true\n })\n\t}"
}
},
"children": [{
"componentName": "Box",
"id": "node_dockcy8n9xed",
"props": {
"style": {
"backgroundColor": "rgba(31,56,88,0.1)",
"padding": "12px 12px 12px 12px"
}
},
"children": [{
"componentName": "Box",
"id": "node_dockcy8n9xee",
"props": {
"style": {
"padding": "12px 12px 12px 12px",
"backgroundColor": "#ffffff"
}
},
"children": [{
"componentName": "Breadcrumb",
"id": "node_dockcy8n9xef",
"props": {
"prefix": "next-",
"maxNode": 100,
"component": "nav"
},
"children": [{
"componentName": "Breadcrumb.Item",
"id": "node_dockcy8n9xeg",
"props": {
"prefix": "next-"
},
"children": ["首页"]
}, {
"componentName": "Breadcrumb.Item",
"id": "node_dockcy8n9xei",
"props": {
"prefix": "next-"
},
"children": ["品质中台"]
}, {
"componentName": "Breadcrumb.Item",
"id": "node_dockcy8n9xek",
"props": {
"prefix": "next-"
},
"children": ["商家品质页面管理"]
}, {
"componentName": "Breadcrumb.Item",
"id": "node_dockcy8n9xem",
"props": {
"prefix": "next-"
},
"children": ["质检知识条配置"]
}]
}]
}, {
"componentName": "Box",
"id": "node_dockcy8n9xeo",
"props": {
"style": {
"marginTop": "12px",
"backgroundColor": "#ffffff"
}
},
"children": [{
"componentName": "Form",
"id": "node_dockcy8n9xep",
"props": {
"inline": true,
"style": {
"marginTop": "12px",
"marginRight": "12px",
"marginLeft": "12px"
},
"__events": []
},
"children": [{
"componentName": "Form.Item",
"id": "node_dockcy8n9xeq",
"props": {
"style": {
"marginBottom": "0"
},
"label": "类目名:"
},
"children": [{
"componentName": "Select",
"id": "node_dockcy8n9xer",
"props": {
"mode": "single",
"hasArrow": true,
"cacheValue": true,
"style": {
"width": "150px"
}
}
}]
}, {
"componentName": "Form.Item",
"id": "node_dockcy8n9xes",
"props": {
"style": {
"marginBottom": "0"
},
"label": "项目类型:"
},
"children": [{
"componentName": "Select",
"id": "node_dockcy8n9xet",
"props": {
"mode": "single",
"hasArrow": true,
"cacheValue": true,
"style": {
"width": "200px"
}
}
}]
}, {
"componentName": "Form.Item",
"id": "node_dockcy8n9xeu",
"props": {
"style": {
"marginBottom": "0"
},
"label": "项目 ID"
},
"children": [{
"componentName": "Input",
"id": "node_dockcy8n9xev",
"props": {
"hasBorder": true,
"size": "medium",
"autoComplete": "off",
"style": {
"width": "200px"
}
}
}]
}, {
"componentName": "Button.Group",
"id": "node_dockcy8n9xew",
"props": {},
"children": [{
"componentName": "Button",
"id": "node_dockcy8n9xex",
"props": {
"type": "primary",
"style": {
"margin": "0 5px 0 5px"
},
"htmlType": "submit"
},
"children": [{
"componentName": "Icon",
"id": "node_dockcy8n9xey",
"props": {
"type": "success"
}
}, "搜索"]
}, {
"componentName": "Button",
"id": "node_dockcy8n9xe10",
"props": {
"type": "normal",
"style": {
"margin": "0 5px 0 5px"
},
"htmlType": "reset"
},
"children": ["清空"]
}]
}]
}]
}, {
"componentName": "Box",
"id": "node_dockcy8n9xe12",
"props": {
"style": {
"justifyContent": "flex-end",
"display": "flex",
"backgroundColor": "#ffffff",
"flexDirection": "row",
"paddingRight": "24px"
}
},
"children": [{
"componentName": "Button",
"id": "node_dockcy8n9xe13",
"props": {
"prefix": "next-",
"type": "primary",
"size": "medium",
"htmlType": "button",
"component": "button",
"style": {
"width": "100px"
},
"events": {
"onClick": {
"type": "JSFunction",
"value": "function(){ this.onClick() }",
"__eventData": {
"type": "componentEvent",
"name": "onClick",
"relatedEventName": "onClick"
}
}
},
"__events": [{
"type": "componentEvent",
"name": "onClick",
"relatedEventName": "onClick"
}],
"onClick": {
"type": "JSFunction",
"value": "function(){ this.onClick() }"
}
},
"children": ["新建配置"]
}]
}, {
"componentName": "Box",
"id": "node_dockcy8n9xe15",
"props": {
"style": {
"backgroundColor": "#ffffff"
}
},
"children": [{
"componentName": "Table",
"id": "node_dockcy8n9xe16",
"props": {
"dataSource": [{
"firstCategory": "其他",
"secondCategory": "新品预览",
"leafCategory": "",
"projectType": "标识判断",
"projectId": "",
"title": "其他类目->新品预览类目类型知识库",
"url": "其他",
"operation": "编辑"
}, {
"firstCategory": "其他",
"secondCategory": "新品预览",
"leafCategory": "",
"projectType": "",
"projectId": "1",
"title": "其他类目->新品预览项目Id知识库",
"url": "其他",
"operation": "编辑"
}],
"size": "medium",
"prefix": "next-",
"hasBorder": true,
"hasHeader": true,
"isZebra": false,
"loading": false,
"expandedIndexSimulate": false,
"primaryKey": "id",
"locale": "zhCN.Table",
"crossline": false,
"style": {
"margin": "24px 12px 24px 12px"
}
},
"children": [{
"componentName": "Table.Column",
"id": "node_dockcy8n9xe17",
"props": {
"title": "一级类目",
"dataIndex": "firstCategory"
}
}, {
"componentName": "Table.Column",
"id": "node_dockcy8n9xe18",
"props": {
"title": "二级类目",
"dataIndex": "secondCategory"
}
}, {
"componentName": "Table.Column",
"id": "node_dockcy8n9xe19",
"props": {
"title": "叶子类目",
"dataIndex": "leafCategory"
}
}, {
"componentName": "Table.Column",
"id": "node_dockcy8n9xe1a",
"props": {
"title": "项目类型",
"dataIndex": "projectType"
}
}, {
"componentName": "Table.Column",
"id": "node_dockcy8n9xe1b",
"props": {
"title": "项目 ID",
"dataIndex": "projectId"
}
}, {
"componentName": "Table.Column",
"id": "node_dockcy8n9xe1c",
"props": {
"title": "知识条标题",
"dataIndex": "title"
}
}, {
"componentName": "Table.Column",
"id": "node_dockcy8n9xe1d",
"props": {
"title": "知识条链接",
"dataIndex": "url"
}
}, {
"componentName": "Table.Column",
"id": "node_dockcy8n9xe1e",
"props": {
"title": "操作",
"dataIndex": "operation"
}
}]
}]
}, {
"componentName": "Box",
"id": "node_dockcy8n9xe1f",
"props": {
"style": {
"backgroundColor": "#ffffff",
"paddingBottom": "24px"
}
},
"children": [{
"componentName": "Pagination",
"id": "node_dockcy8n9xe1g",
"props": {
"prefix": "next-",
"type": "normal",
"shape": "normal",
"size": "medium",
"defaultCurrent": 1,
"total": 100,
"pageShowCount": 5,
"pageSize": 10,
"pageSizePosition": "start",
"showJump": true,
"style": {
"display": "flex",
"justifyContent": "flex-end"
}
}
}]
}]
}, {
"componentName": "Dialog",
"id": "node_dockcy8n9xe1h",
"props": {
"prefix": "next-",
"footerAlign": "right",
"footerActions": ["ok", "cancel"],
"closeable": "esc,close",
"hasMask": true,
"align": "cc cc",
"minMargin": 40,
"visible": {
"type": "JSExpression",
"value": "this.state.isShowDialog"
},
"children": {
"type": "JSSlot"
},
"title": "标题",
"footer": {
"type": "JSSlot"
},
"events": []
}
}]
}

View File

@ -1,4 +1,4 @@
export const NATIVE_ELE_PKG: string = 'native'; export const NATIVE_ELE_PKG = 'native';
export const CONTAINER_TYPE = { export const CONTAINER_TYPE = {
COMPONENT: 'Component', COMPONENT: 'Component',

View File

@ -1,28 +1,18 @@
import { import { BuilderComponentPlugin, IChunkBuilder, ICodeChunk, ICodeStruct } from '../types';
BuilderComponentPlugin,
IChunkBuilder,
ICodeChunk,
ICodeStruct,
} from '../types';
import { COMMON_SUB_MODULE_NAME } from '../const/generator'; import { COMMON_SUB_MODULE_NAME } from '../const/generator';
export const groupChunks = (chunks: ICodeChunk[]): ICodeChunk[][] => { export const groupChunks = (chunks: ICodeChunk[]): ICodeChunk[][] => {
const col = chunks.reduce( const col = chunks.reduce((chunksSet: Record<string, ICodeChunk[]>, chunk) => {
(chunksSet: Record<string, ICodeChunk[]>, chunk) => { const fileKey = `${chunk.subModule || COMMON_SUB_MODULE_NAME}.${chunk.fileType}`;
const fileKey = `${chunk.subModule || COMMON_SUB_MODULE_NAME}.${ if (!chunksSet[fileKey]) {
chunk.fileType chunksSet[fileKey] = [];
}`; }
if (!chunksSet[fileKey]) { chunksSet[fileKey].push(chunk);
chunksSet[fileKey] = []; return chunksSet;
} }, {});
chunksSet[fileKey].push(chunk);
return chunksSet;
},
{},
);
return Object.keys(col).map(key => col[key]); return Object.keys(col).map((key) => col[key]);
}; };
/** /**
@ -39,7 +29,7 @@ export default class ChunkBuilder implements IChunkBuilder {
this.plugins = plugins; this.plugins = plugins;
} }
public async run( async run(
ir: unknown, ir: unknown,
initialStructure: ICodeStruct = { initialStructure: ICodeStruct = {
ir, ir,
@ -64,11 +54,11 @@ export default class ChunkBuilder implements IChunkBuilder {
}; };
} }
public getPlugins() { getPlugins() {
return this.plugins; return this.plugins;
} }
public addPlugin(plugin: BuilderComponentPlugin) { addPlugin(plugin: BuilderComponentPlugin) {
this.plugins.push(plugin); this.plugins.push(plugin);
} }
} }

View File

@ -1,11 +1,4 @@
import { import { ChunkContent, ChunkType, CodeGeneratorError, CodeGeneratorFunction, ICodeBuilder, ICodeChunk } from '../types';
ChunkContent,
ChunkType,
CodeGeneratorError,
CodeGeneratorFunction,
ICodeBuilder,
ICodeChunk,
} from '../types';
export default class Builder implements ICodeBuilder { export default class Builder implements ICodeBuilder {
private chunkDefinitions: ICodeChunk[] = []; private chunkDefinitions: ICodeChunk[] = [];
@ -23,13 +16,13 @@ export default class Builder implements ICodeBuilder {
* Links all chunks together based on their requirements. Returns an array * Links all chunks together based on their requirements. Returns an array
* of ordered chunk names which need to be compiled and glued together. * of ordered chunk names which need to be compiled and glued together.
*/ */
public link(chunkDefinitions: ICodeChunk[] = []): string { link(chunkDefinitions: ICodeChunk[] = []): string {
const chunks = chunkDefinitions || this.chunkDefinitions; const chunks = chunkDefinitions || this.chunkDefinitions;
if (chunks.length <= 0) { if (chunks.length <= 0) {
return ''; return '';
} }
const unprocessedChunks = chunks.map(chunk => { const unprocessedChunks = chunks.map((chunk) => {
return { return {
name: chunk.name, name: chunk.name,
type: chunk.type, type: chunk.type,
@ -50,9 +43,7 @@ export default class Builder implements ICodeBuilder {
} }
if (unprocessedChunks[indexToRemove].linkAfter.length > 0) { if (unprocessedChunks[indexToRemove].linkAfter.length > 0) {
throw new CodeGeneratorError( throw new CodeGeneratorError('Operation aborted. Reason: cyclic dependency between chunks.');
'Operation aborted. Reason: cyclic dependency between chunks.',
);
} }
const { type, content, name } = unprocessedChunks[indexToRemove]; const { type, content, name } = unprocessedChunks[indexToRemove];
@ -62,10 +53,10 @@ export default class Builder implements ICodeBuilder {
} }
unprocessedChunks.splice(indexToRemove, 1); unprocessedChunks.splice(indexToRemove, 1);
if (!unprocessedChunks.some(ch => ch.name === name)) { if (!unprocessedChunks.some((ch) => ch.name === name)) {
unprocessedChunks.forEach( unprocessedChunks.forEach(
// remove the processed chunk from all the linkAfter arrays from the remaining chunks // remove the processed chunk from all the linkAfter arrays from the remaining chunks
ch => (ch.linkAfter = ch.linkAfter.filter(after => after !== name)), (ch) => (ch.linkAfter = ch.linkAfter.filter((after) => after !== name)),
); );
} }
} }
@ -73,14 +64,12 @@ export default class Builder implements ICodeBuilder {
return resultingString.join('\n'); return resultingString.join('\n');
} }
public generateByType(type: string, content: unknown): string { generateByType(type: string, content: unknown): string {
if (!content) { if (!content) {
return ''; return '';
} }
if (Array.isArray(content)) { if (Array.isArray(content)) {
return content return content.map((contentItem) => this.generateByType(type, contentItem)).join('\n');
.map(contentItem => this.generateByType(type, contentItem))
.join('\n');
} }
if (!this.generators[type]) { if (!this.generators[type]) {
@ -95,8 +84,6 @@ export default class Builder implements ICodeBuilder {
// remove invalid chunks (which did not end up being created) from the linkAfter fields // remove invalid chunks (which did not end up being created) from the linkAfter fields
// one use-case is when you want to remove the import plugin // one use-case is when you want to remove the import plugin
private cleanupInvalidChunks(linkAfter: string[], chunks: ICodeChunk[]) { private cleanupInvalidChunks(linkAfter: string[], chunks: ICodeChunk[]) {
return linkAfter.filter(chunkName => return linkAfter.filter((chunkName) => chunks.some((chunk) => chunk.name === chunkName));
chunks.some(chunk => chunk.name === chunkName),
);
} }
} }

View File

@ -1,13 +1,12 @@
import { ProjectSchema, ResultFile, ResultDir } from '@ali/lowcode-types';
import { import {
BuilderComponentPlugin, BuilderComponentPlugin,
CodeGeneratorError, CodeGeneratorError,
IBasicSchema,
ICodeChunk, ICodeChunk,
ICompiledModule, ICompiledModule,
IModuleBuilder, IModuleBuilder,
IParseResult, IParseResult,
IResultDir,
IResultFile,
ISchemaParser, ISchemaParser,
PostProcessor, PostProcessor,
} from '../types'; } from '../types';
@ -17,9 +16,7 @@ import { COMMON_SUB_MODULE_NAME } from '../const/generator';
import SchemaParser from '../parser/SchemaParser'; import SchemaParser from '../parser/SchemaParser';
import ChunkBuilder from './ChunkBuilder'; import ChunkBuilder from './ChunkBuilder';
import CodeBuilder from './CodeBuilder'; import CodeBuilder from './CodeBuilder';
import { createResultFile, createResultDir, addFile } from '../utils/resultHelper';
import ResultDir from '../model/ResultDir';
import ResultFile from '../model/ResultFile';
export function createModuleBuilder( export function createModuleBuilder(
options: { options: {
@ -37,33 +34,27 @@ export function createModuleBuilder(
const generateModule = async (input: unknown): Promise<ICompiledModule> => { const generateModule = async (input: unknown): Promise<ICompiledModule> => {
const moduleMainName = options.mainFileName || COMMON_SUB_MODULE_NAME; const moduleMainName = options.mainFileName || COMMON_SUB_MODULE_NAME;
if (chunkGenerator.getPlugins().length <= 0) { if (chunkGenerator.getPlugins().length <= 0) {
throw new CodeGeneratorError( throw new CodeGeneratorError('No plugins found. Component generation cannot work without any plugins!');
'No plugins found. Component generation cannot work without any plugins!',
);
} }
let files: IResultFile[] = []; let files: ResultFile[] = [];
const { chunks } = await chunkGenerator.run(input); const { chunks } = await chunkGenerator.run(input);
chunks.forEach(fileChunkList => { chunks.forEach((fileChunkList) => {
const content = linker.link(fileChunkList); const content = linker.link(fileChunkList);
const file = new ResultFile( const file = createResultFile(fileChunkList[0].subModule || moduleMainName, fileChunkList[0].fileType, content);
fileChunkList[0].subModule || moduleMainName,
fileChunkList[0].fileType,
content,
);
files.push(file); files.push(file);
}); });
if (options.postProcessors.length > 0) { if (options.postProcessors.length > 0) {
files = files.map(file => { files = files.map((file) => {
let content = file.content; let content = file.content;
const type = file.ext; const type = file.ext;
options.postProcessors.forEach(processer => { options.postProcessors.forEach((processer) => {
content = processer(content, type); content = processer(content, type);
}); });
return new ResultFile(file.name, type, content); return createResultFile(file.name, type, content);
}); });
} }
@ -72,7 +63,7 @@ export function createModuleBuilder(
}; };
}; };
const generateModuleCode = async (schema: IBasicSchema | string): Promise<IResultDir> => { const generateModuleCode = async (schema: ProjectSchema | string): Promise<ResultDir> => {
// Init // Init
const schemaParser: ISchemaParser = new SchemaParser(); const schemaParser: ISchemaParser = new SchemaParser();
const parseResult: IParseResult = schemaParser.parse(schema); const parseResult: IParseResult = schemaParser.parse(schema);
@ -80,26 +71,19 @@ export function createModuleBuilder(
const containerInfo = parseResult.containers[0]; const containerInfo = parseResult.containers[0];
const { files } = await generateModule(containerInfo); const { files } = await generateModule(containerInfo);
const dir = new ResultDir(containerInfo.moduleName); const dir = createResultDir(containerInfo.moduleName);
files.forEach(file => dir.addFile(file)); files.forEach((file) => addFile(dir, file));
return dir; return dir;
} };
const linkCodeChunks = ( const linkCodeChunks = (chunks: Record<string, ICodeChunk[]>, fileName: string) => {
chunks: Record<string, ICodeChunk[]>, const files: ResultFile[] = [];
fileName: string,
) => {
const files: IResultFile[] = [];
Object.keys(chunks).forEach(fileKey => { Object.keys(chunks).forEach((fileKey) => {
const fileChunkList = chunks[fileKey]; const fileChunkList = chunks[fileKey];
const content = linker.link(fileChunkList); const content = linker.link(fileChunkList);
const file = new ResultFile( const file = createResultFile(fileChunkList[0].subModule || fileName, fileChunkList[0].fileType, content);
fileChunkList[0].subModule || fileName,
fileChunkList[0].fileType,
content,
);
files.push(file); files.push(file);
}); });

View File

@ -1,36 +1,35 @@
import { ResultDir, ResultFile, ProjectSchema } from '@ali/lowcode-types';
import { import {
IModuleBuilder, IModuleBuilder,
IParseResult, IParseResult,
IProjectBuilder, IProjectBuilder,
IProjectPlugins, IProjectPlugins,
IProjectSchema,
IProjectTemplate, IProjectTemplate,
IResultDir,
IResultFile,
ISchemaParser, ISchemaParser,
PostProcessor, PostProcessor,
} from '../types'; } from '../types';
import ResultDir from '../model/ResultDir';
import SchemaParser from '../parser/SchemaParser'; import SchemaParser from '../parser/SchemaParser';
import { createResultDir, addDirectory, addFile } from '../utils/resultHelper';
import { createModuleBuilder } from '../generator/ModuleBuilder'; import { createModuleBuilder } from '../generator/ModuleBuilder';
interface IModuleInfo { interface IModuleInfo {
moduleName?: string; moduleName?: string;
path: string[]; path: string[];
files: IResultFile[]; files: ResultFile[];
} }
function getDirFromRoot(root: IResultDir, path: string[]): IResultDir { function getDirFromRoot(root: ResultDir, path: string[]): ResultDir {
let current: IResultDir = root; let current: ResultDir = root;
path.forEach(p => { path.forEach((p) => {
const exist = current.dirs.find(d => d.name === p); const exist = current.dirs.find((d) => d.name === p);
if (exist) { if (exist) {
current = exist; current = exist;
} else { } else {
const newDir = new ResultDir(p); const newDir = createResultDir(p);
current.addDirectory(newDir); addDirectory(current, newDir);
current = newDir; current = newDir;
} }
}); });
@ -57,7 +56,7 @@ export class ProjectBuilder implements IProjectBuilder {
this.postProcessors = postProcessors; this.postProcessors = postProcessors;
} }
public async generateProject(schema: IProjectSchema | string): Promise<IResultDir> { async generateProject(schema: ProjectSchema | string): Promise<ResultDir> {
// Init // Init
const schemaParser: ISchemaParser = new SchemaParser(); const schemaParser: ISchemaParser = new SchemaParser();
const builders = this.createModuleBuilders(); const builders = this.createModuleBuilders();
@ -76,7 +75,7 @@ export class ProjectBuilder implements IProjectBuilder {
// components // components
// pages // pages
const containerBuildResult: IModuleInfo[] = await Promise.all<IModuleInfo>( const containerBuildResult: IModuleInfo[] = await Promise.all<IModuleInfo>(
parseResult.containers.map(async containerInfo => { parseResult.containers.map(async (containerInfo) => {
let builder: IModuleBuilder; let builder: IModuleBuilder;
let path: string[]; let path: string[];
if (containerInfo.containerType === 'Page') { if (containerInfo.containerType === 'Page') {
@ -100,9 +99,7 @@ export class ProjectBuilder implements IProjectBuilder {
// router // router
if (parseResult.globalRouter && builders.router) { if (parseResult.globalRouter && builders.router) {
const { files } = await builders.router.generateModule( const { files } = await builders.router.generateModule(parseResult.globalRouter);
parseResult.globalRouter,
);
buildResult.push({ buildResult.push({
path: this.template.slots.router.path, path: this.template.slots.router.path,
@ -112,9 +109,7 @@ export class ProjectBuilder implements IProjectBuilder {
// entry // entry
if (parseResult.project && builders.entry) { if (parseResult.project && builders.entry) {
const { files } = await builders.entry.generateModule( const { files } = await builders.entry.generateModule(parseResult.project);
parseResult.project,
);
buildResult.push({ buildResult.push({
path: this.template.slots.entry.path, path: this.template.slots.entry.path,
@ -124,9 +119,7 @@ export class ProjectBuilder implements IProjectBuilder {
// appConfig // appConfig
if (parseResult.project && builders.appConfig) { if (parseResult.project && builders.appConfig) {
const { files } = await builders.appConfig.generateModule( const { files } = await builders.appConfig.generateModule(parseResult.project);
parseResult.project,
);
buildResult.push({ buildResult.push({
path: this.template.slots.appConfig.path, path: this.template.slots.appConfig.path,
@ -135,14 +128,8 @@ export class ProjectBuilder implements IProjectBuilder {
} }
// constants? // constants?
if ( if (parseResult.project && builders.constants && this.template.slots.constants) {
parseResult.project && const { files } = await builders.constants.generateModule(parseResult.project);
builders.constants &&
this.template.slots.constants
) {
const { files } = await builders.constants.generateModule(
parseResult.project,
);
buildResult.push({ buildResult.push({
path: this.template.slots.constants.path, path: this.template.slots.constants.path,
@ -151,14 +138,8 @@ export class ProjectBuilder implements IProjectBuilder {
} }
// utils? // utils?
if ( if (parseResult.globalUtils && builders.utils && this.template.slots.utils) {
parseResult.globalUtils && const { files } = await builders.utils.generateModule(parseResult.globalUtils);
builders.utils &&
this.template.slots.utils
) {
const { files } = await builders.utils.generateModule(
parseResult.globalUtils,
);
buildResult.push({ buildResult.push({
path: this.template.slots.utils.path, path: this.template.slots.utils.path,
@ -168,9 +149,7 @@ export class ProjectBuilder implements IProjectBuilder {
// i18n? // i18n?
if (parseResult.globalI18n && builders.i18n && this.template.slots.i18n) { if (parseResult.globalI18n && builders.i18n && this.template.slots.i18n) {
const { files } = await builders.i18n.generateModule( const { files } = await builders.i18n.generateModule(parseResult.globalI18n);
parseResult.globalI18n,
);
buildResult.push({ buildResult.push({
path: this.template.slots.i18n.path, path: this.template.slots.i18n.path,
@ -180,9 +159,7 @@ export class ProjectBuilder implements IProjectBuilder {
// globalStyle // globalStyle
if (parseResult.project && builders.globalStyle) { if (parseResult.project && builders.globalStyle) {
const { files } = await builders.globalStyle.generateModule( const { files } = await builders.globalStyle.generateModule(parseResult.project);
parseResult.project,
);
buildResult.push({ buildResult.push({
path: this.template.slots.globalStyle.path, path: this.template.slots.globalStyle.path,
@ -192,9 +169,7 @@ export class ProjectBuilder implements IProjectBuilder {
// htmlEntry // htmlEntry
if (parseResult.project && builders.htmlEntry) { if (parseResult.project && builders.htmlEntry) {
const { files } = await builders.htmlEntry.generateModule( const { files } = await builders.htmlEntry.generateModule(parseResult.project);
parseResult.project,
);
buildResult.push({ buildResult.push({
path: this.template.slots.htmlEntry.path, path: this.template.slots.htmlEntry.path,
@ -204,9 +179,7 @@ export class ProjectBuilder implements IProjectBuilder {
// packageJSON // packageJSON
if (parseResult.project && builders.packageJSON) { if (parseResult.project && builders.packageJSON) {
const { files } = await builders.packageJSON.generateModule( const { files } = await builders.packageJSON.generateModule(parseResult.project);
parseResult.project,
);
buildResult.push({ buildResult.push({
path: this.template.slots.packageJSON.path, path: this.template.slots.packageJSON.path,
@ -217,14 +190,14 @@ export class ProjectBuilder implements IProjectBuilder {
// Post Process // Post Process
// Combine Modules // Combine Modules
buildResult.forEach(moduleInfo => { buildResult.forEach((moduleInfo) => {
let targetDir = getDirFromRoot(projectRoot, moduleInfo.path); let targetDir = getDirFromRoot(projectRoot, moduleInfo.path);
if (moduleInfo.moduleName) { if (moduleInfo.moduleName) {
const dir = new ResultDir(moduleInfo.moduleName); const dir = createResultDir(moduleInfo.moduleName);
targetDir.addDirectory(dir); addDirectory(targetDir, dir);
targetDir = dir; targetDir = dir;
} }
moduleInfo.files.forEach(file => targetDir.addFile(file)); moduleInfo.files.forEach((file) => addFile(targetDir, file));
}); });
return projectRoot; return projectRoot;
@ -233,7 +206,7 @@ export class ProjectBuilder implements IProjectBuilder {
private createModuleBuilders(): Record<string, IModuleBuilder> { private createModuleBuilders(): Record<string, IModuleBuilder> {
const builders: Record<string, IModuleBuilder> = {}; const builders: Record<string, IModuleBuilder> = {};
Object.keys(this.plugins).forEach(pluginName => { Object.keys(this.plugins).forEach((pluginName) => {
if (this.plugins[pluginName].length > 0) { if (this.plugins[pluginName].length > 0) {
const options: { mainFileName?: string } = {}; const options: { mainFileName?: string } = {};
if (this.template.slots[pluginName] && this.template.slots[pluginName].fileName) { if (this.template.slots[pluginName] && this.template.slots[pluginName].fileName) {

View File

@ -11,11 +11,7 @@ import { createZipPublisher } from './publisher/zip';
// 引入说明 // 引入说明
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';
@ -38,8 +34,11 @@ import prettier from './postprocessor/prettier';
import * as utilsCommon from './utils/common'; import * as utilsCommon from './utils/common';
import * as utilsCompositeType from './utils/compositeType'; import * as utilsCompositeType from './utils/compositeType';
import * as utilsJsExpression from './utils/jsExpression'; import * as utilsJsExpression from './utils/jsExpression';
import * as utilsJsSlot from './utils/jsSlot';
import * as utilsNodeToJSX from './utils/nodeToJSX'; import * as utilsNodeToJSX from './utils/nodeToJSX';
import * as utilsResultHelper from './utils/resultHelper';
import * as utilsTemplateHelper from './utils/templateHelper'; import * as utilsTemplateHelper from './utils/templateHelper';
import * as utilsValidate from './utils/validate';
// 引入内置解决方案模块 // 引入内置解决方案模块
import icejs from './plugins/project/framework/icejs'; import icejs from './plugins/project/framework/icejs';
@ -91,8 +90,11 @@ export default {
common: utilsCommon, common: utilsCommon,
compositeType: utilsCompositeType, compositeType: utilsCompositeType,
jsExpression: utilsJsExpression, jsExpression: utilsJsExpression,
jsSlot: utilsJsSlot,
nodeToJSX: utilsNodeToJSX, nodeToJSX: utilsNodeToJSX,
resultHelper: utilsResultHelper,
templateHelper: utilsTemplateHelper, templateHelper: utilsTemplateHelper,
validate: utilsValidate,
}, },
chunkNames: { chunkNames: {
COMMON_CHUNK_NAME, COMMON_CHUNK_NAME,

View File

@ -1,31 +0,0 @@
import { CodeGeneratorError, IResultDir, IResultFile } from '../types';
export default class ResultDir implements IResultDir {
public name: string;
public dirs: IResultDir[];
public files: IResultFile[];
constructor(name: string) {
this.name = name;
this.dirs = [];
this.files = [];
}
public addDirectory(dir: IResultDir): void {
if (this.dirs.findIndex(d => d.name === dir.name) < 0) {
this.dirs.push(dir);
} else {
throw new CodeGeneratorError(`Adding same directory to one directory: ${dir.name} -> ${this.name}`);
}
}
public addFile(file: IResultFile): void {
if (
this.files.findIndex(f => f.name === file.name && f.ext === file.ext) < 0
) {
this.files.push(file);
} else {
throw new CodeGeneratorError(`Adding same file to one directory: ${file.name} -> ${this.name}`);
}
}
}

View File

@ -1,13 +0,0 @@
import { IResultFile } from '../types';
export default class ResultFile implements IResultFile {
public name: string;
public ext: string;
public content: string;
constructor(name: string, ext: string = 'jsx', content: string = '') {
this.name = name;
this.ext = ext;
this.content = content;
}
}

View File

@ -3,28 +3,25 @@
* schema * schema
*/ */
import changeCase from 'change-case'; import changeCase from 'change-case';
import { UtilItem, NodeDataType, NodeSchema, ContainerSchema, ProjectSchema, PropsMap } from '@ali/lowcode-types';
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 { import {
NodeData,
CodeGeneratorError, CodeGeneratorError,
CompatibilityError, CompatibilityError,
DependencyType, DependencyType,
IBasicSchema,
NodeSchema,
IContainerInfo, IContainerInfo,
IContainerNodeItem,
IDependency, IDependency,
IExternalDependency, IExternalDependency,
IInternalDependency, IInternalDependency,
InternalDependencyType, InternalDependencyType,
IPageMeta,
IParseResult, IParseResult,
IProjectSchema,
ISchemaParser, ISchemaParser,
UtilItem, INpmPackage,
} from '../types'; } from '../types';
const defaultContainer: IContainerInfo = { const defaultContainer: IContainerInfo = {
@ -37,7 +34,7 @@ const defaultContainer: IContainerInfo = {
}; };
class SchemaParser implements ISchemaParser { class SchemaParser implements ISchemaParser {
public validate(schema: IBasicSchema): boolean { validate(schema: ProjectSchema): boolean {
if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) { if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) {
throw new CompatibilityError(`Not support schema with version [${schema.version}]`); throw new CompatibilityError(`Not support schema with version [${schema.version}]`);
} }
@ -45,13 +42,13 @@ class SchemaParser implements ISchemaParser {
return true; return true;
} }
public parse(schemaSrc: IProjectSchema | string): IParseResult { parse(schemaSrc: ProjectSchema | string): IParseResult {
// TODO: collect utils depends in JSExpression // TODO: collect utils depends in JSExpression
const compDeps: Record<string, IExternalDependency> = {}; const compDeps: Record<string, IExternalDependency> = {};
const internalDeps: Record<string, IInternalDependency> = {}; const internalDeps: Record<string, IInternalDependency> = {};
let utilsDeps: IExternalDependency[] = []; let utilsDeps: IExternalDependency[] = [];
let schema: IProjectSchema; let schema: ProjectSchema;
if (typeof schemaSrc === 'string') { if (typeof schemaSrc === 'string') {
try { try {
schema = JSON.parse(schemaSrc); schema = JSON.parse(schemaSrc);
@ -68,7 +65,7 @@ class SchemaParser implements ISchemaParser {
compDeps[info.componentName] = { compDeps[info.componentName] = {
...info, ...info,
dependencyType: DependencyType.External, dependencyType: DependencyType.External,
importName: info.componentName, componentName: info.componentName,
exportName: info.exportName ?? info.componentName, exportName: info.exportName ?? info.componentName,
version: info.version || '*', version: info.version || '*',
destructuring: info.destructuring ?? false, destructuring: info.destructuring ?? false,
@ -79,7 +76,7 @@ class SchemaParser implements ISchemaParser {
let containers: IContainerInfo[]; let containers: IContainerInfo[];
// Test if this is a lowcode component without container // Test if this is a lowcode component without container
if (schema.componentsTree.length > 0) { if (schema.componentsTree.length > 0) {
const firstRoot: IContainerNodeItem = schema.componentsTree[0] as IContainerNodeItem; const firstRoot: ContainerSchema = schema.componentsTree[0] as ContainerSchema;
if (!('fileName' in firstRoot) || !firstRoot.fileName) { if (!('fileName' in firstRoot) || !firstRoot.fileName) {
// 整个 schema 描述一个容器,且无根节点定义 // 整个 schema 描述一个容器,且无根节点定义
@ -91,7 +88,7 @@ class SchemaParser implements ISchemaParser {
} else { } else {
// 普通带 1 到多个容器的 schema // 普通带 1 到多个容器的 schema
containers = schema.componentsTree.map((n) => { containers = schema.componentsTree.map((n) => {
const subRoot = n; const subRoot = n as ContainerSchema;
const container: IContainerInfo = { const container: IContainerInfo = {
...subRoot, ...subRoot,
containerType: subRoot.componentName, containerType: subRoot.componentName,
@ -130,34 +127,62 @@ class SchemaParser implements ISchemaParser {
internalDeps[dep.moduleName] = dep; internalDeps[dep.moduleName] = dep;
}); });
// 分析容器内部组件依赖 const containersDeps = ([] as IDependency[]).concat(...containers.map((c) => c.deps || []));
// TODO: 不应该在出码部分解决?
// 处理 children 写在了 props 里的情况
containers.forEach((container) => { containers.forEach((container) => {
if (container.children) { if (container.children) {
// const depNames = this.getComponentNames(container.children); handleSubNodes<string>(
// container.deps = uniqueArray<string>(depNames) container.children,
// .map(depName => internalDeps[depName] || compDeps[depName]) {
// .filter(dep => !!dep); node: (i: NodeSchema) => {
container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]); if (i.props) {
if (Array.isArray(i.props)) {
// FIXME: is array type props description
} else {
const nodeProps = i.props as PropsMap;
if (nodeProps.children && !i.children) {
i.children = nodeProps.children as NodeDataType;
}
}
}
return [''];
},
},
{
rerun: true,
},
);
} }
}); });
const containersDeps = ([] as IDependency[]).concat(...containers.map((c) => c.deps || [])); // 分析容器内部组件依赖
containers.forEach((container) => {
if (container.children) {
const depNames = this.getComponentNames(container.children);
container.deps = uniqueArray<string>(depNames, (i: string) => i)
.map((depName) => internalDeps[depName] || compDeps[depName])
.filter((dep) => !!dep);
// container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]);
}
});
// 分析路由配置 // 分析路由配置
// TODO: 低代码规范里面的路由是咋弄的? // TODO: 低代码规范里面的路由是咋弄的?
const routes = containers const routes = containers
.filter((container) => container.containerType === 'Page') .filter((container) => container.containerType === 'Page')
.map((page) => { .map((page) => {
const meta = (page as { meta?: IPageMeta }).meta as IPageMeta; let router = '';
if (meta) { if (page.meta) {
return { router = (page.meta as any)?.router || '';
path: meta.router, }
componentName: page.moduleName,
}; if (!router) {
router = `/${page.fileName}`;
} }
return { return {
path: '', path: router,
componentName: page.moduleName, componentName: page.moduleName,
}; };
}); });
@ -175,6 +200,16 @@ class SchemaParser implements ISchemaParser {
utils = []; utils = [];
} }
// 分析项目 npm 依赖
let npms: INpmPackage[] = [];
containers.forEach((con) => {
const p = (con.deps || [])
.map((dep) => (dep.dependencyType === DependencyType.External ? dep : null))
.filter((dep) => dep !== null);
npms.push(...((p as unknown) as INpmPackage[]));
});
npms = uniqueArray<INpmPackage>(npms, (i) => i.package);
return { return {
containers, containers,
globalUtils: { globalUtils: {
@ -187,21 +222,26 @@ class SchemaParser implements ISchemaParser {
deps: routerDeps, deps: routerDeps,
}, },
project: { project: {
meta: schema.meta,
config: schema.config,
css: schema.css, css: schema.css,
constants: schema.constants, constants: schema.constants,
i18n: schema.i18n, i18n: schema.i18n,
containersDeps, containersDeps,
utilsDeps, utilsDeps,
packages: npms,
}, },
}; };
} }
public getComponentNames(children: NodeData | NodeData[]): string[] { getComponentNames(children: NodeDataType): string[] {
return handleChildren(children, { return handleSubNodes<string>(
node: (i: NodeSchema) => [i.componentName], children,
}); {
node: (i: NodeSchema) => [i.componentName],
},
{
rerun: true,
},
);
} }
} }

View File

@ -15,6 +15,8 @@ import {
IWithDependency, IWithDependency,
} from '../../types'; } from '../../types';
import { isValidIdentifier } from '../../utils/validate';
function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> { function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
const depMap: Record<string, IDependency[]> = {}; const depMap: Record<string, IDependency[]> = {};
@ -25,11 +27,23 @@ function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
depMap[pkg].push(dep); depMap[pkg].push(dep);
}; };
// TODO: main 这个信息到底怎么用,是不是外部包不需要使用?
// deps.forEach(dep => {
// if (dep.dependencyType === DependencyType.Internal) {
// addDep(
// `${(dep as IInternalDependency).moduleName}${`/${dep.main}` || ''}`,
// dep,
// );
// } else {
// addDep(`${(dep as IExternalDependency).package}${`/${dep.main}` || ''}`, dep);
// }
// });
deps.forEach((dep) => { deps.forEach((dep) => {
if (dep.dependencyType === DependencyType.Internal) { if (dep.dependencyType === DependencyType.Internal) {
addDep(`${(dep as IInternalDependency).moduleName}${dep.main || ''}`, dep); addDep(`${(dep as IInternalDependency).moduleName}`, dep);
} else { } else {
addDep(`${(dep as IExternalDependency).package}${dep.main || ''}`, dep); addDep(`${(dep as IExternalDependency).package}`, dep);
} }
}); });
@ -38,16 +52,13 @@ function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
function buildPackageImport(pkg: string, deps: IDependency[], targetFileType: string): ICodeChunk[] { function buildPackageImport(pkg: string, deps: IDependency[], targetFileType: string): ICodeChunk[] {
const chunks: ICodeChunk[] = []; const chunks: ICodeChunk[] = [];
let defaultImport: string = ''; let defaultImport = '';
let defaultImportAs: string = ''; let defaultImportAs = '';
const imports: Record<string, string> = {}; const imports: Record<string, string> = {};
deps.forEach((dep) => { deps.forEach((dep) => {
const srcName = dep.exportName; const srcName = dep.exportName;
let targetName = dep.importName || dep.exportName; let targetName = dep.componentName || dep.exportName;
if (dep.subName) {
return;
}
if (dep.subName) { if (dep.subName) {
chunks.push({ chunks.push({
@ -63,6 +74,20 @@ function buildPackageImport(pkg: string, deps: IDependency[], targetFileType: st
}, },
}); });
if (targetName !== `${srcName}.${dep.subName}`) {
if (!isValidIdentifier(targetName)) {
throw new CodeGeneratorError(`Invalid Identifier [${targetName}]`);
}
chunks.push({
type: ChunkType.STRING,
fileType: targetFileType,
name: COMMON_CHUNK_NAME.FileVarDefine,
content: `const ${targetName} = ${srcName}.${dep.subName};`,
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport],
});
}
targetName = srcName; targetName = srcName;
} }

View File

@ -1,12 +1,6 @@
import { COMMON_CHUNK_NAME } from '../../const/generator'; import { COMMON_CHUNK_NAME } from '../../const/generator';
import { import { BuilderComponentPlugin, BuilderComponentPluginFactory, ChunkType, FileType, ICodeStruct } from '../../types';
BuilderComponentPlugin,
BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
} from '../../types';
// TODO: How to merge this logic to common deps // TODO: How to merge this logic to common deps
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {

View File

@ -6,7 +6,6 @@ import {
ChunkType, ChunkType,
FileType, FileType,
ICodeStruct, ICodeStruct,
IContainerInfo,
} from '../../../types'; } from '../../../types';
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {

View File

@ -1,3 +1,5 @@
import { isJSExpression, isJSFunction, JSExpression, JSFunction, NpmInfo } from '@ali/lowcode-types';
import { import {
BuilderComponentPlugin, BuilderComponentPlugin,
BuilderComponentPluginFactory, BuilderComponentPluginFactory,
@ -6,11 +8,6 @@ import {
ICodeChunk, ICodeChunk,
ICodeStruct, ICodeStruct,
IContainerInfo, IContainerInfo,
isJSExpression,
isJSFunction,
JSExpression,
JSFunction,
NpmInfo,
} from '../../../types'; } from '../../../types';
import { RAX_CHUNK_NAME } from './const'; import { RAX_CHUNK_NAME } from './const';
@ -73,9 +70,9 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
}, },
[generateReactCtrlLine], [generateReactCtrlLine],
{ {
expression: (input) => (isJSExpression(input) ? handlers.expression(input) : ''), expression: (input: JSExpression) => (isJSExpression(input) ? handlers.expression(input) : ''),
function: (input) => (isJSFunction(input) ? handlers.function(input) : ''), function: (input: JSFunction) => (isJSFunction(input) ? handlers.function(input) : ''),
loopDataExpr: (input) => (typeof input === 'string' ? transformers.transformLoopExpr(input) : ''), loopDataExpr: (input: string) => (typeof input === 'string' ? transformers.transformLoopExpr(input) : ''),
tagName: mapComponentNameToAliasOrKeepIt, tagName: mapComponentNameToAliasOrKeepIt,
}, },
); );

View File

@ -60,10 +60,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
fileType: FileType.JSX, fileType: FileType.JSX,
name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,
content: '}', content: '}',
linkAfter: [ linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart, CLASS_DEFINE_CHUNK_NAME.ConstructorContent],
CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
],
}); });
next.chunks.push({ next.chunks.push({
@ -83,11 +80,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
fileType: FileType.JSX, fileType: FileType.JSX,
name: REACT_CHUNK_NAME.ClassRenderEnd, name: REACT_CHUNK_NAME.ClassRenderEnd,
content: '}', content: '}',
linkAfter: [ linkAfter: [REACT_CHUNK_NAME.ClassRenderStart, REACT_CHUNK_NAME.ClassRenderPre, REACT_CHUNK_NAME.ClassRenderJSX],
REACT_CHUNK_NAME.ClassRenderStart,
REACT_CHUNK_NAME.ClassRenderPre,
REACT_CHUNK_NAME.ClassRenderJSX,
],
}); });
next.chunks.push({ next.chunks.push({

View File

@ -13,7 +13,7 @@ import {
type PluginConfig = { type PluginConfig = {
fileType: string; fileType: string;
} };
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
const cfg: PluginConfig = { const cfg: PluginConfig = {
@ -30,9 +30,9 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
if (ir.state) { if (ir.state) {
const state = ir.state; const state = ir.state;
const fields = Object.keys(state).map<string>(stateName => { const fields = Object.keys(state).map<string>((stateName) => {
const [isString, value] = generateCompositeType(state[stateName]); const value = generateCompositeType(state[stateName]);
return `${stateName}: ${isString ? `'${value}'` : value},`; return `${stateName}: ${value},`;
}); });
next.chunks.push({ next.chunks.push({

View File

@ -14,7 +14,7 @@ import {
type PluginConfig = { type PluginConfig = {
fileType: string; fileType: string;
implementType: 'inConstructor' | 'insMember' | 'hooks'; implementType: 'inConstructor' | 'insMember' | 'hooks';
} };
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
const cfg: PluginConfig = { const cfg: PluginConfig = {
@ -32,9 +32,9 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
if (ir.state) { if (ir.state) {
const state = ir.state; const state = ir.state;
const fields = Object.keys(state).map<string>(stateName => { const fields = Object.keys(state).map<string>((stateName) => {
const [isString, value] = generateCompositeType(state[stateName]); const value = generateCompositeType(state[stateName]);
return `${stateName}: ${isString ? `'${value}'` : value},`; return `${stateName}: ${value},`;
}); });
if (cfg.implementType === 'inConstructor') { if (cfg.implementType === 'inConstructor') {

View File

@ -1,18 +1,16 @@
import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
import { REACT_CHUNK_NAME } from './const'; import { REACT_CHUNK_NAME } from './const';
import { getFuncExprBody, transformFuncExpr2MethodMember } from '../../../utils/jsExpression'; import { generateFunction } from '../../../utils/jsExpression';
import { import {
BuilderComponentPlugin, BuilderComponentPlugin,
BuilderComponentPluginFactory, BuilderComponentPluginFactory,
ChunkType, ChunkType,
CodeGeneratorError,
FileType, FileType,
ICodeChunk, ICodeChunk,
ICodeStruct, ICodeStruct,
IContainerInfo, IContainerInfo,
JSExpression,
} from '../../../types'; } from '../../../types';
type PluginConfig = { type PluginConfig = {
@ -46,7 +44,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
content: getFuncExprBody((lifeCycles[lifeCycleName] as JSExpression).value), content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }),
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]], linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]],
}; };
} }
@ -55,7 +53,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: REACT_CHUNK_NAME.ClassRenderPre, name: REACT_CHUNK_NAME.ClassRenderPre,
content: getFuncExprBody((lifeCycles[lifeCycleName] as JSExpression).value), content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }),
linkAfter: [REACT_CHUNK_NAME.ClassRenderStart], linkAfter: [REACT_CHUNK_NAME.ClassRenderStart],
}; };
} }
@ -64,12 +62,12 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsMethod, name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
content: transformFuncExpr2MethodMember(exportName, (lifeCycles[lifeCycleName] as JSExpression).value), content: generateFunction(lifeCycles[lifeCycleName], { name: exportName, isMember: true }),
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
}; };
}); });
next.chunks.push.apply(next.chunks, chunks); next.chunks.push(...chunks);
} }
return next; return next;

View File

@ -1,6 +1,6 @@
import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
import { transformFuncExpr2MethodMember } from '../../../utils/jsExpression'; import { generateFunction } from '../../../utils/jsExpression';
import { import {
BuilderComponentPlugin, BuilderComponentPlugin,
@ -10,7 +10,6 @@ import {
ICodeChunk, ICodeChunk,
ICodeStruct, ICodeStruct,
IContainerInfo, IContainerInfo,
JSExpression,
} from '../../../types'; } from '../../../types';
type PluginConfig = { type PluginConfig = {
@ -36,11 +35,11 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsMethod, name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
content: transformFuncExpr2MethodMember(methodName, (methods[methodName] as JSExpression).value), content: generateFunction(methods[methodName], { name: methodName, isMember: true }),
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
})); }));
next.chunks.push.apply(next.chunks, chunks); next.chunks.push(...chunks);
} }
return next; return next;

View File

@ -12,16 +12,18 @@ import { REACT_CHUNK_NAME } from './const';
import { createReactNodeGenerator } from '../../../utils/nodeToJSX'; import { createReactNodeGenerator } from '../../../utils/nodeToJSX';
type PluginConfig = { type PluginConfig = {
fileType: string; fileType?: string;
} nodeTypeMapping?: Record<string, string>;
};
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
const cfg: PluginConfig = { const cfg = {
fileType: FileType.JSX, fileType: FileType.JSX,
nodeTypeMapping: {},
...config, ...config,
}; };
const generator = createReactNodeGenerator(); const generator = createReactNodeGenerator({ nodeTypeMapping: cfg.nodeTypeMapping });
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
const next: ICodeStruct = { const next: ICodeStruct = {
@ -36,10 +38,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
fileType: cfg.fileType, fileType: cfg.fileType,
name: REACT_CHUNK_NAME.ClassRenderJSX, name: REACT_CHUNK_NAME.ClassRenderJSX,
content: `return ${jsxContent};`, content: `return ${jsxContent};`,
linkAfter: [ linkAfter: [REACT_CHUNK_NAME.ClassRenderStart, REACT_CHUNK_NAME.ClassRenderPre],
REACT_CHUNK_NAME.ClassRenderStart,
REACT_CHUNK_NAME.ClassRenderPre,
],
}); });
return next; return next;

View File

@ -1,3 +0,0 @@
export const RECORE_CHUNK_NAME = {
};

View File

@ -1,3 +1,5 @@
import { JSExpression, CompositeValue } from '@ali/lowcode-types';
import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
import { import {
@ -7,15 +9,14 @@ import {
FileType, FileType,
ICodeStruct, ICodeStruct,
IContainerInfo, IContainerInfo,
CompositeValue,
JSExpression,
} from '../../../types'; } from '../../../types';
import { generateCompositeType, handleStringValueDefault } from '../../../utils/compositeType'; import { generateCompositeType } from '../../../utils/compositeType';
import { generateExpression } from '../../../utils/jsExpression'; import { generateExpression } from '../../../utils/jsExpression';
function packJsExpression(exp: JSExpression): string { function packJsExpression(exp: unknown): string {
const funcStr = generateExpression(exp); const expression = exp as JSExpression;
const funcStr = generateExpression(expression);
return `function() { return (${funcStr}); }`; return `function() { return (${funcStr}); }`;
} }
@ -40,11 +41,11 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
attrs = [...attrs, ...extConfigs]; attrs = [...attrs, ...extConfigs];
const listProp = handleStringValueDefault( const listProp = generateCompositeType((list as unknown) as CompositeValue, {
generateCompositeType((list as unknown) as CompositeValue, { handlers: {
expression: packJsExpression, expression: packJsExpression,
}), },
); });
attrs.push(`list: ${listProp}`); attrs.push(`list: ${listProp}`);

View File

@ -22,7 +22,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: FileType.TS, fileType: FileType.TS,
name: CLASS_DEFINE_CHUNK_NAME.StaticVar, name: CLASS_DEFINE_CHUNK_NAME.StaticVar,
content: `static cssText = '${ir.css.replace(/\'/g, '\\\'')}';`, content: `static cssText = '${ir.css.replace(/'/g, "\\'")}';`,
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.StaticVar]], linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.StaticVar]],
}); });
} }

View File

@ -1,20 +1,22 @@
import { NodeSchema } from '@ali/lowcode-types';
import { import {
BuilderComponentPlugin, BuilderComponentPlugin,
BuilderComponentPluginFactory, BuilderComponentPluginFactory,
ChunkType, ChunkType,
ICodeStruct, ICodeStruct,
IContainerInfo, IContainerInfo,
NodeSchema, 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 } from '../../../utils/compositeType';
const generateGlobalProps = (nodeItem: NodeSchema): CodePiece[] => { const generateGlobalProps = (ctx: INodeGeneratorContext, nodeItem: NodeSchema): CodePiece[] => {
return [ return [
{ {
value: `{...globalProps.${nodeItem.componentName}}`, value: `{...globalProps.${nodeItem.componentName}}`,
@ -23,11 +25,11 @@ const generateGlobalProps = (nodeItem: NodeSchema): CodePiece[] => {
]; ];
}; };
const generateCtrlLine = (nodeItem: NodeSchema): CodePiece[] => { const generateCtrlLine = (ctx: INodeGeneratorContext, nodeItem: NodeSchema): CodePiece[] => {
const pieces: CodePiece[] = []; const pieces: CodePiece[] = [];
if (nodeItem.loop && nodeItem.loopArgs) { if (nodeItem.loop && nodeItem.loopArgs) {
const loopDataExp = handleStringValueDefault(generateCompositeType(nodeItem.loop)); const loopDataExp = generateCompositeType(nodeItem.loop);
pieces.push({ pieces.push({
type: PIECE_TYPE.ATTR, type: PIECE_TYPE.ATTR,
value: `x-for={${loopDataExp}}`, value: `x-for={${loopDataExp}}`,
@ -40,7 +42,7 @@ const generateCtrlLine = (nodeItem: NodeSchema): CodePiece[] => {
} }
if (nodeItem.condition) { if (nodeItem.condition) {
const conditionExp = handleStringValueDefault(generateCompositeType(nodeItem.condition)); const conditionExp = generateCompositeType(nodeItem.condition);
pieces.push({ pieces.push({
type: PIECE_TYPE.ATTR, type: PIECE_TYPE.ATTR,
value: `x-if={${conditionExp}}`, value: `x-if={${conditionExp}}`,

View File

@ -1,11 +1,6 @@
import { COMMON_CHUNK_NAME } from '../../../const/generator'; import { COMMON_CHUNK_NAME } from '../../../const/generator';
import { import { BuilderComponentPlugin, BuilderComponentPluginFactory, ChunkType, ICodeStruct } from '../../../types';
BuilderComponentPlugin,
BuilderComponentPluginFactory,
ChunkType,
ICodeStruct,
} from '../../../types';
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {

View File

@ -12,7 +12,7 @@ import {
type PluginConfig = { type PluginConfig = {
fileType: string; fileType: string;
moduleFileType: string; moduleFileType: string;
} };
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
const cfg: PluginConfig = { const cfg: PluginConfig = {

View File

@ -17,7 +17,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
const ir = next.ir as IProjectInfo; const ir = next.ir as IProjectInfo;
if (ir.constants) { if (ir.constants) {
const [, constantStr] = generateCompositeType(ir.constants); const constantStr = generateCompositeType(ir.constants);
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,

View File

@ -6,7 +6,6 @@ import {
ChunkType, ChunkType,
FileType, FileType,
ICodeStruct, ICodeStruct,
IProjectInfo,
} from '../../../../../types'; } from '../../../../../types';
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
@ -15,8 +14,6 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
...pre, ...pre,
}; };
const ir = next.ir as IProjectInfo;
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: FileType.JS, fileType: FileType.JS,
@ -34,10 +31,10 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
content: ` content: `
const appConfig = { const appConfig = {
app: { app: {
rootId: '${ir.config.targetRootID}', rootId: 'app',
}, },
router: { router: {
type: '${ir.config.historyMode}', type: 'hash',
}, },
}; };
createApp(appConfig); createApp(appConfig);

View File

@ -31,7 +31,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
<title>${ir.meta.name}</title> <title>${ir.meta.name}</title>
</head> </head>
<body> <body>
<div id="${ir.config.targetRootID}"></div> <div id="app"></div>
</body> </body>
</html> </html>
`, `,

View File

@ -1,3 +1,5 @@
import { PackageJSON } from '@ali/lowcode-types';
import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
import { import {
@ -6,11 +8,10 @@ import {
ChunkType, ChunkType,
FileType, FileType,
ICodeStruct, ICodeStruct,
IPackageJSON,
IProjectInfo, IProjectInfo,
} from '../../../../../types'; } from '../../../../../types';
interface IIceJsPackageJSON extends IPackageJSON { interface IIceJsPackageJSON extends PackageJSON {
ideMode: { ideMode: {
name: string; name: string;
}; };
@ -73,6 +74,8 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
originTemplate: '@alifd/scaffold-lite-js', originTemplate: '@alifd/scaffold-lite-js',
}; };
ir.packages.forEach((packageInfo) => (packageJson.dependencies[packageInfo.package] = packageInfo.version));
next.chunks.push({ next.chunks.push({
type: ChunkType.JSON, type: ChunkType.JSON,
fileType: FileType.JSON, fileType: FileType.JSON,

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'README', 'README',
'md', 'md',
` `

View File

@ -1,17 +1,17 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( return [
'abc', [],
'json', {
` name: 'abc',
ext: 'json',
content: `
{ {
"type": "ice-app", "type": "ice-app",
"builder": "@ali/builder-ice-app" "builder": "@ali/builder-ice-app"
} }
`, `,
); },
];
return [[], file];
} }

View File

@ -1,11 +1,12 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( return [
'build', [],
'json', {
` name: 'build',
ext: 'json',
content: `
{ {
"entry": "src/app.js", "entry": "src/app.js",
"plugins": [ "plugins": [
@ -26,8 +27,7 @@ export default function getFile(): [string[], IResultFile] {
"@ali/build-plugin-ice-def" "@ali/build-plugin-ice-def"
] ]
} }
`, `,
); },
];
return [[], file];
} }

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.editorconfig', '.editorconfig',
'', '',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.eslintignore', '.eslintignore',
'', '',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.eslintrc', '.eslintrc',
'js', 'js',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.gitignore', '.gitignore',
'', '',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'jsconfig', 'jsconfig',
'json', 'json',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.prettierignore', '.prettierignore',
'', '',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.prettierrc', '.prettierrc',
'js', 'js',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../../../../../../types'; import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'index', 'index',
'jsx', 'jsx',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../../../../../../types'; import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'index', 'index',
'module.scss', 'module.scss',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../../../../../../types'; import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'index', 'index',
'jsx', 'jsx',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../../../../../../types'; import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'index', 'index',
'module.scss', 'module.scss',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../../../../../../types'; import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'index', 'index',
'jsx', 'jsx',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../../../../types'; import { createResultFile } from '../../../../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'index', 'index',
'jsx', 'jsx',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../../../../types'; import { createResultFile } from '../../../../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'menuConfig', 'menuConfig',
'js', 'js',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.stylelintignore', '.stylelintignore',
'', '',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.stylelintrc', '.stylelintrc',
'js', 'js',
` `

View File

@ -1,8 +1,8 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'tsconfig', 'tsconfig',
'json', 'json',
` `

View File

@ -1,8 +1,7 @@
import ResultDir from '../../../../../model/ResultDir'; import { ResultDir } from '@ali/lowcode-types';
import { import { IProjectTemplate } from '../../../../../types';
IProjectTemplate,
IResultDir, import { createResultDir } from '../../../../../utils/resultHelper';
} from '../../../../../types';
import { runFileGenerator } from '../../../../../utils/templateHelper'; import { runFileGenerator } from '../../../../../utils/templateHelper';
import file12 from './files/abc.json'; import file12 from './files/abc.json';
@ -68,8 +67,8 @@ const icejsTemplate: IProjectTemplate = {
}, },
}, },
generateTemplate(): IResultDir { generateTemplate(): ResultDir {
const root = new ResultDir('.'); const root = createResultDir('.');
runFileGenerator(root, file1); runFileGenerator(root, file1);
runFileGenerator(root, file2); runFileGenerator(root, file2);

View File

@ -1,4 +1,4 @@
import { NpmInfo } from '@ali/lowcode-types'; import { NpmInfo, PackageJSON } from '@ali/lowcode-types';
import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
import { import {
@ -7,7 +7,6 @@ import {
ChunkType, ChunkType,
FileType, FileType,
ICodeStruct, ICodeStruct,
IPackageJSON,
IProjectInfo, IProjectInfo,
} from '../../../../../types'; } from '../../../../../types';
import { isNpmInfo } from '../../../../../utils/schema'; import { isNpmInfo } from '../../../../../utils/schema';
@ -23,7 +22,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
const npmDeps = getNpmDependencies(ir); const npmDeps = getNpmDependencies(ir);
const packageJson: IPackageJSON = { const packageJson: PackageJSON = {
name: '@ali/rax-app-demo', name: '@ali/rax-app-demo',
private: true, private: true,
version: '1.0.0', version: '1.0.0',

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'.editorconfig', '.editorconfig',
'', '',
` `
@ -29,4 +28,3 @@ trim_trailing_whitespace = false
return [[], file]; return [[], file];
} }

View File

@ -1,9 +1,9 @@
import ResultFile from '../../../../../../model/ResultFile'; import { ResultFile } from '@ali/lowcode-types';
import { IResultFile } from '../../../../../../types'; import { createResultFile } from '../../../../../../utils/resultHelper';
export default function getFile(): [string[], IResultFile] { export default function getFile(): [string[], ResultFile] {
const file = new ResultFile( const file = createResultFile(
'.eslintignore', '.eslintignore',
'', '',
` `
@ -23,4 +23,3 @@ packages/solution
return [[], file]; return [[], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'.gitignore', '.gitignore',
'', '',
` `
@ -54,4 +53,3 @@ Thumbs.db
return [[], file]; return [[], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'.prettierrc', '.prettierrc',
'', '',
` `
@ -19,4 +18,3 @@ export default function getFile(): [string[], IResultFile] {
return [[], file]; return [[], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'README', 'README',
'md', 'md',
` `

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'abc', 'abc',
'json', 'json',
` `
@ -25,4 +24,3 @@ export default function getFile(): [string[], IResultFile] {
return [[], file]; return [[], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'build', 'build',
'json', 'json',
` `
@ -29,4 +28,3 @@ export default function getFile(): [string[], IResultFile] {
return [[], file]; return [[], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'package', 'package',
'json', 'json',
` `
@ -63,4 +62,3 @@ export default function getFile(): [string[], IResultFile] {
return [[], file]; return [[], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'index', 'index',
'html', 'html',
` `
@ -48,4 +47,3 @@ export default function getFile(): [string[], IResultFile] {
return [['public'], file]; return [['public'], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'app', 'app',
'ts', 'ts',
` `
@ -72,6 +71,5 @@ export default {
`, `,
); );
return [['src','config'], file]; return [['src', 'config'], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'components', 'components',
'ts', 'ts',
` `
@ -38,6 +37,5 @@ export default componentsMap;
`, `,
); );
return [['src','config'], file]; return [['src', 'config'], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'utils', 'utils',
'ts', 'ts',
` `
@ -24,6 +23,5 @@ export default {
`, `,
); );
return [['src','config'], file]; return [['src', 'config'], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'index', 'index',
'ts', 'ts',
` `
@ -98,4 +97,3 @@ app.run();
return [['src'], file]; return [['src'], file];
} }

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'router', 'router',
'ts', 'ts',
` `

View File

@ -1,9 +1,8 @@
import { ResultFile } from '@ali/lowcode-types';
import { createResultFile } from '../../../../../../utils/resultHelper';
import ResultFile from '../../../../../../model/ResultFile'; export default function getFile(): [string[], ResultFile] {
import { IResultFile } from '../../../../../../types'; const file = createResultFile(
export default function getFile(): [string[], IResultFile] {
const file = new ResultFile(
'tsconfig', 'tsconfig',
'json', 'json',
` `
@ -50,4 +49,3 @@ export default function getFile(): [string[], IResultFile] {
return [[], file]; return [[], file];
} }

View File

@ -1,8 +1,6 @@
import ResultDir from '../../../../../model/ResultDir'; import { ResultDir } from '@ali/lowcode-types';
import { import { IProjectTemplate } from '../../../../../types';
IProjectTemplate, import { createResultDir } from '../../../../../utils/resultHelper';
IResultDir,
} from '../../../../../types';
import { runFileGenerator } from '../../../../../utils/templateHelper'; import { runFileGenerator } from '../../../../../utils/templateHelper';
import file1 from './files/abc.json'; import file1 from './files/abc.json';
@ -28,8 +26,8 @@ const icejsTemplate: IProjectTemplate = {
}, },
}, },
generateTemplate(): IResultDir { generateTemplate(): ResultDir {
const root = new ResultDir('.'); const root = createResultDir('.');
runFileGenerator(root, file1); runFileGenerator(root, file1);
runFileGenerator(root, file2); runFileGenerator(root, file2);

View File

@ -17,7 +17,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
const ir = next.ir as IProjectInfo; const ir = next.ir as IProjectInfo;
if (ir.i18n) { if (ir.i18n) {
const [, i18nStr] = generateCompositeType(ir.i18n, {}); const i18nStr = generateCompositeType(ir.i18n);
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,

View File

@ -1,10 +1,5 @@
import { import { ResultDir } from '@ali/lowcode-types';
IResultDir, import { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types';
PublisherFactory,
IPublisher,
IPublisherFactoryParams,
PublisherError,
} from '../../types';
import { writeFolder } from './utils'; import { writeFolder } from './utils';
export interface IDiskFactoryParams extends IPublisherFactoryParams { export interface IDiskFactoryParams extends IPublisherFactoryParams {
@ -18,19 +13,18 @@ export interface IDiskPublisher extends IPublisher<IDiskFactoryParams, string> {
setOutputPath: (path: string) => void; setOutputPath: (path: string) => void;
} }
export const createDiskPublisher: PublisherFactory< export const createDiskPublisher: PublisherFactory<IDiskFactoryParams, IDiskPublisher> = (
IDiskFactoryParams, params: IDiskFactoryParams = {},
IDiskPublisher ): IDiskPublisher => {
> = (params: IDiskFactoryParams = {}): IDiskPublisher => {
let { project, outputPath = './' } = params; let { project, outputPath = './' } = params;
const getProject = (): IResultDir => { const getProject = (): ResultDir => {
if (!project) { if (!project) {
throw new PublisherError('Missing Project'); throw new PublisherError('Missing Project');
} }
return project; return project;
}; };
const setProject = (projectToSet: IResultDir): void => { const setProject = (projectToSet: ResultDir): void => {
project = projectToSet; project = projectToSet;
}; };
@ -49,19 +43,14 @@ export const createDiskPublisher: PublisherFactory<
const projectOutputPath = options.outputPath || outputPath; const projectOutputPath = options.outputPath || outputPath;
const overrideProjectSlug = options.projectSlug || params.projectSlug; const overrideProjectSlug = options.projectSlug || params.projectSlug;
const createProjectFolder = const createProjectFolder = options.createProjectFolder || params.createProjectFolder;
options.createProjectFolder || params.createProjectFolder;
if (overrideProjectSlug) { if (overrideProjectSlug) {
projectToPublish.name = overrideProjectSlug; projectToPublish.name = overrideProjectSlug;
} }
try { try {
await writeFolder( await writeFolder(projectToPublish, projectOutputPath, createProjectFolder);
projectToPublish,
projectOutputPath,
createProjectFolder,
);
return { success: true, payload: projectOutputPath }; return { success: true, payload: projectOutputPath };
} catch (error) { } catch (error) {
throw new PublisherError(error); throw new PublisherError(error);

View File

@ -1,36 +1,27 @@
import { existsSync, mkdir, writeFile } from 'fs'; import { existsSync, mkdir, writeFile } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ResultDir, ResultFile } from '@ali/lowcode-types';
import { IResultDir, IResultFile } from '../../types';
export const writeFolder = async ( export const writeFolder = async (
folder: IResultDir, folder: ResultDir,
currentPath: string, currentPath: string,
createProjectFolder = true, createProjectFolder = true,
): Promise<void> => { ): Promise<void> => {
const { name, files, dirs } = folder; const { name, files, dirs } = folder;
const folderPath = createProjectFolder const folderPath = createProjectFolder ? join(currentPath, name) : currentPath;
? join(currentPath, name)
: currentPath;
if (!existsSync(folderPath)) { if (!existsSync(folderPath)) {
await createDirectory(folderPath); await createDirectory(folderPath);
} }
const promises = [ const promises = [writeFilesToFolder(folderPath, files), writeSubFoldersToFolder(folderPath, dirs)];
writeFilesToFolder(folderPath, files),
writeSubFoldersToFolder(folderPath, dirs),
];
await Promise.all(promises); await Promise.all(promises);
}; };
const writeFilesToFolder = async ( const writeFilesToFolder = async (folderPath: string, files: ResultFile[]): Promise<void> => {
folderPath: string, const promises = files.map((file) => {
files: IResultFile[],
): Promise<void> => {
const promises = files.map(file => {
const fileName = file.ext ? `${file.name}.${file.ext}` : file.name; const fileName = file.ext ? `${file.name}.${file.ext}` : file.name;
const filePath = join(folderPath, fileName); const filePath = join(folderPath, fileName);
return writeContentToFile(filePath, file.content); return writeContentToFile(filePath, file.content);
@ -39,11 +30,8 @@ const writeFilesToFolder = async (
await Promise.all(promises); await Promise.all(promises);
}; };
const writeSubFoldersToFolder = async ( const writeSubFoldersToFolder = async (folderPath: string, subFolders: ResultDir[]): Promise<void> => {
folderPath: string, const promises = subFolders.map((subFolder) => {
subFolders: IResultDir[],
): Promise<void> => {
const promises = subFolders.map(subFolder => {
return writeFolder(subFolder, folderPath); return writeFolder(subFolder, folderPath);
}); });
@ -52,19 +40,15 @@ const writeSubFoldersToFolder = async (
const createDirectory = (pathToDir: string): Promise<void> => { const createDirectory = (pathToDir: string): Promise<void> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
mkdir(pathToDir, { recursive: true }, err => { mkdir(pathToDir, { recursive: true }, (err) => {
err ? reject(err) : resolve(); err ? reject(err) : resolve();
}); });
}); });
}; };
const writeContentToFile = ( const writeContentToFile = (filePath: string, fileContent: string, encoding = 'utf8'): Promise<void> => {
filePath: string,
fileContent: string,
encoding: string = 'utf8',
): Promise<void> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
writeFile(filePath, fileContent, encoding, err => { writeFile(filePath, fileContent, encoding, (err) => {
err ? reject(err) : resolve(); err ? reject(err) : resolve();
}); });
}); });

View File

@ -1,11 +1,6 @@
import { import { ResultDir } from '@ali/lowcode-types';
IResultDir, import { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types';
PublisherFactory, import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils';
IPublisher,
IPublisherFactoryParams,
PublisherError,
} from '../../types';
import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils'
// export type ZipBuffer = Buffer | Blob; // export type ZipBuffer = Buffer | Blob;
export type ZipBuffer = Buffer; export type ZipBuffer = Buffer;
@ -28,14 +23,14 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher
let { project, outputPath } = params; let { project, outputPath } = params;
const getProject = () => project; const getProject = () => project;
const setProject = (projectToSet: IResultDir) => { const setProject = (projectToSet: ResultDir) => {
project = projectToSet; project = projectToSet;
} };
const getOutputPath = () => outputPath; const getOutputPath = () => outputPath;
const setOutputPath = (path: string) => { const setOutputPath = (path: string) => {
outputPath = path; outputPath = path;
} };
const publish = async (options: ZipFactoryParams = {}) => { const publish = async (options: ZipFactoryParams = {}) => {
const projectToPublish = options.project || project; const projectToPublish = options.project || project;
@ -57,7 +52,7 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher
} catch (error) { } catch (error) {
throw new PublisherError(error); throw new PublisherError(error);
} }
} };
return { return {
publish, publish,
@ -66,4 +61,4 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher
getOutputPath, getOutputPath,
setOutputPath, setOutputPath,
}; };
} };

View File

@ -1,21 +1,17 @@
import JSZip from 'jszip'; import JSZip from 'jszip';
import { IResultDir, IResultFile } from '../../types'; import { ResultDir, ResultFile } from '@ali/lowcode-types';
import { ZipBuffer } from './index'; import { ZipBuffer } from './index';
export const isNodeProcess = (): boolean => { export const isNodeProcess = (): boolean => {
return ( return (
typeof process === 'object' && typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node !== 'undefined'
typeof process.versions === 'object' &&
typeof process.versions.node !== 'undefined'
); );
} };
export const writeZipToDisk = ( export const writeZipToDisk = (zipFolderPath: string, content: ZipBuffer, zipName: string): void => {
zipFolderPath: string, // eslint-disable-next-line @typescript-eslint/no-var-requires
content: ZipBuffer,
zipName: string,
): void => {
const fs = require('fs'); const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path'); const path = require('path');
if (!fs.existsSync(zipFolderPath)) { if (!fs.existsSync(zipFolderPath)) {
@ -27,34 +23,30 @@ export const writeZipToDisk = (
const writeStream = fs.createWriteStream(zipPath); const writeStream = fs.createWriteStream(zipPath);
writeStream.write(content); writeStream.write(content);
writeStream.end(); writeStream.end();
} };
export const generateProjectZip = async (project: IResultDir): Promise<ZipBuffer> => { export const generateProjectZip = async (project: ResultDir): Promise<ZipBuffer> => {
let zip = new JSZip(); let zip = new JSZip();
zip = writeFolderToZip(project, zip, true); zip = writeFolderToZip(project, zip, true);
// const zipType = isNodeProcess() ? 'nodebuffer' : 'blob'; // const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';
const zipType = 'nodebuffer'; // 目前先只支持 node 调用 const zipType = 'nodebuffer'; // 目前先只支持 node 调用
return zip.generateAsync({ type: zipType }); return zip.generateAsync({ type: zipType });
} };
const writeFolderToZip = ( const writeFolderToZip = (folder: ResultDir, parentFolder: JSZip, ignoreFolder = false) => {
folder: IResultDir,
parentFolder: JSZip,
ignoreFolder: boolean = false,
) => {
const zipFolder = ignoreFolder ? parentFolder : parentFolder.folder(folder.name); const zipFolder = ignoreFolder ? parentFolder : parentFolder.folder(folder.name);
if (zipFolder !== null) { if (zipFolder !== null) {
folder.files.forEach((file: IResultFile) => { folder.files.forEach((file: ResultFile) => {
// const options = file.contentEncoding === 'base64' ? { base64: true } : {}; // const options = file.contentEncoding === 'base64' ? { base64: true } : {};
const options = {}; const options = {};
const fileName = file.ext ? `${file.name}.${file.ext}` : file.name; const fileName = file.ext ? `${file.name}.${file.ext}` : file.name;
zipFolder.file(fileName, file.content, options); zipFolder.file(fileName, file.content, options);
}); });
folder.dirs.forEach((subFolder: IResultDir) => { folder.dirs.forEach((subFolder: ResultDir) => {
writeFolderToZip(subFolder, zipFolder); writeFolderToZip(subFolder, zipFolder);
}); });
} }
return parentFolder; return parentFolder;
} };

View File

@ -5,7 +5,7 @@ import { createProjectBuilder } from '../generator/ProjectBuilder';
import esmodule from '../plugins/common/esmodule'; import esmodule from '../plugins/common/esmodule';
import containerClass from '../plugins/component/react/containerClass'; import containerClass from '../plugins/component/react/containerClass';
import containerInitState from '../plugins/component/react/containerInitState'; import containerInitState from '../plugins/component/react/containerInitState';
import containerInjectUtils from '../plugins/component/react/containerInjectUtils'; // import containerInjectUtils from '../plugins/component/react/containerInjectUtils';
import containerLifeCycle from '../plugins/component/react/containerLifeCycle'; import containerLifeCycle from '../plugins/component/react/containerLifeCycle';
import containerMethod from '../plugins/component/react/containerMethod'; import containerMethod from '../plugins/component/react/containerMethod';
import jsx from '../plugins/component/react/jsx'; import jsx from '../plugins/component/react/jsx';
@ -29,11 +29,18 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
fileType: 'jsx', fileType: 'jsx',
}), }),
containerClass(), containerClass(),
containerInjectUtils(), // containerInjectUtils(),
containerInitState(), containerInitState(),
containerLifeCycle(), containerLifeCycle(),
containerMethod(), containerMethod(),
jsx(), jsx({
nodeTypeMapping: {
Div: 'div',
Component: 'div',
Page: 'div',
Block: 'div',
},
}),
css(), css(),
], ],
pages: [ pages: [
@ -42,11 +49,19 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
fileType: 'jsx', fileType: 'jsx',
}), }),
containerClass(), containerClass(),
containerInjectUtils(), // containerInjectUtils(),
containerInitState(), containerInitState(),
containerLifeCycle(), containerLifeCycle(),
containerMethod(), containerMethod(),
jsx(), jsx({
nodeTypeMapping: {
Div: 'div',
Component: 'div',
Page: 'div',
Block: 'div',
// Box: 'div',
},
}),
css(), css(),
], ],
router: [esmodule(), icejs.plugins.router()], router: [esmodule(), icejs.plugins.router()],
@ -58,6 +73,6 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
htmlEntry: [icejs.plugins.entryHtml()], htmlEntry: [icejs.plugins.entryHtml()],
packageJSON: [icejs.plugins.packageJSON()], packageJSON: [icejs.plugins.packageJSON()],
}, },
postProcessors: [prettier()], postProcessors: [prettier()], // prettier()
}); });
} }

View File

@ -1,9 +1,19 @@
import { JSExpression, JSFunction, NodeSchema } from '@ali/lowcode-types'; import {
ResultDir,
ResultFile,
NodeData,
NodeSchema,
ProjectSchema,
JSExpression,
JSFunction,
CompositeArray,
CompositeObject,
JSONArray,
JSONObject,
JSSlot,
} from '@ali/lowcode-types';
import { CustomHandlerSet } from '../utils/compositeType';
import { IParseResult } from './intermediate'; import { IParseResult } from './intermediate';
import { IResultDir, IResultFile } from './result';
import { IBasicSchema, IProjectSchema } from './schema';
export enum FileType { export enum FileType {
CSS = 'css', CSS = 'css',
@ -68,13 +78,13 @@ export interface ICodeBuilder {
} }
export interface ICompiledModule { export interface ICompiledModule {
files: IResultFile[]; files: ResultFile[];
} }
export interface IModuleBuilder { export interface IModuleBuilder {
generateModule(input: unknown): Promise<ICompiledModule>; generateModule(input: unknown): Promise<ICompiledModule>;
generateModuleCode(schema: IBasicSchema | string): Promise<IResultDir>; generateModuleCode(schema: ProjectSchema | string): Promise<ResultDir>;
linkCodeChunks(chunks: Record<string, ICodeChunk[]>, fileName: string): IResultFile[]; linkCodeChunks(chunks: Record<string, ICodeChunk[]>, fileName: string): ResultFile[];
addPlugin(plugin: BuilderComponentPlugin): void; addPlugin(plugin: BuilderComponentPlugin): void;
} }
@ -88,21 +98,21 @@ export interface ICodeGenerator {
/** /**
* Schema * Schema
* *
* @param {(IBasicSchema)} schema Schema * @param {(ProjectSchema)} schema Schema
* @returns {IResultDir} * @returns {ResultDir}
* @memberof ICodeGenerator * @memberof ICodeGenerator
*/ */
toCode(schema: IBasicSchema): Promise<IResultDir>; toCode(schema: ProjectSchema): Promise<ResultDir>;
} }
export interface ISchemaParser { export interface ISchemaParser {
validate(schema: IBasicSchema): boolean; validate(schema: ProjectSchema): boolean;
parse(schema: IBasicSchema | string): IParseResult; parse(schema: ProjectSchema | string): IParseResult;
} }
export interface IProjectTemplate { export interface IProjectTemplate {
slots: Record<string, IProjectSlot>; slots: Record<string, IProjectSlot>;
generateTemplate(): IResultDir; generateTemplate(): ResultDir;
} }
export interface IProjectSlot { export interface IProjectSlot {
@ -110,25 +120,12 @@ export interface IProjectSlot {
fileName?: string; fileName?: string;
} }
// export interface IProjectSlots {
// components: IProjectSlot;
// pages: IProjectSlot;
// router: IProjectSlot;
// entry: IProjectSlot;
// constants?: IProjectSlot;
// utils?: IProjectSlot;
// i18n?: IProjectSlot;
// globalStyle: IProjectSlot;
// htmlEntry: IProjectSlot;
// packageJSON: IProjectSlot;
// }
export interface IProjectPlugins { export interface IProjectPlugins {
[slotName: string]: BuilderComponentPlugin[]; [slotName: string]: BuilderComponentPlugin[];
} }
export interface IProjectBuilder { export interface IProjectBuilder {
generateProject(schema: IProjectSchema | string): Promise<IResultDir>; generateProject(schema: ProjectSchema | string): Promise<ResultDir>;
} }
export type PostProcessorFactory<T> = (config?: T) => PostProcessor; export type PostProcessorFactory<T> = (config?: T) => PostProcessor;
@ -161,10 +158,41 @@ export interface HandlerSet<T> {
common?: (input: unknown) => T[]; common?: (input: unknown) => T[];
} }
export type ExtGeneratorPlugin = (nodeItem: NodeSchema, handlers: CustomHandlerSet) => CodePiece[]; export type ExtGeneratorPlugin = (
ctx: INodeGeneratorContext,
nodeItem: NodeSchema,
handlers: CustomHandlerSet,
) => CodePiece[];
// export interface InteratorScope { export interface INodeGeneratorConfig {
// [$item: string]: string; // $item 默认取值 "item" nodeTypeMapping?: Record<string, string>;
// [$index: string]: string | number; // $index 默认取值 "index" }
// __proto__: BlockInstance;
// } export type NodeGenerator = (nodeItem: NodeData) => string;
export interface INodeGeneratorContext {
generator: NodeGenerator;
}
export type CompositeValueCustomHandler = (data: unknown) => string;
export type CompositeTypeContainerHandler = (value: string) => string;
export interface CompositeValueCustomHandlerSet {
boolean?: CompositeValueCustomHandler;
number?: CompositeValueCustomHandler;
string?: CompositeValueCustomHandler;
array?: CompositeValueCustomHandler;
object?: CompositeValueCustomHandler;
expression?: CompositeValueCustomHandler;
function?: CompositeValueCustomHandler;
}
export interface CompositeTypeContainerHandlerSet {
default?: CompositeTypeContainerHandler;
string?: CompositeTypeContainerHandler;
}
export type CompositeValueGeneratorOptions = {
handlers?: CompositeValueCustomHandlerSet;
containerHandlers?: CompositeTypeContainerHandlerSet;
nodeGenerator?: NodeGenerator;
};

View File

@ -1,13 +1,15 @@
export interface INpmPackage {
package: string; // 组件包的名称
version: string; // 组件包的版本
}
/** /**
* *
* *
* @export * @export
* @interface IExternalDependency * @interface IExternalDependency
*/ */
export interface IExternalDependency extends IDependency { export interface IExternalDependency extends INpmPackage, IDependency {}
package: string; // 组件包的名称
version: string; // 组件包的版本
}
export enum InternalDependencyType { export enum InternalDependencyType {
PAGE = 'pages', PAGE = 'pages',
@ -32,5 +34,5 @@ export interface IDependency {
subName?: string; // 下标子组件名称 subName?: string; // 下标子组件名称
main?: string; // 包导出组件入口文件路径 /lib/input main?: string; // 包导出组件入口文件路径 /lib/input
dependencyType?: DependencyType; // 依赖类型 内/外 dependencyType?: DependencyType; // 依赖类型 内/外
importName?: string; // 导入后名称 componentName?: string; // 导入后名称
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-useless-constructor */
export class CodeGeneratorError extends Error { export class CodeGeneratorError extends Error {
constructor(message: string) { constructor(message: string) {
super(message); super(message);
@ -5,21 +6,18 @@ export class CodeGeneratorError extends Error {
} }
} }
// tslint:disable-next-line: max-classes-per-file
export class ComponentValidationError extends CodeGeneratorError { export class ComponentValidationError extends CodeGeneratorError {
constructor(errorString: string) { constructor(errorString: string) {
super(errorString); super(errorString);
} }
} }
// tslint:disable-next-line: max-classes-per-file
export class CompatibilityError extends CodeGeneratorError { export class CompatibilityError extends CodeGeneratorError {
constructor(errorString: string) { constructor(errorString: string) {
super(errorString); super(errorString);
} }
} }
// tslint:disable-next-line: max-classes-per-file
export class PublisherError extends CodeGeneratorError { export class PublisherError extends CodeGeneratorError {
constructor(errorString: string) { constructor(errorString: string) {
super(errorString); super(errorString);

View File

@ -1,7 +1,5 @@
export * from './core'; export * from './core';
export * from './deps'; export * from './deps';
export * from './error'; export * from './error';
export * from './result';
export * from './schema';
export * from './intermediate'; export * from './intermediate';
export * from './publisher'; export * from './publisher';

View File

@ -1,25 +1,26 @@
import { IAppConfig, IAppMeta, IContainerNodeItem, IDependency, II18nMap, UtilItem } from '.'; import { I18nMap, UtilsMap, ContainerSchema, JSONObject } from '@ali/lowcode-types';
import { IDependency, INpmPackage } from './deps';
export interface IParseResult { export interface IParseResult {
containers: IContainerInfo[]; containers: IContainerInfo[];
globalUtils?: IUtilInfo; globalUtils?: IUtilInfo;
globalI18n?: II18nMap; globalI18n?: I18nMap;
globalRouter?: IRouterInfo; globalRouter?: IRouterInfo;
project?: IProjectInfo; project?: IProjectInfo;
} }
export type IContainerInfo = IContainerNodeItem &
IWithDependency & {
containerType: string;
moduleName: string;
};
export interface IWithDependency { export interface IWithDependency {
deps?: IDependency[]; deps?: IDependency[];
} }
export interface IContainerInfo extends ContainerSchema, IWithDependency {
containerType: string;
moduleName: string;
}
export interface IUtilInfo extends IWithDependency { export interface IUtilInfo extends IWithDependency {
utils: UtilItem[]; utils: UtilsMap;
} }
export interface IRouterInfo extends IWithDependency { export interface IRouterInfo extends IWithDependency {
@ -30,13 +31,15 @@ export interface IRouterInfo extends IWithDependency {
} }
export interface IProjectInfo { export interface IProjectInfo {
config: IAppConfig;
meta: IAppMeta;
css?: string; css?: string;
constants?: Record<string, string>;
i18n?: II18nMap;
containersDeps?: IDependency[]; containersDeps?: IDependency[];
utilsDeps?: IDependency[]; utilsDeps?: IDependency[];
constants?: JSONObject;
i18n?: I18nMap;
packages: INpmPackage[];
meta?: {
name?: string;
};
} }
/** /**

View File

@ -1,17 +1,15 @@
import { import { ResultDir } from '@ali/lowcode-types';
IResultDir,
} from './index';
export type PublisherFactory<T, U> = (configuration?: Partial<T>) => U; export type PublisherFactory<T, U> = (configuration?: Partial<T>) => U;
export interface IPublisher<T, U> { export interface IPublisher<T, U> {
publish: (options?: T) => Promise<IPublisherResponse<U>>; publish: (options?: T) => Promise<IPublisherResponse<U>>;
getProject: () => IResultDir | void; getProject: () => ResultDir | void;
setProject: (project: IResultDir) => void; setProject: (project: ResultDir) => void;
} }
export interface IPublisherFactoryParams { export interface IPublisherFactoryParams {
project?: IResultDir; project?: ResultDir;
} }
export interface IPublisherResponse<T> { export interface IPublisherResponse<T> {
success: boolean; success: boolean;

View File

@ -1,88 +0,0 @@
/**
*
*
* @export
* @interface IResultDir
*/
export interface IResultDir {
/**
* Root .
*
* @type {string}
* @memberof IResultDir
*/
name: string;
/**
*
*
* @type {IResultDir[]}
* @memberof IResultDir
*/
dirs: IResultDir[];
/**
*
*
* @type {IResultFile[]}
* @memberof IResultDir
*/
files: IResultFile[];
/**
*
*
* @param {IResultFile} file
* @memberof IResultDir
*/
addFile(file: IResultFile): void;
/**
*
*
* @param {IResultDir} dir
* @memberof IResultDir
*/
addDirectory(dir: IResultDir): void;
}
/**
*
*
* @export
* @interface IResultFile
*/
export interface IResultFile {
/**
*
*
* @type {string}
* @memberof IResultFile
*/
name: string;
/**
* .js .less
*
* @type {string}
* @memberof IResultFile
*/
ext: string;
/**
*
*
* @type {string}
* @memberof IResultFile
*/
content: string;
}
export interface IPackageJSON {
name: string;
version: string;
description?: string;
dependencies: Record<string, string>;
devDependencies: Record<string, string>;
scripts?: Record<string, string>;
engines?: Record<string, string>;
repository?: {
type: string;
url: string;
};
private?: boolean;
}

View File

@ -1,69 +0,0 @@
import { BlockSchema, ComponentSchema, NodeSchema, PageSchema, ProjectSchema } from '@ali/lowcode-types';
export * from '@ali/lowcode-types';
/**
* -
*
* @export
* @interface II18nMap
*/
export interface II18nMap {
[lang: string]: {
[key: string]: string;
};
}
/**
*
*
* @export
* @interface IBasicSchema
*/
export interface IBasicSchema extends ProjectSchema {}
export interface IProjectSchema extends IBasicSchema {
// TODO: 下面的几个值真的需要吗?....
constants: Record<string, string>; // 应用范围内的全局常量;
css: string; // 应用范围内的全局样式;
config: IAppConfig; // 当前应用配置信息
meta: IAppMeta; // 当前应用元数据信息
}
/**
* -
*
* @export
* @interface IContainerNodeItem
* @extends {NodeSchema}
*/
export type IContainerNodeItem = PageSchema | BlockSchema | ComponentSchema;
// TODO...
export interface IBasicMeta {
title: string; // 标题描述
}
// TODO...
export interface IPageMeta extends IBasicMeta {
router: string; // 页面路由
spmb?: string; // spm
}
export interface IAppConfig {
sdkVersion?: string; // 渲染模块版本
historyMode?: 'browser' | 'hash'; // 浏览器路由browser 哈希路由hash
targetRootID?: string; // 渲染根节点 ID
layout?: NodeSchema;
theme?: object; // 主题配置,根据接入的主题模块不同
}
export interface IAppMeta {
name: string; // 应用中文名称
git_group?: string; // 应用对应git分组名
project_name?: string; // 应用对应git的project名称
description?: string; // 应用描述
spma?: string; // 应用spma A位信息
creator?: string; // author
[otherAttrName: string]: any;
}

View File

@ -22,7 +22,10 @@ export function upperCaseFirst(inputValue: string): string {
return changeCase.upperCaseFirst(inputValue); return changeCase.upperCaseFirst(inputValue);
} }
export function uniqueArray<T>(arr: T[]) { export function uniqueArray<T>(arr: T[], by: (i: T) => string) {
const uniqueItems = [...new Set<T>(arr)]; const map: Record<string, T> = {};
arr.forEach((item) => (map[by(item)] = item));
const uniqueKeys = [...new Set<string>(Object.keys(map))];
const uniqueItems = uniqueKeys.map((key) => map[key]);
return uniqueItems; return uniqueItems;
} }

View File

@ -2,98 +2,100 @@ import {
CompositeArray, CompositeArray,
CompositeValue, CompositeValue,
CompositeObject, CompositeObject,
JSExpression,
JSFunction,
JSONArray,
JSONObject,
isJSExpression, isJSExpression,
isJSFunction, isJSFunction,
isJSSlot, isJSSlot,
JSSlot, } from '@ali/lowcode-types';
NodeSchema,
NodeData,
} from '../types';
import { generateExpression, generateFunction } from './jsExpression'; import { generateExpression, generateFunction } from './jsExpression';
import { generateJsSlot } from './jsSlot';
import { isValidIdentifier } from './validate';
import { camelize } from './common';
export interface CustomHandlerSet { import { CompositeValueGeneratorOptions, CompositeTypeContainerHandlerSet, CodeGeneratorError } from '../types';
boolean?: (bool: boolean) => string;
number?: (num: number) => string;
string?: (str: string) => string;
array?: (arr: JSONArray | CompositeArray) => string;
object?: (obj: JSONObject | CompositeObject) => string;
expression?: (jsExpr: JSExpression) => string;
function?: (jsFunc: JSFunction) => string;
slot?: (jsSlot: JSSlot) => string;
node?: (node: NodeSchema) => string;
loopDataExpr?: (loopDataExpr: string) => string;
conditionExpr?: (conditionExpr: string) => string;
tagName?: (tagName: string) => string;
}
function generateArray(value: CompositeArray, handlers: CustomHandlerSet): string { const defaultContainerHandlers: CompositeTypeContainerHandlerSet = {
const body = value.map((v) => generateUnknownType(v, handlers)).join(','); default: (v) => v,
string: (v) => `'${v}'`,
};
function generateArray(value: CompositeArray, options: CompositeValueGeneratorOptions = {}): string {
const body = value.map((v) => generateUnknownType(v, options)).join(',');
return `[${body}]`; return `[${body}]`;
} }
function generateObject(value: CompositeObject, handlers: CustomHandlerSet): string { function generateObject(value: CompositeObject, options: CompositeValueGeneratorOptions = {}): string {
const body = Object.keys(value) const body = Object.keys(value)
.map((key) => { .map((key) => {
const v = generateUnknownType(value[key], handlers); let propName = key;
return `${key}: ${v}`;
// TODO: 可以增加更多智能修复的方法
const fixMethods: Array<(v: string) => string> = [camelize];
// Try to fix propName
while (!isValidIdentifier(propName)) {
const fixMethod = fixMethods.pop();
if (fixMethod) {
try {
propName = fixMethod(propName);
} catch (error) {
throw new CodeGeneratorError(error.message);
}
} else {
throw new CodeGeneratorError(`Propname: ${key} is not a valid identifier.`);
}
}
const v = generateUnknownType(value[key], options);
return `${propName}: ${v}`;
}) })
.join(',\n'); .join(',\n');
return `{${body}}`; return `{${body}}`;
} }
export function generateUnknownType(value: CompositeValue, handlers: CustomHandlerSet = {}): string { 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, handlers); return generateArray(value, options);
} else if (typeof value === 'object') { } else if (typeof value === 'object') {
if (value === null) { if (value === null) {
return 'null'; return 'null';
} }
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);
} }
if (isJSFunction(value)) { if (isJSFunction(value)) {
if (handlers.function) { if (options.handlers && options.handlers.function) {
return handlers.function(value); return options.handlers.function(value);
} }
return generateFunction(value); return generateFunction(value, { isArrow: true });
} }
if (isJSSlot(value)) { if (isJSSlot(value)) {
if (handlers.slot) { if (options.nodeGenerator) {
return handlers.slot(value); return generateJsSlot(value, options.nodeGenerator);
} }
throw new CodeGeneratorError("Can't find Node Generator");
return generateSlot(value, handlers);
} }
if (handlers.object) { if (options.handlers && options.handlers.object) {
return handlers.object(value); return options.handlers.object(value);
} }
return generateObject(value as CompositeObject, options);
return generateObject(value, handlers);
} 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 JSON.stringify(value); } else if (typeof value === 'number' && options.handlers && options.handlers.number) {
} else if (typeof value === 'number' && handlers.number) { return options.handlers.number(value);
return handlers.number(value); } else if (typeof value === 'boolean' && options.handlers && options.handlers.boolean) {
} else if (typeof value === 'boolean' && handlers.boolean) { return options.handlers.boolean(value);
return handlers.boolean(value);
} else if (typeof value === 'undefined') { } else if (typeof value === 'undefined') {
return 'undefined'; return 'undefined';
} }
@ -101,65 +103,16 @@ export function generateUnknownType(value: CompositeValue, handlers: CustomHandl
return JSON.stringify(value); return JSON.stringify(value);
} }
export function generateCompositeType(value: CompositeValue, handlers: CustomHandlerSet = {}): [boolean, string] { export function generateCompositeType(value: CompositeValue, options: CompositeValueGeneratorOptions = {}): string {
const result = generateUnknownType(value, handlers); const result = generateUnknownType(value, options);
const containerHandlers = {
...defaultContainerHandlers,
...(options.containerHandlers || {}),
};
// TODO什么场景下会返回这样的字符串 const isStringType = result.substr(0, 1) === "'" && result.substr(-1, 1) === "'";
if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") { if (isStringType) {
return [true, result.substring(1, result.length - 1)]; return (containerHandlers.string && containerHandlers.string(result.substring(1, result.length - 1))) || '';
} }
return (containerHandlers.default && containerHandlers.default(result)) || '';
return [false, result];
}
export function handleStringValueDefault([isString, result]: [boolean, string]) {
if (isString) {
return `'${result}'`;
}
return result;
}
function generateSlot({ title, params, value }: JSSlot, handlers: CustomHandlerSet): string {
return [
title && generateSingleLineComment(title),
`(`,
...(params || []),
`) => (`,
...(!value
? ['null']
: !Array.isArray(value)
? [generateNodeData(value, handlers)]
: value.map((node) => generateNodeData(node, handlers))),
`)`,
]
.filter(Boolean)
.join('');
}
function generateNodeData(node: NodeData, handlers: CustomHandlerSet): string {
if (typeof node === 'string') {
if (handlers.string) {
return handlers.string(node);
}
return JSON.stringify(node);
}
if (isJSExpression(node)) {
if (handlers.expression) {
return handlers.expression(node);
}
return generateExpression(node);
}
if (!handlers.node) {
throw new Error('cannot handle NodeSchema, handlers.node is missing');
}
return handlers.node(node);
}
function generateSingleLineComment(commentText: string): string {
return '/* ' + commentText.split('\n').join(' ').replace(/\*\//g, '*-/') + '*/';
} }

View File

@ -1,4 +1,5 @@
import { CodeGeneratorError, isJSExpression, isJSFunction } from '../types'; import { JSExpression, JSFunction, isJsExpression, isJsFunction } from '@ali/lowcode-types';
import { CodeGeneratorError } from '../types';
export function transformFuncExpr2MethodMember(methodName: string, functionBody: string): string { export function transformFuncExpr2MethodMember(methodName: string, functionBody: string): string {
const args = getFuncExprArguments(functionBody); const args = getFuncExprArguments(functionBody);
@ -31,19 +32,52 @@ export function getFuncExprBody(functionBody: string) {
return body; return body;
} }
export function getArrowFunction(functionBody: string) {
const args = getFuncExprArguments(functionBody);
const body = getFuncExprBody(functionBody);
return `(${args}) => { ${body} }`;
}
export function isJsCode(value: unknown): boolean {
return isJsExpression(value) || isJsFunction(value);
}
export function generateExpression(value: any): string { export function generateExpression(value: any): string {
if (isJSExpression(value)) { if (isJsExpression(value)) {
return value.value || 'null'; return (value as JSExpression).value || 'null';
} }
throw new CodeGeneratorError('Not a JSExpression'); throw new CodeGeneratorError('Not a JSExpression');
} }
// TODO: 这样真的可以吗? export function generateFunction(
export function generateFunction(value: any): string { value: any,
if (isJSFunction(value)) { config: {
return value.value || 'null'; name?: string;
isMember?: boolean;
isBlock?: boolean;
isArrow?: boolean;
} = {
name: undefined,
isMember: false,
isBlock: false,
isArrow: false,
},
) {
if (isJsCode(value)) {
const functionCfg = value as JSFunction;
if (config.isMember) {
return transformFuncExpr2MethodMember(config.name || '', functionCfg.value);
}
if (config.isBlock) {
return getFuncExprBody(functionCfg.value);
}
if (config.isArrow) {
return getArrowFunction(functionCfg.value);
}
return functionCfg.value;
} }
throw new CodeGeneratorError('Not a isJSFunction'); throw new CodeGeneratorError('Not a JSFunction or JSExpression');
} }

View File

@ -0,0 +1,35 @@
import { JSSlot, isJSSlot } from '@ali/lowcode-types';
import { CodeGeneratorError, NodeGenerator } from '../types';
function generateSingleLineComment(commentText: string): string {
return (
'/* ' +
commentText
.split('\n')
.join(' ')
.replace(/\*\//g, '*-/') +
'*/'
);
}
export function generateJsSlot(slot: any, generator: NodeGenerator): string {
if (isJSSlot(slot)) {
const { title, params, value } = slot as JSSlot;
if (!value) {
return 'null';
}
return [
title && generateSingleLineComment(title),
`(`,
...(params || []),
`) => (`,
...(!value ? ['null'] : !Array.isArray(value) ? [generator(value)] : value.map((node) => generator(node))),
`)`,
]
.filter(Boolean)
.join('');
}
throw new CodeGeneratorError('Not a JSSlot');
}

View File

@ -1,54 +1,134 @@
import _ from 'lodash'; import _ from 'lodash';
import { import {
PIECE_TYPE, JSSlot,
JSExpression,
NodeData,
NodeSchema,
PropsMap,
isJSExpression,
isJSSlot,
isDOMText,
} from '@ali/lowcode-types';
import {
CodeGeneratorError, CodeGeneratorError,
PIECE_TYPE,
CodePiece, CodePiece,
HandlerSet, HandlerSet,
NodeGenerator,
ExtGeneratorPlugin, ExtGeneratorPlugin,
isJSExpression, INodeGeneratorContext,
isJSFunction, INodeGeneratorConfig,
NodeData,
CompositeValue,
NodeSchema,
} from '../types'; } from '../types';
import { CustomHandlerSet, generateCompositeType } from './compositeType';
import { generateCompositeType } from './compositeType';
import { generateExpression } from './jsExpression'; import { generateExpression } from './jsExpression';
// tslint:disable-next-line: no-empty // tslint:disable-next-line: no-empty
const noop = () => []; const noop = () => [];
export function handleChildren(children: NodeData | NodeData[], handlers: HandlerSet<string>): string[] { const handleChildrenDefaultOptions = {
rerun: false,
};
export function handleSubNodes<T>(
children: unknown,
handlers: HandlerSet<T>,
options?: {
rerun?: boolean;
},
): T[] {
const opt = {
...handleChildrenDefaultOptions,
...(options || {}),
};
if (Array.isArray(children)) { if (Array.isArray(children)) {
return children.map((child) => handleChildren(child, handlers)).reduce((p, c) => p.concat(c), []); const list: NodeData[] = children as NodeData[];
} else if (typeof children === 'string') { return list.map((child) => handleSubNodes(child, handlers, opt)).reduce((p, c) => p.concat(c), []);
} else if (isDOMText(children)) {
const handler = handlers.string || handlers.common || noop; const handler = handlers.string || handlers.common || noop;
return handler(children); return handler(children as string);
} else if (isJSExpression(children)) { } else if (isJSExpression(children)) {
const handler = handlers.expression || handlers.common || noop; const handler = handlers.expression || handlers.common || noop;
return ['{', ...handler(children), '}']; return handler(children as JSExpression);
} else if (isJSFunction(children)) {
const handler = handlers.function || handlers.common || noop;
return handler(children);
} else { } else {
const handler = handlers.node || handlers.common || noop; const handler = handlers.node || handlers.common || noop;
return handler(children); const child = children as NodeSchema;
let curRes = handler(child);
if (opt.rerun && child.children) {
const childRes = handleSubNodes(child.children, handlers, opt);
curRes = curRes.concat(childRes || []);
}
if (child.props) {
// FIXME: currently only support PropsMap
const childProps = child.props as PropsMap;
Object.keys(childProps)
.filter((propName) => isJSSlot(childProps[propName]))
.forEach((propName) => {
const soltVals = (childProps[propName] as JSSlot).value;
const childRes = handleSubNodes(soltVals, handlers, opt);
curRes = curRes.concat(childRes || []);
});
}
return curRes;
} }
} }
export function generateAttr(attrName: string, attrValue: CompositeValue, handlers: CustomHandlerSet): CodePiece[] { export function handleChildren<T>(
if (attrName === 'initValue' || attrName === 'labelCol') { ctx: INodeGeneratorContext,
children: unknown,
handlers: HandlerSet<T>,
options?: {
rerun?: boolean;
},
): T[] {
const opt = {
...handleChildrenDefaultOptions,
...(options || {}),
};
if (Array.isArray(children)) {
const list: NodeData[] = children as NodeData[];
return list.map((child) => handleChildren(ctx, child, handlers, opt)).reduce((p, c) => p.concat(c), []);
} else if (isDOMText(children)) {
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 JSExpression);
} else {
const handler = handlers.node || handlers.common || noop;
const child = children as NodeSchema;
let curRes = handler(child);
if (opt.rerun && child.children) {
const childRes = handleChildren(ctx, child.children, handlers, opt);
curRes = curRes.concat(childRes || []);
}
return curRes;
}
}
export function generateAttr(ctx: INodeGeneratorContext, attrName: string, attrValue: any): CodePiece[] {
if (attrName === 'initValue') {
return []; return [];
} }
const [isString, valueStr] = generateCompositeType(attrValue, handlers); const valueStr = generateCompositeType(attrValue, {
containerHandlers: {
default: (v) => `{${v}}`,
string: (v) => `"${v}"`,
},
nodeGenerator: ctx.generator,
});
return [ return [
{ {
value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`, value: `${attrName}=${valueStr}`,
type: PIECE_TYPE.ATTR, type: PIECE_TYPE.ATTR,
}, },
]; ];
} }
export function generateAttrs(nodeItem: NodeSchema, handlers: CustomHandlerSet): CodePiece[] { export function generateAttrs(ctx: INodeGeneratorContext, nodeItem: NodeSchema): CodePiece[] {
const { props } = nodeItem; const { props } = nodeItem;
let pieces: CodePiece[] = []; let pieces: CodePiece[] = [];
@ -56,12 +136,12 @@ export function generateAttrs(nodeItem: NodeSchema, handlers: CustomHandlerSet):
if (props) { if (props) {
if (!Array.isArray(props)) { if (!Array.isArray(props)) {
Object.keys(props).forEach((propName: string) => { Object.keys(props).forEach((propName: string) => {
pieces = pieces.concat(generateAttr(propName, props[propName], handlers)); pieces = pieces.concat(generateAttr(ctx, propName, props[propName]));
}); });
} else { } else {
props.forEach((prop) => { props.forEach((prop) => {
if (prop.name && !prop.spread) { if (prop.name && !prop.spread) {
pieces = pieces.concat(generateAttr(prop.name, prop.value, handlers)); pieces = pieces.concat(generateAttr(ctx, prop.name, prop.value));
} }
// TODO: 处理 spread 场景(<Xxx {...(something)}/>) // TODO: 处理 spread 场景(<Xxx {...(something)}/>)
@ -72,32 +152,47 @@ export function generateAttrs(nodeItem: NodeSchema, handlers: CustomHandlerSet):
return pieces; return pieces;
} }
export function mapNodeName(src: string): string { function mapNodeName(src: string, mapping: Record<string, string>): string {
if (src === 'Div') { if (mapping[src]) {
return 'div'; return mapping[src];
} }
return src; return src;
} }
export function generateBasicNode(nodeItem: NodeSchema): CodePiece[] { export function generateBasicNode(
ctx: INodeGeneratorContext,
nodeItem: NodeSchema,
mapping: Record<string, string>,
): CodePiece[] {
const pieces: CodePiece[] = []; const pieces: CodePiece[] = [];
pieces.push({ pieces.push({
value: mapNodeName(nodeItem.componentName), value: mapNodeName(nodeItem.componentName, mapping),
type: PIECE_TYPE.TAG, type: PIECE_TYPE.TAG,
}); });
return pieces; return pieces;
} }
export function generateReactCtrlLine(nodeItem: NodeSchema, handlers: CustomHandlerSet): CodePiece[] { // TODO: 生成文档
// 为包裹的代码片段生成子上下文,集成父级上下文,并传入子级上下文新增内容。(如果存在多级上下文怎么处理?)
// 创建新的上下文,并从作用域中取对应同名变量塞到作用域里面?
// export function createSubContext() {}
/**
* JSX React loop condition
*
* @export
* @param {NodeSchema} nodeItem UI
* @returns {CodePiece[]}
*/
export function generateReactCtrlLine(ctx: INodeGeneratorContext, nodeItem: NodeSchema): CodePiece[] {
const pieces: CodePiece[] = []; const pieces: CodePiece[] = [];
if (nodeItem.loop) { if (nodeItem.loop) {
const loopItemName = nodeItem.loopArgs?.[0] || 'item'; const loopItemName = nodeItem.loopArgs?.[0] || 'item';
const loopIndexName = nodeItem.loopArgs?.[1] || 'index'; const loopIndexName = nodeItem.loopArgs?.[1] || 'index';
// TODO: 静态的值可以抽离出来?
const loopDataExpr = (handlers.loopDataExpr || _.identity)( const loopDataExpr = (handlers.loopDataExpr || _.identity)(
isJSExpression(nodeItem.loop) ? `(${nodeItem.loop.value})` : `(${JSON.stringify(nodeItem.loop)})`, isJSExpression(nodeItem.loop) ? `(${nodeItem.loop.value})` : `(${JSON.stringify(nodeItem.loop)})`,
); );
@ -114,8 +209,11 @@ export function generateReactCtrlLine(nodeItem: NodeSchema, handlers: CustomHand
} }
if (nodeItem.condition) { if (nodeItem.condition) {
const [isString, value] = generateCompositeType(nodeItem.condition, handlers); const value = generateCompositeType(nodeItem.condition, {
const conditionExpr = (handlers.conditionExpr || _.identity)(isString ? `'${value}'` : value); nodeGenerator: ctx.generator,
});
const conditionExpr = (handlers.conditionExpr || _.identity)(value);
pieces.unshift({ pieces.unshift({
value: `(${conditionExpr}) && (`, value: `(${conditionExpr}) && (`,
@ -183,21 +281,27 @@ export function linkPieces(pieces: CodePiece[], handlers: CustomHandlerSet): str
export function createNodeGenerator( export function createNodeGenerator(
handlers: HandlerSet<string>, handlers: HandlerSet<string>,
plugins: ExtGeneratorPlugin[], plugins: ExtGeneratorPlugin[],
customHandlers: CustomHandlerSet = {}, cfg?: INodeGeneratorConfig,
) { ): NodeGenerator {
let nodeTypeMapping: Record<string, string> = {};
if (cfg && cfg.nodeTypeMapping) {
nodeTypeMapping = cfg.nodeTypeMapping;
}
const generateNode = (nodeItem: NodeSchema): string => { const generateNode = (nodeItem: NodeSchema): string => {
let pieces: CodePiece[] = []; let pieces: CodePiece[] = [];
const ctx: INodeGeneratorContext = {
generator: generateNode,
};
plugins.forEach((p) => { plugins.forEach((p) => {
pieces = pieces.concat(p(nodeItem, customHandlers)); pieces = pieces.concat(p(ctx, nodeItem));
}); });
pieces = pieces.concat(generateBasicNode(ctx, nodeItem, nodeTypeMapping));
pieces = pieces.concat(generateBasicNode(nodeItem)); pieces = pieces.concat(generateAttrs(ctx, nodeItem));
pieces = pieces.concat(generateAttrs(nodeItem, customHandlers)); if (nodeItem.children && (nodeItem.children as unknown[]).length > 0) {
if (nodeItem.children && !_.isEmpty(nodeItem.children)) {
pieces = pieces.concat( pieces = pieces.concat(
handleChildren(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,
})), })),
@ -207,21 +311,20 @@ export function createNodeGenerator(
return linkPieces(pieces, customHandlers); return linkPieces(pieces, customHandlers);
}; };
handlers.node = (node: NodeSchema) => [generateNode(node)]; handlers.node = (input: NodeSchema) => [generateNode(input)];
customHandlers.node = customHandlers.node || generateNode;
return generateNode; return generateNode;
} }
export const generateString = (input: string) => [input]; export const generateString = (input: string) => [input];
export function createReactNodeGenerator() { export function createReactNodeGenerator(cfg?: INodeGeneratorConfig): NodeGenerator {
return createNodeGenerator( return createNodeGenerator(
{ {
string: generateString, string: generateString,
expression: (input) => [generateExpression(input)], expression: (input) => [generateExpression(input)],
}, },
[generateReactCtrlLine], [generateReactCtrlLine],
cfg,
); );
} }

View File

@ -0,0 +1,35 @@
import { ResultFile, ResultDir } from '@ali/lowcode-types';
import { CodeGeneratorError } from '../types/error';
export function createResultFile(name: string, ext = 'jsx', content = ''): ResultFile {
return {
name,
ext,
content,
};
}
export function createResultDir(name: string): ResultDir {
return {
name,
dirs: [],
files: [],
};
}
export function addDirectory(target: ResultDir, dir: ResultDir): void {
if (target.dirs.findIndex((d) => d.name === dir.name) < 0) {
target.dirs.push(dir);
} else {
throw new CodeGeneratorError(`Adding same directory to one directory: ${dir.name} -> ${target.name}`);
}
}
export function addFile(target: ResultDir, file: ResultFile): void {
if (target.files.findIndex((f) => f.name === file.name && f.ext === file.ext) < 0) {
target.files.push(file);
} else {
throw new CodeGeneratorError(`Adding same file to one directory: ${file.name} -> ${target.name}`);
}
}

View File

@ -1,25 +1,25 @@
import { IResultFile, IResultDir } from '../types'; import { ResultDir, ResultFile } from '@ali/lowcode-types';
import ResultDir from '../model/ResultDir'; import { createResultDir, addDirectory, addFile } from '../utils/resultHelper';
type FuncFileGenerator = () => [string[], IResultFile]; type FuncFileGenerator = () => [string[], ResultFile];
export function insertFile(root: IResultDir, path: string[], file: IResultFile) { export function insertFile(root: ResultDir, path: string[], file: ResultFile) {
let current: IResultDir = root; let current: ResultDir = root;
path.forEach(pathNode => { path.forEach((pathNode) => {
const dir = current.dirs.find(d => d.name === pathNode); const dir = current.dirs.find((d) => d.name === pathNode);
if (dir) { if (dir) {
current = dir; current = dir;
} else { } else {
const newDir = new ResultDir(pathNode); const newDir = createResultDir(pathNode);
current.addDirectory(newDir); addDirectory(current, newDir);
current = newDir; current = newDir;
} }
}); });
current.addFile(file); addFile(current, file);
} }
export function runFileGenerator(root: IResultDir, fun: FuncFileGenerator) { export function runFileGenerator(root: ResultDir, fun: FuncFileGenerator) {
const [path, file] = fun(); const [path, file] = fun();
insertFile(root, path, file); insertFile(root, path, file);
} }

View File

@ -0,0 +1,3 @@
export const isValidIdentifier = (name: string) => {
return /^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/.test(name);
};

View File

@ -0,0 +1,14 @@
export interface PackageJSON {
name: string;
version: string;
description?: string;
dependencies: Record<string, string>;
devDependencies: Record<string, string>;
scripts?: Record<string, string>;
engines?: Record<string, string>;
repository?: {
type: string;
url: string;
};
private?: boolean;
}

View File

@ -0,0 +1,59 @@
/**
*
*
* @export
* @interface ResultDir
*/
export interface ResultDir {
/**
* Root .
*
* @type {string}
* @memberof ResultDir
*/
name: string;
/**
*
*
* @type {ResultDir[]}
* @memberof ResultDir
*/
dirs: ResultDir[];
/**
*
*
* @type {ResultFile[]}
* @memberof ResultDir
*/
files: ResultFile[];
}
/**
*
*
* @export
* @interface ResultFile
*/
export interface ResultFile {
/**
*
*
* @type {string}
* @memberof ResultFile
*/
name: string;
/**
* .js .less
*
* @type {string}
* @memberof ResultFile
*/
ext: string;
/**
*
*
* @type {string}
* @memberof ResultFile
*/
content: string;
}

View File

@ -51,7 +51,7 @@ export interface FieldExtraProps {
mode?: 'plaintext' | 'paragraph' | 'article'; mode?: 'plaintext' | 'paragraph' | 'article';
// 从 contentEditable 获取内容并设置到属性 // 从 contentEditable 获取内容并设置到属性
onSaveContent?: (content: string, prop: any) => any; onSaveContent?: (content: string, prop: any) => any;
} };
} }
export interface FieldConfig extends FieldExtraProps { export interface FieldConfig extends FieldExtraProps {

View File

@ -15,3 +15,5 @@ export * from './setter-config';
export * from './setting-target'; export * from './setting-target';
export * from './node'; export * from './node';
export * from './transform-stage'; export * from './transform-stage';
export * from './code-intermediate';
export * from './code-result';

View File

@ -1,18 +1,20 @@
import { ComponentsMap } from './npm'; import { ComponentsMap } from './npm';
import { CompositeValue, JSExpression, CompositeObject, JSONObject } from './value-type'; import { CompositeValue, JSExpression, JSFunction, CompositeObject, JSONObject } from './value-type';
import { DataSource } from './data-source'; import { DataSource } from './data-source';
import { I18nMap } from './i18n'; import { I18nMap } from './i18n';
import { UtilsMap } from './utils'; import { UtilsMap } from './utils';
// 搭建基础协议 - 单个组件树节点描述
// 转换成一个 .jsx 文件内 React Class 类 render 函数返回的 jsx 代码
export interface NodeSchema { export interface NodeSchema {
id?: string; id?: string;
componentName: string; componentName: string; // 组件名称 必填、首字母大写
props?: PropsMap | PropsList; props?: PropsMap | PropsList; // 组件属性对象
leadingComponents?: string; leadingComponents?: string;
condition?: CompositeValue; condition?: CompositeValue; // 渲染条件
loop?: CompositeValue; loop?: CompositeValue; // 循环数据
loopArgs?: [string, string]; loopArgs?: [string, string]; // 循环迭代对象、索引名称 ["item", "index"]
children?: NodeData | NodeData[]; children?: NodeData | NodeData[]; // 子节点
// ------- future support ----- // ------- future support -----
conditionGroup?: string; conditionGroup?: string;
@ -30,6 +32,7 @@ export type PropsList = Array<{
}>; }>;
export type NodeData = NodeSchema | JSExpression | DOMText; export type NodeData = NodeSchema | JSExpression | DOMText;
export type NodeDataType = NodeData | NodeData[];
export function isDOMText(data: any): data is DOMText { export function isDOMText(data: any): data is DOMText {
return typeof data === 'string'; return typeof data === 'string';
@ -45,10 +48,10 @@ export interface ContainerSchema extends NodeSchema {
[key: string]: CompositeValue; [key: string]: CompositeValue;
}; };
methods?: { methods?: {
[key: string]: JSExpression; [key: string]: JSExpression | JSFunction;
}; };
lifeCycles?: { lifeCycles?: {
[key: string]: JSExpression; [key: string]: JSExpression | JSFunction;
}; };
css?: string; css?: string;
dataSource?: DataSource; dataSource?: DataSource;
@ -82,7 +85,6 @@ export interface BlockSchema extends ContainerSchema {
export type RootSchema = PageSchema | ComponentSchema | BlockSchema; export type RootSchema = PageSchema | ComponentSchema | BlockSchema;
export interface SlotSchema extends NodeSchema { export interface SlotSchema extends NodeSchema {
name?: string;
componentName: 'Slot'; componentName: 'Slot';
params?: string[]; params?: string[];
} }

View File

@ -1,21 +1,17 @@
import { NpmInfo } from './npm'; import { NpmInfo } from './npm';
import { JSExpression, JSFunction } from './value-type'; import { JSExpression, JSFunction } from './value-type';
export type UtilItem = export type InternalUtils = {
| { name: string;
name: string; type: 'function';
type: 'npm'; content: JSFunction | JSExpression;
content: NpmInfo; };
}
| {
name: string;
type: 'tnpm';
content: NpmInfo;
}
| {
name: string;
type: 'function';
content: JSFunction | JSExpression;
};
export type ExternalUtils = {
name: string;
type: 'npm' | 'tnpm';
content: NpmInfo;
};
export type UtilItem = InternalUtils | ExternalUtils;
export type UtilsMap = UtilItem[]; export type UtilsMap = UtilItem[];

View File

@ -11,10 +11,15 @@ export interface JSExpression {
* *
*/ */
mock?: any; mock?: any;
}
// 函数
export interface JSFunction {
type: 'JSFunction';
/** /**
* extTypeevents *
*/ */
[key: string]: any; value: string;
} }
/** /**
@ -34,7 +39,6 @@ export interface JSFunction {
} }
export interface JSSlot { export interface JSSlot {
name?: string;
type: 'JSSlot'; type: 'JSSlot';
title?: string; title?: string;
// 函数的入参 // 函数的入参
@ -61,7 +65,6 @@ export interface CompositeObject {
[key: string]: CompositeValue; [key: string]: CompositeValue;
} }
export function isJSExpression(data: any): data is JSExpression { export function isJSExpression(data: any): data is JSExpression {
return data && data.type === 'JSExpression'; return data && data.type === 'JSExpression';
} }