feat: support UIPaaS-Component code generator solution

This commit is contained in:
LeoYuan 袁力皓 2022-12-13 11:36:44 +08:00 committed by eternalsky
parent 82b6a01533
commit 1ca940c880
9 changed files with 37 additions and 19 deletions

View File

@ -559,8 +559,8 @@ codealike.json
"registry": "https://registry.npm.xxx.com" "registry": "https://registry.npm.xxx.com"
}, },
"dependencies": { "dependencies": {
"@alilc/lowcode-code-generator": "^1.0.0-beta.16", "@alilc/lowcode-code-generator": "^1.0.0",
"@alilc/lowcode-types": "^1.0.0-beta.21", "@alilc/lowcode-types": "^1.0.0",
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -62,10 +62,10 @@ export class ProjectBuilder implements IProjectBuilder {
private projectPostProcessors: ProjectPostProcessor[]; private projectPostProcessors: ProjectPostProcessor[];
/** 是否处于严格模式 */ /** 是否处于严格模式 */
public readonly inStrictMode: boolean; readonly inStrictMode: boolean;
/** 一些额外的上下文数据 */ /** 一些额外的上下文数据 */
public readonly extraContextData: IContextData; readonly extraContextData: IContextData;
constructor({ constructor({
template, template,
@ -260,7 +260,10 @@ export class ProjectBuilder implements IProjectBuilder {
let finalResult = projectRoot; let finalResult = projectRoot;
for (const projectPostProcessor of this.projectPostProcessors) { for (const projectPostProcessor of this.projectPostProcessors) {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
finalResult = await projectPostProcessor(finalResult, schema, originalSchema); finalResult = await projectPostProcessor(finalResult, schema, originalSchema, {
template: this.template,
parseResult,
});
} }
return finalResult; return finalResult;

View File

@ -32,7 +32,7 @@ import {
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const'; import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
import { getErrorMessage } from '../utils/errors'; import { getErrorMessage } from '../utils/errors';
import { handleSubNodes } from '../utils/schema'; import { handleSubNodes, isValidContainerType } from '../utils/schema';
import { uniqueArray } from '../utils/common'; import { uniqueArray } from '../utils/common';
import { componentAnalyzer } from '../analyzer/componentAnalyzer'; import { componentAnalyzer } from '../analyzer/componentAnalyzer';
import { ensureValidClassName } from '../utils/validate'; import { ensureValidClassName } from '../utils/validate';
@ -141,7 +141,7 @@ export class SchemaParser implements ISchemaParser {
if (schema.componentsTree.length > 0) { if (schema.componentsTree.length > 0) {
const firstRoot: ContainerSchema = schema.componentsTree[0] as ContainerSchema; const firstRoot: ContainerSchema = schema.componentsTree[0] as ContainerSchema;
if (!('fileName' in firstRoot) || !firstRoot.fileName) { if (!firstRoot.fileName && !isValidContainerType(firstRoot)) {
// 整个 schema 描述一个容器,且无根节点定义 // 整个 schema 描述一个容器,且无根节点定义
const container: IContainerInfo = { const container: IContainerInfo = {
...firstRoot, ...firstRoot,
@ -259,8 +259,7 @@ export class SchemaParser implements ISchemaParser {
utils = schema.utils; utils = schema.utils;
utilsDeps = schema.utils utilsDeps = schema.utils
.filter( .filter(
(u): u is { name: string; type: 'npm' | 'tnpm'; content: NpmInfo } => (u): u is { name: string; type: 'npm' | 'tnpm'; content: NpmInfo } => u.type !== 'function',
u.type !== 'function',
) )
.map( .map(
(u): IExternalDependency => ({ (u): IExternalDependency => ({

View File

@ -9,7 +9,7 @@ const PARSERS = ['css', 'scss', 'less', 'json', 'html', 'vue'];
export interface ProcessorConfig { export interface ProcessorConfig {
customFileTypeParser: Record<string, string>; customFileTypeParser: Record<string, string>;
plugins?: Array<prettier.Plugin>; plugins?: prettier.Plugin[];
} }
const factory: PostProcessorFactory<ProcessorConfig> = (config?: ProcessorConfig) => { const factory: PostProcessorFactory<ProcessorConfig> = (config?: ProcessorConfig) => {
@ -33,6 +33,8 @@ const factory: PostProcessorFactory<ProcessorConfig> = (config?: ProcessorConfig
return prettier.format(content, { return prettier.format(content, {
parser, parser,
plugins: [parserBabel, parserPostCss, parserHtml, ...(cfg.plugins || [])], plugins: [parserBabel, parserPostCss, parserHtml, ...(cfg.plugins || [])],
singleQuote: true,
jsxSingleQuote: false,
}); });
}; };

View File

@ -170,11 +170,17 @@ export interface IProjectBuilder {
/** 项目级别的前置处理器 */ /** 项目级别的前置处理器 */
export type ProjectPreProcessor = (schema: ProjectSchema) => Promise<ProjectSchema> | ProjectSchema; export type ProjectPreProcessor = (schema: ProjectSchema) => Promise<ProjectSchema> | ProjectSchema;
export interface ProjectPostProcessorOptions {
parseResult?: IParseResult;
template?: IProjectTemplate;
}
/** 项目级别的后置处理器 */ /** 项目级别的后置处理器 */
export type ProjectPostProcessor = ( export type ProjectPostProcessor = (
result: ResultDir, result: ResultDir,
schema: ProjectSchema, schema: ProjectSchema,
originalSchema: ProjectSchema | string, originalSchema: ProjectSchema | string,
options: ProjectPostProcessorOptions,
) => Promise<ResultDir> | ResultDir; ) => Promise<ResultDir> | ResultDir;
/** 模块级别的后置处理器的工厂方法 */ /** 模块级别的后置处理器的工厂方法 */

View File

@ -1,7 +1,7 @@
import changeCase from 'change-case'; import changeCase from 'change-case';
import type { IProjectInfo } from '../types/intermediate'; import type { IProjectInfo } from '../types/intermediate';
export type DataSourceDependenciesConfig = { export interface DataSourceDependenciesConfig {
/** 数据源引擎的版本 */ /** 数据源引擎的版本 */
engineVersion?: string; engineVersion?: string;
/** 数据源引擎的包名 */ /** 数据源引擎的包名 */
@ -14,7 +14,7 @@ export type DataSourceDependenciesConfig = {
handlersPackages?: { handlersPackages?: {
[key: string]: string; [key: string]: string;
}; };
}; }
export function buildDataSourceDependencies( export function buildDataSourceDependencies(
ir: IProjectInfo, ir: IProjectInfo,
@ -22,13 +22,13 @@ export function buildDataSourceDependencies(
): Record<string, string> { ): Record<string, string> {
return { return {
// 数据源引擎的依赖包 // 数据源引擎的依赖包
[cfg.enginePackage || '@alilc/lowcode-datasource-engine']: cfg.engineVersion || 'latest', [cfg.enginePackage || '@alilc/lowcode-datasource-engine']: cfg.engineVersion || '^1.0.0',
// 各种数据源的 handlers 的依赖包 // 各种数据源的 handlers 的依赖包
...(ir.dataSourcesTypes || []).reduce( ...(ir.dataSourcesTypes || []).reduce(
(acc, dsType) => ({ (acc, dsType) => ({
...acc, ...acc,
[getDataSourceHandlerPackageName(dsType)]: cfg.handlersVersion?.[dsType] || 'latest', [getDataSourceHandlerPackageName(dsType)]: cfg.handlersVersion?.[dsType] || '^1.0.0',
}), }),
{}, {},
), ),

View File

@ -11,6 +11,7 @@ import * as schema from './schema';
import * as version from './version'; import * as version from './version';
import * as scope from './Scope'; import * as scope from './Scope';
import * as expressionParser from './expressionParser'; import * as expressionParser from './expressionParser';
import * as dataSource from './dataSource';
export { export {
common, common,
@ -25,4 +26,5 @@ export {
version, version,
scope, scope,
expressionParser, expressionParser,
dataSource,
}; };

View File

@ -182,7 +182,7 @@ function generateSimpleNode(
function linkPieces(pieces: CodePiece[]): string { function linkPieces(pieces: CodePiece[]): string {
const tagsPieces = pieces.filter((p) => p.type === PIECE_TYPE.TAG); const tagsPieces = pieces.filter((p) => p.type === PIECE_TYPE.TAG);
if (tagsPieces.length !== 1) { if (tagsPieces.length !== 1) {
throw new CodeGeneratorError('One node only need one tag define'); throw new CodeGeneratorError('Only one tag definition required', tagsPieces);
} }
const tagName = tagsPieces[0].value; const tagName = tagsPieces[0].value;
@ -270,8 +270,7 @@ export function generateReactLoopCtrl(
const loopDataExpr = pipe( const loopDataExpr = pipe(
nodeItem.loop, nodeItem.loop,
// 将 JSExpression 转换为 JS 表达式代码: // 将 JSExpression 转换为 JS 表达式代码:
(expr) => (expr) => generateCompositeType(expr, scope, {
generateCompositeType(expr, scope, {
handlers: config?.handlers, handlers: config?.handlers,
tolerateEvalErrors: false, // 这个内部不需要包 try catch, 下面会统一加的 tolerateEvalErrors: false, // 这个内部不需要包 try catch, 下面会统一加的
}), }),
@ -391,8 +390,7 @@ export function createNodeGenerator(cfg: NodeGeneratorConfig = {}): NodeGenerato
return `{${valueStr}}`; return `{${valueStr}}`;
}; };
return (nodeItem: NodeDataType, scope: IScope) => return (nodeItem: NodeDataType, scope: IScope) => unwrapJsExprQuoteInJsx(generateNode(nodeItem, scope));
unwrapJsExprQuoteInJsx(generateNode(nodeItem, scope));
} }
const defaultReactGeneratorConfig: NodeGeneratorConfig = { const defaultReactGeneratorConfig: NodeGeneratorConfig = {

View File

@ -138,3 +138,11 @@ export function handleSubNodes<T>(
return []; return [];
} }
} }
export function isValidContainerType(schema: NodeSchema) {
return [
'Page',
'Component',
'Block',
].includes(schema.componentName);
}