mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-26 12:18:21 +00:00
feat: 🎸 完善 Rax 出码, 补充更复杂的带有数据源绑定/条件/循环以及 Utils 的测试用例并 pass
This commit is contained in:
parent
7fe4bc0ac1
commit
adcfacb233
@ -1,6 +1,7 @@
|
|||||||
export const COMMON_CHUNK_NAME = {
|
export const COMMON_CHUNK_NAME = {
|
||||||
ExternalDepsImport: 'CommonExternalDependencyImport',
|
ExternalDepsImport: 'CommonExternalDependencyImport',
|
||||||
InternalDepsImport: 'CommonInternalDependencyImport',
|
InternalDepsImport: 'CommonInternalDependencyImport',
|
||||||
|
ImportAliasDefine: 'CommonImportAliasDefine',
|
||||||
FileVarDefine: 'CommonFileScopeVarDefine',
|
FileVarDefine: 'CommonFileScopeVarDefine',
|
||||||
FileUtilDefine: 'CommonFileScopeMethodDefine',
|
FileUtilDefine: 'CommonFileScopeMethodDefine',
|
||||||
FileMainContent: 'CommonFileMainContent',
|
FileMainContent: 'CommonFileMainContent',
|
||||||
@ -28,18 +29,22 @@ export const CLASS_DEFINE_CHUNK_NAME = {
|
|||||||
export const DEFAULT_LINK_AFTER = {
|
export const DEFAULT_LINK_AFTER = {
|
||||||
[COMMON_CHUNK_NAME.ExternalDepsImport]: [],
|
[COMMON_CHUNK_NAME.ExternalDepsImport]: [],
|
||||||
[COMMON_CHUNK_NAME.InternalDepsImport]: [COMMON_CHUNK_NAME.ExternalDepsImport],
|
[COMMON_CHUNK_NAME.InternalDepsImport]: [COMMON_CHUNK_NAME.ExternalDepsImport],
|
||||||
|
[COMMON_CHUNK_NAME.ImportAliasDefine]: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport],
|
||||||
[COMMON_CHUNK_NAME.FileVarDefine]: [
|
[COMMON_CHUNK_NAME.FileVarDefine]: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
],
|
],
|
||||||
[COMMON_CHUNK_NAME.FileUtilDefine]: [
|
[COMMON_CHUNK_NAME.FileUtilDefine]: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
],
|
],
|
||||||
[CLASS_DEFINE_CHUNK_NAME.Start]: [
|
[CLASS_DEFINE_CHUNK_NAME.Start]: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
],
|
],
|
||||||
@ -50,20 +55,13 @@ export const DEFAULT_LINK_AFTER = {
|
|||||||
CLASS_DEFINE_CHUNK_NAME.InsVar,
|
CLASS_DEFINE_CHUNK_NAME.InsVar,
|
||||||
CLASS_DEFINE_CHUNK_NAME.InsVarMethod,
|
CLASS_DEFINE_CHUNK_NAME.InsVarMethod,
|
||||||
],
|
],
|
||||||
[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]: [
|
[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],
|
||||||
CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
|
|
||||||
],
|
|
||||||
[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]: [
|
[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]: [
|
||||||
CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
|
CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
|
||||||
CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
|
CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
|
||||||
],
|
],
|
||||||
[CLASS_DEFINE_CHUNK_NAME.StaticVar]: [
|
[CLASS_DEFINE_CHUNK_NAME.StaticVar]: [CLASS_DEFINE_CHUNK_NAME.Start],
|
||||||
CLASS_DEFINE_CHUNK_NAME.Start,
|
[CLASS_DEFINE_CHUNK_NAME.StaticMethod]: [CLASS_DEFINE_CHUNK_NAME.Start, CLASS_DEFINE_CHUNK_NAME.StaticVar],
|
||||||
],
|
|
||||||
[CLASS_DEFINE_CHUNK_NAME.StaticMethod]: [
|
|
||||||
CLASS_DEFINE_CHUNK_NAME.Start,
|
|
||||||
CLASS_DEFINE_CHUNK_NAME.StaticVar,
|
|
||||||
],
|
|
||||||
[CLASS_DEFINE_CHUNK_NAME.InsVar]: [
|
[CLASS_DEFINE_CHUNK_NAME.InsVar]: [
|
||||||
CLASS_DEFINE_CHUNK_NAME.Start,
|
CLASS_DEFINE_CHUNK_NAME.Start,
|
||||||
CLASS_DEFINE_CHUNK_NAME.StaticVar,
|
CLASS_DEFINE_CHUNK_NAME.StaticVar,
|
||||||
@ -105,6 +103,7 @@ export const DEFAULT_LINK_AFTER = {
|
|||||||
[COMMON_CHUNK_NAME.FileMainContent]: [
|
[COMMON_CHUNK_NAME.FileMainContent]: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
CLASS_DEFINE_CHUNK_NAME.End,
|
CLASS_DEFINE_CHUNK_NAME.End,
|
||||||
@ -112,6 +111,7 @@ export const DEFAULT_LINK_AFTER = {
|
|||||||
[COMMON_CHUNK_NAME.FileExport]: [
|
[COMMON_CHUNK_NAME.FileExport]: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
CLASS_DEFINE_CHUNK_NAME.End,
|
CLASS_DEFINE_CHUNK_NAME.End,
|
||||||
@ -120,6 +120,6 @@ export const DEFAULT_LINK_AFTER = {
|
|||||||
[COMMON_CHUNK_NAME.StyleDepsImport]: [],
|
[COMMON_CHUNK_NAME.StyleDepsImport]: [],
|
||||||
[COMMON_CHUNK_NAME.StyleCssContent]: [COMMON_CHUNK_NAME.StyleDepsImport],
|
[COMMON_CHUNK_NAME.StyleCssContent]: [COMMON_CHUNK_NAME.StyleDepsImport],
|
||||||
[COMMON_CHUNK_NAME.HtmlContent]: [],
|
[COMMON_CHUNK_NAME.HtmlContent]: [],
|
||||||
}
|
};
|
||||||
|
|
||||||
export const COMMON_SUB_MODULE_NAME = 'index';
|
export const COMMON_SUB_MODULE_NAME = 'index';
|
||||||
|
|||||||
@ -39,9 +39,7 @@ const defaultContainer: IContainerInfo = {
|
|||||||
class SchemaParser implements ISchemaParser {
|
class SchemaParser implements ISchemaParser {
|
||||||
public validate(schema: IBasicSchema): boolean {
|
public validate(schema: IBasicSchema): boolean {
|
||||||
if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) {
|
if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) {
|
||||||
throw new CompatibilityError(
|
throw new CompatibilityError(`Not support schema with version [${schema.version}]`);
|
||||||
`Not support schema with version [${schema.version}]`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -65,19 +63,25 @@ class SchemaParser implements ISchemaParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 解析三方组件依赖
|
// 解析三方组件依赖
|
||||||
schema.componentsMap.forEach(info => {
|
schema.componentsMap.forEach((info) => {
|
||||||
info.dependencyType = DependencyType.External;
|
if (info.componentName) {
|
||||||
info.importName = info.componentName;
|
compDeps[info.componentName] = {
|
||||||
compDeps[info.componentName] = info;
|
...info,
|
||||||
|
dependencyType: DependencyType.External,
|
||||||
|
importName: info.componentName,
|
||||||
|
exportName: info.exportName ?? info.componentName,
|
||||||
|
version: info.version || '*',
|
||||||
|
destructuring: info.destructuring ?? false,
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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
|
const firstRoot: IContainerNodeItem = schema.componentsTree[0] as IContainerNodeItem;
|
||||||
.componentsTree[0] as IContainerNodeItem;
|
|
||||||
|
|
||||||
if (!firstRoot.fileName) {
|
if (!('fileName' in firstRoot) || !firstRoot.fileName) {
|
||||||
// 整个 schema 描述一个容器,且无根节点定义
|
// 整个 schema 描述一个容器,且无根节点定义
|
||||||
const container: IContainerInfo = {
|
const container: IContainerInfo = {
|
||||||
...defaultContainer,
|
...defaultContainer,
|
||||||
@ -86,8 +90,8 @@ class SchemaParser implements ISchemaParser {
|
|||||||
containers = [container];
|
containers = [container];
|
||||||
} else {
|
} else {
|
||||||
// 普通带 1 到多个容器的 schema
|
// 普通带 1 到多个容器的 schema
|
||||||
containers = schema.componentsTree.map(n => {
|
containers = schema.componentsTree.map((n) => {
|
||||||
const subRoot = n as IContainerNodeItem;
|
const subRoot = n;
|
||||||
const container: IContainerInfo = {
|
const container: IContainerInfo = {
|
||||||
...subRoot,
|
...subRoot,
|
||||||
containerType: subRoot.componentName,
|
containerType: subRoot.componentName,
|
||||||
@ -101,7 +105,7 @@ class SchemaParser implements ISchemaParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 建立所有容器的内部依赖索引
|
// 建立所有容器的内部依赖索引
|
||||||
containers.forEach(container => {
|
containers.forEach((container) => {
|
||||||
let type;
|
let type;
|
||||||
switch (container.containerType) {
|
switch (container.containerType) {
|
||||||
case 'Page':
|
case 'Page':
|
||||||
@ -127,31 +131,31 @@ class SchemaParser implements ISchemaParser {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 分析容器内部组件依赖
|
// 分析容器内部组件依赖
|
||||||
containers.forEach(container => {
|
containers.forEach((container) => {
|
||||||
if (container.children) {
|
if (container.children) {
|
||||||
// const depNames = this.getComponentNames(container.children);
|
// const depNames = this.getComponentNames(container.children);
|
||||||
// container.deps = uniqueArray<string>(depNames)
|
// container.deps = uniqueArray<string>(depNames)
|
||||||
// .map(depName => internalDeps[depName] || compDeps[depName])
|
// .map(depName => internalDeps[depName] || compDeps[depName])
|
||||||
// .filter(dep => !!dep);
|
// .filter(dep => !!dep);
|
||||||
container.deps = Object.keys(compDeps).map(
|
container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]);
|
||||||
depName => compDeps[depName],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const containersDeps = ([] as IDependency[]).concat(...containers.map(c => c.deps || []));
|
const containersDeps = ([] as IDependency[]).concat(...containers.map((c) => c.deps || []));
|
||||||
|
|
||||||
// 分析路由配置
|
// 分析路由配置
|
||||||
|
// TODO: 低代码规范里面的路由是咋弄的?
|
||||||
const routes = containers
|
const routes = containers
|
||||||
.filter(container => container.containerType === 'Page')
|
.filter((container) => container.containerType === 'Page')
|
||||||
.map(page => {
|
.map((page) => {
|
||||||
const meta = page.meta as IPageMeta;
|
const meta = (page as { meta?: IPageMeta }).meta as IPageMeta;
|
||||||
if (meta) {
|
if (meta) {
|
||||||
return {
|
return {
|
||||||
path: meta.router,
|
path: meta.router,
|
||||||
componentName: page.moduleName,
|
componentName: page.moduleName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
path: '',
|
path: '',
|
||||||
componentName: page.moduleName,
|
componentName: page.moduleName,
|
||||||
@ -159,16 +163,14 @@ class SchemaParser implements ISchemaParser {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const routerDeps = routes
|
const routerDeps = routes
|
||||||
.map(r => internalDeps[r.componentName] || compDeps[r.componentName])
|
.map((r) => internalDeps[r.componentName] || compDeps[r.componentName])
|
||||||
.filter(dep => !!dep);
|
.filter((dep) => !!dep);
|
||||||
|
|
||||||
// 分析 Utils 依赖
|
// 分析 Utils 依赖
|
||||||
let utils: IUtilItem[];
|
let utils: IUtilItem[];
|
||||||
if (schema.utils) {
|
if (schema.utils) {
|
||||||
utils = schema.utils;
|
utils = schema.utils;
|
||||||
utilsDeps = schema.utils
|
utilsDeps = schema.utils.filter((u) => u.type !== 'function').map((u) => u.content as IExternalDependency);
|
||||||
.filter(u => u.type !== 'function')
|
|
||||||
.map(u => u.content as IExternalDependency);
|
|
||||||
} else {
|
} else {
|
||||||
utils = [];
|
utils = [];
|
||||||
}
|
}
|
||||||
@ -197,7 +199,7 @@ class SchemaParser implements ISchemaParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getComponentNames(children: ChildNodeType): string[] {
|
public getComponentNames(children: ChildNodeType): string[] {
|
||||||
return handleChildren<string>(children, {
|
return handleChildren(children, {
|
||||||
node: (i: IComponentNodeItem) => [i.componentName],
|
node: (i: IComponentNodeItem) => [i.componentName],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,12 +25,9 @@ function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
|
|||||||
depMap[pkg].push(dep);
|
depMap[pkg].push(dep);
|
||||||
};
|
};
|
||||||
|
|
||||||
deps.forEach(dep => {
|
deps.forEach((dep) => {
|
||||||
if (dep.dependencyType === DependencyType.Internal) {
|
if (dep.dependencyType === DependencyType.Internal) {
|
||||||
addDep(
|
addDep(`${(dep as IInternalDependency).moduleName}${dep.main || ''}`, dep);
|
||||||
`${(dep as IInternalDependency).moduleName}${dep.main || ''}`,
|
|
||||||
dep,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
addDep(`${(dep as IExternalDependency).package}${dep.main || ''}`, dep);
|
addDep(`${(dep as IExternalDependency).package}${dep.main || ''}`, dep);
|
||||||
}
|
}
|
||||||
@ -39,17 +36,13 @@ function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
|
|||||||
return depMap;
|
return depMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildPackageImport(
|
function buildPackageImport(pkg: string, deps: IDependency[], targetFileType: string): ICodeChunk[] {
|
||||||
pkg: string,
|
|
||||||
deps: IDependency[],
|
|
||||||
targetFileType: string,
|
|
||||||
): ICodeChunk[] {
|
|
||||||
const chunks: ICodeChunk[] = [];
|
const chunks: ICodeChunk[] = [];
|
||||||
let defaultImport: string = '';
|
let defaultImport: string = '';
|
||||||
let defaultImportAs: string = '';
|
let defaultImportAs: string = '';
|
||||||
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.importName || dep.exportName;
|
||||||
if (dep.subName) {
|
if (dep.subName) {
|
||||||
@ -60,12 +53,14 @@ function buildPackageImport(
|
|||||||
chunks.push({
|
chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: targetFileType,
|
fileType: targetFileType,
|
||||||
name: COMMON_CHUNK_NAME.FileVarDefine,
|
name: COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
content: `const ${targetName} = ${srcName}.${dep.subName};`,
|
content: `const ${targetName} = ${srcName}.${dep.subName};`,
|
||||||
linkAfter: [
|
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport],
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
ext: {
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
originalName: `${srcName}.${dep.subName}`,
|
||||||
],
|
aliasName: targetName,
|
||||||
|
dependency: dep,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
targetName = srcName;
|
targetName = srcName;
|
||||||
@ -74,18 +69,26 @@ function buildPackageImport(
|
|||||||
if (dep.destructuring) {
|
if (dep.destructuring) {
|
||||||
imports[srcName] = targetName;
|
imports[srcName] = targetName;
|
||||||
} else if (defaultImport) {
|
} else if (defaultImport) {
|
||||||
throw new CodeGeneratorError(
|
// 有些时候,可能已经从某个包里引入了一个东东,但是希望能再起个别名,这时候用赋值语句代替
|
||||||
`[${pkg}] has more than one default export.`,
|
chunks.push({
|
||||||
);
|
type: ChunkType.STRING,
|
||||||
|
fileType: targetFileType,
|
||||||
|
name: COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
|
content: `const ${targetName} = ${defaultImportAs};`,
|
||||||
|
linkAfter: [COMMON_CHUNK_NAME.InternalDepsImport, COMMON_CHUNK_NAME.ExternalDepsImport],
|
||||||
|
ext: {
|
||||||
|
originalName: defaultImportAs,
|
||||||
|
aliasName: targetName,
|
||||||
|
dependency: dep,
|
||||||
|
},
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
defaultImport = srcName;
|
defaultImport = srcName;
|
||||||
defaultImportAs = targetName;
|
defaultImportAs = targetName;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const items = Object.keys(imports).map(src =>
|
const items = Object.keys(imports).map((src) => (src === imports[src] ? src : `${src} as ${imports[src]}`));
|
||||||
src === imports[src] ? src : `${src} as ${imports[src]}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const statementL = ['import'];
|
const statementL = ['import'];
|
||||||
if (defaultImport) {
|
if (defaultImport) {
|
||||||
@ -125,7 +128,7 @@ function buildPackageImport(
|
|||||||
|
|
||||||
type PluginConfig = {
|
type PluginConfig = {
|
||||||
fileType: string;
|
fileType: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?: PluginConfig) => {
|
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?: PluginConfig) => {
|
||||||
const cfg: PluginConfig = {
|
const cfg: PluginConfig = {
|
||||||
@ -143,9 +146,9 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?: Plu
|
|||||||
if (ir && ir.deps && ir.deps.length > 0) {
|
if (ir && ir.deps && ir.deps.length > 0) {
|
||||||
const packs = groupDepsByPack(ir.deps);
|
const packs = groupDepsByPack(ir.deps);
|
||||||
|
|
||||||
Object.keys(packs).forEach(pkg => {
|
Object.keys(packs).forEach((pkg) => {
|
||||||
const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType);
|
const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType);
|
||||||
next.chunks.push.apply(next.chunks, chunks);
|
next.chunks.push(...chunks);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
export const RAX_CHUNK_NAME = {
|
export const RAX_CHUNK_NAME = {
|
||||||
ClassDidMountStart: 'RaxComponentClassDidMountStart',
|
ClassDidMountBegin: 'RaxComponentClassDidMountBegin',
|
||||||
ClassDidMountContent: 'RaxComponentClassDidMountContent',
|
ClassDidMountContent: 'RaxComponentClassDidMountContent',
|
||||||
ClassDidMountEnd: 'RaxComponentClassDidMountEnd',
|
ClassDidMountEnd: 'RaxComponentClassDidMountEnd',
|
||||||
ClassRenderStart: 'RaxComponentClassRenderStart',
|
ClassRenderBegin: 'RaxComponentClassRenderBegin',
|
||||||
ClassRenderPre: 'RaxComponentClassRenderPre',
|
ClassRenderPre: 'RaxComponentClassRenderPre',
|
||||||
ClassRenderJSX: 'RaxComponentClassRenderJSX',
|
ClassRenderJSX: 'RaxComponentClassRenderJSX',
|
||||||
ClassRenderEnd: 'RaxComponentClassRenderEnd',
|
ClassRenderEnd: 'RaxComponentClassRenderEnd',
|
||||||
|
MethodsBegin: 'RaxComponentMethodsBegin',
|
||||||
|
MethodsContent: 'RaxComponentMethodsContent',
|
||||||
|
MethodsEnd: 'RaxComponentMethodsEnd',
|
||||||
};
|
};
|
||||||
|
|||||||
@ -30,12 +30,12 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.JSX,
|
fileType: FileType.JSX,
|
||||||
@ -43,8 +43,9 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
content: `}`,
|
content: `}`,
|
||||||
linkAfter: [
|
linkAfter: [
|
||||||
CLASS_DEFINE_CHUNK_NAME.Start,
|
CLASS_DEFINE_CHUNK_NAME.Start,
|
||||||
RAX_CHUNK_NAME.ClassRenderEnd,
|
|
||||||
CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,
|
CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,
|
||||||
|
RAX_CHUNK_NAME.ClassRenderEnd,
|
||||||
|
RAX_CHUNK_NAME.MethodsEnd,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -70,13 +71,9 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.JSX,
|
fileType: FileType.JSX,
|
||||||
name: RAX_CHUNK_NAME.ClassDidMountStart,
|
name: RAX_CHUNK_NAME.ClassDidMountBegin,
|
||||||
content: `componentDidMount() {`,
|
content: `componentDidMount() {`,
|
||||||
linkAfter: [
|
linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start, CLASS_DEFINE_CHUNK_NAME.InsVar, CLASS_DEFINE_CHUNK_NAME.InsMethod],
|
||||||
CLASS_DEFINE_CHUNK_NAME.Start,
|
|
||||||
CLASS_DEFINE_CHUNK_NAME.InsVar,
|
|
||||||
CLASS_DEFINE_CHUNK_NAME.InsMethod,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
@ -84,20 +81,15 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
fileType: FileType.JSX,
|
fileType: FileType.JSX,
|
||||||
name: RAX_CHUNK_NAME.ClassDidMountEnd,
|
name: RAX_CHUNK_NAME.ClassDidMountEnd,
|
||||||
content: `}`,
|
content: `}`,
|
||||||
linkAfter: [
|
linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin, RAX_CHUNK_NAME.ClassDidMountContent],
|
||||||
RAX_CHUNK_NAME.ClassDidMountStart,
|
|
||||||
RAX_CHUNK_NAME.ClassDidMountContent,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.JSX,
|
fileType: FileType.JSX,
|
||||||
name: RAX_CHUNK_NAME.ClassRenderStart,
|
name: RAX_CHUNK_NAME.ClassRenderBegin,
|
||||||
content: 'render() {',
|
content: 'render() {',
|
||||||
linkAfter: [
|
linkAfter: [RAX_CHUNK_NAME.ClassDidMountEnd],
|
||||||
RAX_CHUNK_NAME.ClassDidMountEnd,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
@ -105,7 +97,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
fileType: FileType.JSX,
|
fileType: FileType.JSX,
|
||||||
name: RAX_CHUNK_NAME.ClassRenderEnd,
|
name: RAX_CHUNK_NAME.ClassRenderEnd,
|
||||||
content: '}',
|
content: '}',
|
||||||
linkAfter: [RAX_CHUNK_NAME.ClassRenderStart, RAX_CHUNK_NAME.ClassRenderPre, RAX_CHUNK_NAME.ClassRenderJSX],
|
linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin, RAX_CHUNK_NAME.ClassRenderPre, RAX_CHUNK_NAME.ClassRenderJSX],
|
||||||
});
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
@ -116,6 +108,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
CLASS_DEFINE_CHUNK_NAME.End,
|
CLASS_DEFINE_CHUNK_NAME.End,
|
||||||
|
|||||||
@ -1,52 +0,0 @@
|
|||||||
import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';
|
|
||||||
|
|
||||||
import { generateCompositeType } from '../../../utils/compositeType';
|
|
||||||
|
|
||||||
import {
|
|
||||||
BuilderComponentPlugin,
|
|
||||||
BuilderComponentPluginFactory,
|
|
||||||
ChunkType,
|
|
||||||
FileType,
|
|
||||||
ICodeStruct,
|
|
||||||
IContainerInfo,
|
|
||||||
} from '../../../types';
|
|
||||||
|
|
||||||
type PluginConfig = {
|
|
||||||
fileType: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
|
||||||
const cfg: PluginConfig = {
|
|
||||||
fileType: FileType.JSX,
|
|
||||||
...config,
|
|
||||||
};
|
|
||||||
|
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
|
||||||
const next: ICodeStruct = {
|
|
||||||
...pre,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ir = next.ir as IContainerInfo;
|
|
||||||
|
|
||||||
if (ir.state) {
|
|
||||||
const state = ir.state;
|
|
||||||
const fields = Object.keys(state).map<string>(stateName => {
|
|
||||||
const [isString, value] = generateCompositeType(state[stateName]);
|
|
||||||
return `${stateName}: ${isString ? `'${value}'` : value},`;
|
|
||||||
});
|
|
||||||
|
|
||||||
next.chunks.push({
|
|
||||||
type: ChunkType.STRING,
|
|
||||||
fileType: cfg.fileType,
|
|
||||||
name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
|
|
||||||
content: `this.state = { ${fields.join('')} };`,
|
|
||||||
linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
|
||||||
};
|
|
||||||
return plugin;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default pluginFactory;
|
|
||||||
@ -14,12 +14,12 @@ 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 = {
|
||||||
fileType: FileType.JSX,
|
fileType: FileType.JSX,
|
||||||
implementType: 'inConstructor',
|
implementType: 'insMember',
|
||||||
...config,
|
...config,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,8 +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]);
|
// TODO: 这里用什么 handlers?
|
||||||
|
const [isString, value] = generateCompositeType(state[stateName], {});
|
||||||
return `${stateName}: ${isString ? `'${value}'` : value},`;
|
return `${stateName}: ${isString ? `'${value}'` : value},`;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],
|
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// TODO: hooks state??
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|||||||
@ -54,11 +54,11 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
content: `
|
content: `
|
||||||
this._dataSourceEngine.reloadDataSource();
|
this._dataSourceEngine.reloadDataSource();
|
||||||
`,
|
`,
|
||||||
linkAfter: [RAX_CHUNK_NAME.ClassDidMountStart],
|
linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin],
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataSource = isContainerSchema(pre.ir) ? pre.ir.dataSource : null;
|
const dataSource = isContainerSchema(pre.ir) ? pre.ir.dataSource : null;
|
||||||
const dataSourceItems: DataSourceConfig[] = dataSource && dataSource.list || [];
|
const dataSourceItems: DataSourceConfig[] = (dataSource && dataSource.list) || [];
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';
|
import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
@ -11,7 +11,7 @@ import { RAX_CHUNK_NAME } from './const';
|
|||||||
|
|
||||||
type PluginConfig = {
|
type PluginConfig = {
|
||||||
fileType: string;
|
fileType: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
||||||
const cfg: PluginConfig = {
|
const cfg: PluginConfig = {
|
||||||
@ -24,7 +24,17 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
...pre,
|
...pre,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: utils 怎么注入?
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
// TODO: 下面这个路径有没有更好的方式来获取?而非写死
|
||||||
|
content: `
|
||||||
|
import __$$projectUtils from '../../utils';
|
||||||
|
`,
|
||||||
|
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
|
||||||
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: cfg.fileType,
|
fileType: cfg.fileType,
|
||||||
@ -33,18 +43,29 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],
|
linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Page methods...
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: cfg.fileType,
|
fileType: cfg.fileType,
|
||||||
name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,
|
name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,
|
||||||
|
|
||||||
|
// 绑定下上下文,这样在所有的 utils 里面都能通过 this.xxx 来访问上下文了
|
||||||
|
// TODO: 要不要优化为通过 Proxy 的方式懒绑定?
|
||||||
content: `
|
content: `
|
||||||
_defineUtils() {
|
_defineUtils() {
|
||||||
return {};
|
const utils = {
|
||||||
|
...__$$projectUtils,
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.entries(utils).forEach(([name, util]) => {
|
||||||
|
if (typeof util === 'function') {
|
||||||
|
utils[name] = util.bind(this._context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return utils;
|
||||||
}`,
|
}`,
|
||||||
linkAfter: [
|
linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],
|
||||||
RAX_CHUNK_NAME.ClassRenderEnd
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
|
import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
|
||||||
import { RAX_CHUNK_NAME } from './const';
|
import { RAX_CHUNK_NAME } from './const';
|
||||||
|
|
||||||
import {
|
import { getFuncExprBody, transformFuncExpr2MethodMember } from '../../../utils/jsExpression';
|
||||||
getFuncExprBody,
|
|
||||||
transformFuncExpr2MethodMember,
|
|
||||||
} from '../../../utils/jsExpression';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
@ -22,7 +19,7 @@ type PluginConfig = {
|
|||||||
fileType: string;
|
fileType: string;
|
||||||
exportNameMapping: Record<string, string>;
|
exportNameMapping: Record<string, string>;
|
||||||
normalizeNameMapping: Record<string, string>;
|
normalizeNameMapping: Record<string, string>;
|
||||||
}
|
};
|
||||||
|
|
||||||
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
||||||
const cfg: PluginConfig = {
|
const cfg: PluginConfig = {
|
||||||
@ -37,50 +34,53 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
...pre,
|
...pre,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ir = next.ir as IContainerInfo;
|
// TODO: Rax 程序的生命周期暂未明确,此处先屏蔽
|
||||||
|
// @see https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5
|
||||||
|
|
||||||
if (ir.lifeCycles) {
|
// const ir = next.ir as IContainerInfo;
|
||||||
const lifeCycles = ir.lifeCycles;
|
|
||||||
const chunks = Object.keys(lifeCycles).map<ICodeChunk>(lifeCycleName => {
|
|
||||||
const normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName;
|
|
||||||
const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName;
|
|
||||||
if (normalizeName === 'constructor') {
|
|
||||||
return {
|
|
||||||
type: ChunkType.STRING,
|
|
||||||
fileType: cfg.fileType,
|
|
||||||
name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
|
|
||||||
content: getFuncExprBody(
|
|
||||||
(lifeCycles[lifeCycleName] as IJSExpression).value,
|
|
||||||
),
|
|
||||||
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (normalizeName === 'render') {
|
|
||||||
return {
|
|
||||||
type: ChunkType.STRING,
|
|
||||||
fileType: cfg.fileType,
|
|
||||||
name: RAX_CHUNK_NAME.ClassRenderPre,
|
|
||||||
content: getFuncExprBody(
|
|
||||||
(lifeCycles[lifeCycleName] as IJSExpression).value,
|
|
||||||
),
|
|
||||||
linkAfter: [RAX_CHUNK_NAME.ClassRenderStart],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
// if (ir.lifeCycles) {
|
||||||
type: ChunkType.STRING,
|
// const lifeCycles = ir.lifeCycles;
|
||||||
fileType: cfg.fileType,
|
// const chunks = Object.keys(lifeCycles).map<ICodeChunk>(lifeCycleName => {
|
||||||
name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
|
// const normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName;
|
||||||
content: transformFuncExpr2MethodMember(
|
// const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName;
|
||||||
exportName,
|
// if (normalizeName === 'constructor') {
|
||||||
(lifeCycles[lifeCycleName] as IJSExpression).value,
|
// return {
|
||||||
),
|
// type: ChunkType.STRING,
|
||||||
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
|
// fileType: cfg.fileType,
|
||||||
};
|
// name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
|
||||||
});
|
// content: getFuncExprBody(
|
||||||
|
// (lifeCycles[lifeCycleName] as IJSExpression).value,
|
||||||
|
// ),
|
||||||
|
// linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]],
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// if (normalizeName === 'render') {
|
||||||
|
// return {
|
||||||
|
// type: ChunkType.STRING,
|
||||||
|
// fileType: cfg.fileType,
|
||||||
|
// name: RAX_CHUNK_NAME.ClassRenderPre,
|
||||||
|
// content: getFuncExprBody(
|
||||||
|
// (lifeCycles[lifeCycleName] as IJSExpression).value,
|
||||||
|
// ),
|
||||||
|
// linkAfter: [RAX_CHUNK_NAME.ClassRenderStart],
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
next.chunks.push.apply(next.chunks, chunks);
|
// return {
|
||||||
}
|
// type: ChunkType.STRING,
|
||||||
|
// fileType: cfg.fileType,
|
||||||
|
// name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
|
||||||
|
// content: transformFuncExpr2MethodMember(
|
||||||
|
// exportName,
|
||||||
|
// (lifeCycles[lifeCycleName] as IJSExpression).value,
|
||||||
|
// ),
|
||||||
|
// linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// next.chunks.push.apply(next.chunks, chunks);
|
||||||
|
// }
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,54 +0,0 @@
|
|||||||
import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
|
|
||||||
|
|
||||||
import { transformFuncExpr2MethodMember } from '../../../utils/jsExpression';
|
|
||||||
|
|
||||||
import {
|
|
||||||
BuilderComponentPlugin,
|
|
||||||
BuilderComponentPluginFactory,
|
|
||||||
ChunkType,
|
|
||||||
FileType,
|
|
||||||
ICodeChunk,
|
|
||||||
ICodeStruct,
|
|
||||||
IContainerInfo,
|
|
||||||
IJSExpression,
|
|
||||||
} from '../../../types';
|
|
||||||
|
|
||||||
type PluginConfig = {
|
|
||||||
fileType: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
|
||||||
const cfg: PluginConfig = {
|
|
||||||
fileType: FileType.JSX,
|
|
||||||
...config,
|
|
||||||
};
|
|
||||||
|
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
|
||||||
const next: ICodeStruct = {
|
|
||||||
...pre,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ir = next.ir as IContainerInfo;
|
|
||||||
|
|
||||||
if (ir.methods) {
|
|
||||||
const methods = ir.methods;
|
|
||||||
const chunks = Object.keys(methods).map<ICodeChunk>(methodName => ({
|
|
||||||
type: ChunkType.STRING,
|
|
||||||
fileType: cfg.fileType,
|
|
||||||
name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
|
|
||||||
content: transformFuncExpr2MethodMember(
|
|
||||||
methodName,
|
|
||||||
(methods[methodName] as IJSExpression).value,
|
|
||||||
),
|
|
||||||
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
|
|
||||||
}));
|
|
||||||
|
|
||||||
next.chunks.push.apply(next.chunks, chunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
|
||||||
};
|
|
||||||
return plugin;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default pluginFactory;
|
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BuilderComponentPlugin,
|
||||||
|
BuilderComponentPluginFactory,
|
||||||
|
ChunkType,
|
||||||
|
FileType,
|
||||||
|
ICodeStruct,
|
||||||
|
IContainerInfo,
|
||||||
|
} from '../../../types';
|
||||||
|
|
||||||
|
import { RAX_CHUNK_NAME } from './const';
|
||||||
|
|
||||||
|
type PluginConfig = {
|
||||||
|
fileType: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
||||||
|
const cfg: PluginConfig = {
|
||||||
|
fileType: FileType.JSX,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
|
||||||
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
const next: ICodeStruct = {
|
||||||
|
...pre,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ir = next.ir as IContainerInfo;
|
||||||
|
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: CLASS_DEFINE_CHUNK_NAME.InsVar,
|
||||||
|
content: `
|
||||||
|
_methods = this._defineMethods();
|
||||||
|
`,
|
||||||
|
linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],
|
||||||
|
});
|
||||||
|
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: RAX_CHUNK_NAME.MethodsBegin,
|
||||||
|
content: `
|
||||||
|
_defineMethods() {
|
||||||
|
return ({
|
||||||
|
`,
|
||||||
|
linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd, CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod],
|
||||||
|
});
|
||||||
|
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: RAX_CHUNK_NAME.MethodsEnd,
|
||||||
|
content: `
|
||||||
|
});
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
linkAfter: [RAX_CHUNK_NAME.MethodsBegin, RAX_CHUNK_NAME.MethodsContent],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ir.methods && Object.keys(ir.methods).length > 0) {
|
||||||
|
Object.entries(ir.methods).forEach(([methodName, methodDefine]) => {
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: RAX_CHUNK_NAME.MethodsContent,
|
||||||
|
content: `${methodName}: (${methodDefine.value}),`,
|
||||||
|
linkAfter: [RAX_CHUNK_NAME.MethodsBegin],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
};
|
||||||
|
return plugin;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default pluginFactory;
|
||||||
@ -3,25 +3,44 @@ import {
|
|||||||
BuilderComponentPluginFactory,
|
BuilderComponentPluginFactory,
|
||||||
ChunkType,
|
ChunkType,
|
||||||
FileType,
|
FileType,
|
||||||
|
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';
|
||||||
|
import { COMMON_CHUNK_NAME } from '../../../const/generator';
|
||||||
|
|
||||||
import { createReactNodeGenerator } from '../../../utils/nodeToJSX';
|
import { createNodeGenerator, generateReactCtrlLine, generateString } from '../../../utils/nodeToJSX';
|
||||||
|
import { generateExpression } from '../../../utils/jsExpression';
|
||||||
|
|
||||||
type PluginConfig = {
|
type PluginConfig = {
|
||||||
fileType: string;
|
fileType: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// TODO: componentName 若并非大写字符打头,甚至并非是一个有效的 JS 标识符怎么办??
|
||||||
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
|
||||||
const cfg: PluginConfig = {
|
const cfg: PluginConfig = {
|
||||||
fileType: FileType.JSX,
|
fileType: FileType.JSX,
|
||||||
...config,
|
...config,
|
||||||
};
|
};
|
||||||
|
|
||||||
const generator = createReactNodeGenerator();
|
const transformers = {
|
||||||
|
transformThis2Context,
|
||||||
|
transformJsExpr: (expr: string) =>
|
||||||
|
isLiteralAtomicExpr(expr) ? expr : `__$$eval(() => (${transformThis2Context(expr)}))`,
|
||||||
|
transformLoopExpr: (expr: string) => `__$$evalArray(() => (${transformThis2Context(expr)}))`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
expression: (input: JSExpression) => transformers.transformJsExpr(generateExpression(input)),
|
||||||
|
function: (input: JSFunction) => transformers.transformJsExpr(input.value || 'null'),
|
||||||
|
};
|
||||||
|
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
const next: ICodeStruct = {
|
const next: ICodeStruct = {
|
||||||
@ -29,22 +48,122 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ir = next.ir as IContainerInfo;
|
const ir = next.ir as IContainerInfo;
|
||||||
|
|
||||||
|
// Rax 构建到小程序的时候,不能给组件起起别名,得直接引用,故这里将所有的别名替换掉
|
||||||
|
// 先收集下所有的 alias 的映射
|
||||||
|
const componentsNameAliasMap = new Map<string, string>();
|
||||||
|
next.chunks.forEach((chunk) => {
|
||||||
|
if (isImportAliasDefineChunk(chunk)) {
|
||||||
|
componentsNameAliasMap.set(chunk.ext.aliasName, chunk.ext.originalName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapComponentNameToAliasOrKeepIt = (componentName: string) =>
|
||||||
|
componentsNameAliasMap.get(componentName) || componentName;
|
||||||
|
|
||||||
|
// 然后过滤掉所有的别名 chunks
|
||||||
|
next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk));
|
||||||
|
|
||||||
|
// 创建代码生成器
|
||||||
|
const generator = createNodeGenerator(
|
||||||
|
{
|
||||||
|
string: generateString,
|
||||||
|
expression: (input) => [handlers.expression(input)],
|
||||||
|
function: (input) => [handlers.function(input)],
|
||||||
|
},
|
||||||
|
[generateReactCtrlLine],
|
||||||
|
{
|
||||||
|
expression: (input) => (isJSExpression(input) ? handlers.expression(input) : ''),
|
||||||
|
function: (input) => (isJSFunction(input) ? handlers.function(input) : ''),
|
||||||
|
loopDataExpr: (input) => (typeof input === 'string' ? transformers.transformLoopExpr(input) : ''),
|
||||||
|
tagName: mapComponentNameToAliasOrKeepIt,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// 生成 JSX 代码
|
||||||
const jsxContent = generator(ir);
|
const jsxContent = generator(ir);
|
||||||
|
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: RAX_CHUNK_NAME.ClassRenderPre,
|
||||||
|
content: `const __$$context = this._context;`,
|
||||||
|
linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin],
|
||||||
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: cfg.fileType,
|
fileType: cfg.fileType,
|
||||||
name: RAX_CHUNK_NAME.ClassRenderJSX,
|
name: RAX_CHUNK_NAME.ClassRenderJSX,
|
||||||
content: `return ${jsxContent};`,
|
content: `return ${jsxContent};`,
|
||||||
linkAfter: [
|
linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin, RAX_CHUNK_NAME.ClassRenderPre],
|
||||||
RAX_CHUNK_NAME.ClassRenderStart,
|
});
|
||||||
RAX_CHUNK_NAME.ClassRenderPre,
|
|
||||||
],
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: COMMON_CHUNK_NAME.CustomContent,
|
||||||
|
content: `
|
||||||
|
|
||||||
|
function __$$eval(expr) {
|
||||||
|
try {
|
||||||
|
return expr();
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Failed to evaluate: ', expr, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __$$evalArray(expr) {
|
||||||
|
const res = __$$eval(expr);
|
||||||
|
return Array.isArray(res) ? res : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
`,
|
||||||
|
linkAfter: [COMMON_CHUNK_NAME.FileExport],
|
||||||
});
|
});
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
};
|
};
|
||||||
|
|
||||||
return plugin;
|
return plugin;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default pluginFactory;
|
export default pluginFactory;
|
||||||
|
|
||||||
|
function isImportAliasDefineChunk(
|
||||||
|
chunk: ICodeChunk,
|
||||||
|
): chunk is ICodeChunk & {
|
||||||
|
ext: {
|
||||||
|
aliasName: string;
|
||||||
|
originalName: string;
|
||||||
|
dependency: NpmInfo;
|
||||||
|
};
|
||||||
|
} {
|
||||||
|
return (
|
||||||
|
chunk.name === COMMON_CHUNK_NAME.ImportAliasDefine &&
|
||||||
|
!!chunk.ext &&
|
||||||
|
typeof chunk.ext.aliasName === 'string' &&
|
||||||
|
typeof chunk.ext.originalName === 'string' &&
|
||||||
|
!!(chunk.ext.dependency as NpmInfo | null)?.componentName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否是原子类型的表达式
|
||||||
|
*/
|
||||||
|
function isLiteralAtomicExpr(expr: string): boolean {
|
||||||
|
return expr === 'null' || expr === 'undefined' || expr === 'true' || expr === 'false' || /^\d+$/.test(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将所有的 this.xxx 替换为 __$$context.xxx
|
||||||
|
* @param expr
|
||||||
|
*/
|
||||||
|
function transformThis2Context(expr: string): string {
|
||||||
|
// TODO: 应该根据语法分析来搞
|
||||||
|
// TODO: 如何替换自定义名字的循环变量?(generateReactCtrlLine)
|
||||||
|
return expr
|
||||||
|
.replace(/\bthis\.item\./, () => 'item.')
|
||||||
|
.replace(/\bthis\.index\./, () => 'index.')
|
||||||
|
.replace(/\bthis\./, () => '__$$context.');
|
||||||
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
],
|
],
|
||||||
@ -97,6 +98,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
CLASS_DEFINE_CHUNK_NAME.End,
|
CLASS_DEFINE_CHUNK_NAME.End,
|
||||||
|
|||||||
@ -7,16 +7,15 @@ import {
|
|||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IContainerInfo,
|
IContainerInfo,
|
||||||
IJSExpression,
|
|
||||||
CompositeValue,
|
CompositeValue,
|
||||||
|
JSExpression,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
|
|
||||||
import { generateCompositeType, handleStringValueDefault } from '../../../utils/compositeType';
|
import { generateCompositeType, handleStringValueDefault } from '../../../utils/compositeType';
|
||||||
import { generateExpression } from '../../../utils/jsExpression';
|
import { generateExpression } from '../../../utils/jsExpression';
|
||||||
|
|
||||||
function packJsExpression(exp: unknown): string {
|
function packJsExpression(exp: JSExpression): string {
|
||||||
const expression = exp as IJSExpression;
|
const funcStr = generateExpression(exp);
|
||||||
const funcStr = generateExpression(expression);
|
|
||||||
return `function() { return (${funcStr}); }`;
|
return `function() { return (${funcStr}); }`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,14 +28,11 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
const ir = next.ir as IContainerInfo;
|
const ir = next.ir as IContainerInfo;
|
||||||
if (ir.dataSource) {
|
if (ir.dataSource) {
|
||||||
const { dataSource } = ir;
|
const { dataSource } = ir;
|
||||||
const {
|
const { list, ...rest } = dataSource;
|
||||||
list,
|
|
||||||
...rest
|
|
||||||
} = dataSource;
|
|
||||||
|
|
||||||
let attrs: string[] = [];
|
let attrs: string[] = [];
|
||||||
|
|
||||||
const extConfigs = Object.keys(rest).map(extConfigName => {
|
const extConfigs = Object.keys(rest).map((extConfigName) => {
|
||||||
const value = (rest as Record<string, CompositeValue>)[extConfigName];
|
const value = (rest as Record<string, CompositeValue>)[extConfigName];
|
||||||
const [isString, valueStr] = generateCompositeType(value);
|
const [isString, valueStr] = generateCompositeType(value);
|
||||||
return `${extConfigName}: ${isString ? `'${valueStr}'` : valueStr}`;
|
return `${extConfigName}: ${isString ? `'${valueStr}'` : valueStr}`;
|
||||||
@ -44,9 +40,11 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
|
|
||||||
attrs = [...attrs, ...extConfigs];
|
attrs = [...attrs, ...extConfigs];
|
||||||
|
|
||||||
const listProp = handleStringValueDefault(generateCompositeType(list as unknown as CompositeValue, {
|
const listProp = handleStringValueDefault(
|
||||||
|
generateCompositeType((list as unknown) as CompositeValue, {
|
||||||
expression: packJsExpression,
|
expression: packJsExpression,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
attrs.push(`list: ${listProp}`);
|
attrs.push(`list: ${listProp}`);
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
COMMON_CHUNK_NAME.FileMainContent,
|
COMMON_CHUNK_NAME.FileMainContent,
|
||||||
|
|||||||
@ -45,6 +45,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -39,7 +39,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
children: [
|
children: [
|
||||||
${ir.routes
|
${ir.routes
|
||||||
.map(
|
.map(
|
||||||
route => `
|
(route) => `
|
||||||
{
|
{
|
||||||
path: '${route.path}',
|
path: '${route.path}',
|
||||||
component: ${route.componentName},
|
component: ${route.componentName},
|
||||||
@ -54,6 +54,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -69,6 +70,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileMainContent,
|
COMMON_CHUNK_NAME.FileMainContent,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -38,6 +38,7 @@ runApp(appConfig);
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -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,
|
||||||
@ -36,6 +36,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
],
|
],
|
||||||
@ -54,6 +55,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
COMMON_CHUNK_NAME.FileMainContent,
|
COMMON_CHUNK_NAME.FileMainContent,
|
||||||
|
|||||||
@ -28,24 +28,26 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
COMMON_CHUNK_NAME.FileMainContent,
|
COMMON_CHUNK_NAME.FileMainContent,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
ir.utils.forEach(util => {
|
ir.utils.forEach((util) => {
|
||||||
if (util.type === 'function') {
|
if (util.type === 'function') {
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.JS,
|
fileType: FileType.JS,
|
||||||
name: COMMON_CHUNK_NAME.FileVarDefine,
|
name: COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
content: `
|
content: `
|
||||||
const ${util.name} = ${util.content};
|
const ${util.name} = ${util.content.value};
|
||||||
`,
|
`,
|
||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -54,12 +56,11 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.JS,
|
fileType: FileType.JS,
|
||||||
name: COMMON_CHUNK_NAME.FileExport,
|
name: COMMON_CHUNK_NAME.FileExport,
|
||||||
content: `
|
content: `${util.name},`,
|
||||||
${util.name},
|
|
||||||
`,
|
|
||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
COMMON_CHUNK_NAME.FileMainContent,
|
COMMON_CHUNK_NAME.FileMainContent,
|
||||||
@ -77,6 +78,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
linkAfter: [
|
linkAfter: [
|
||||||
COMMON_CHUNK_NAME.ExternalDepsImport,
|
COMMON_CHUNK_NAME.ExternalDepsImport,
|
||||||
COMMON_CHUNK_NAME.InternalDepsImport,
|
COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
COMMON_CHUNK_NAME.ImportAliasDefine,
|
||||||
COMMON_CHUNK_NAME.FileVarDefine,
|
COMMON_CHUNK_NAME.FileVarDefine,
|
||||||
COMMON_CHUNK_NAME.FileUtilDefine,
|
COMMON_CHUNK_NAME.FileUtilDefine,
|
||||||
COMMON_CHUNK_NAME.FileMainContent,
|
COMMON_CHUNK_NAME.FileMainContent,
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import { createProjectBuilder } from '../generator/ProjectBuilder';
|
|||||||
|
|
||||||
import esModule from '../plugins/common/esmodule';
|
import esModule from '../plugins/common/esmodule';
|
||||||
import containerClass from '../plugins/component/rax/containerClass';
|
import containerClass from '../plugins/component/rax/containerClass';
|
||||||
import containerLifeCycle from '../plugins/component/rax/containerLifeCycle';
|
import containerLifeCycles from '../plugins/component/rax/containerLifeCycle';
|
||||||
import containerMethod from '../plugins/component/rax/containerMethod';
|
import containerMethods from '../plugins/component/rax/containerMethods';
|
||||||
import containerInitState from '../plugins/component/rax/containerInitState';
|
import containerInitState from '../plugins/component/rax/containerInitState';
|
||||||
import containerInjectContext from '../plugins/component/rax/containerInjectContext';
|
import containerInjectContext from '../plugins/component/rax/containerInjectContext';
|
||||||
import containerInjectDataSourceEngine from '../plugins/component/rax/containerInjectDataSourceEngine';
|
import containerInjectDataSourceEngine from '../plugins/component/rax/containerInjectDataSourceEngine';
|
||||||
@ -27,29 +27,27 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
|
|||||||
plugins: {
|
plugins: {
|
||||||
components: [
|
components: [
|
||||||
commonDeps(),
|
commonDeps(),
|
||||||
esModule({
|
esModule({ fileType: 'jsx' }),
|
||||||
fileType: 'jsx',
|
|
||||||
}),
|
|
||||||
containerClass(),
|
containerClass(),
|
||||||
containerInjectUtils(),
|
|
||||||
containerInitState(),
|
containerInitState(),
|
||||||
containerLifeCycle(),
|
containerMethods(),
|
||||||
containerMethod(),
|
containerInjectContext(),
|
||||||
|
containerInjectDataSourceEngine(),
|
||||||
|
containerInjectUtils(),
|
||||||
|
containerLifeCycles(),
|
||||||
jsx(),
|
jsx(),
|
||||||
css(),
|
css(),
|
||||||
],
|
],
|
||||||
pages: [
|
pages: [
|
||||||
commonDeps(),
|
commonDeps(),
|
||||||
esModule({
|
esModule({ fileType: 'jsx' }),
|
||||||
fileType: 'jsx',
|
|
||||||
}),
|
|
||||||
containerClass(),
|
containerClass(),
|
||||||
containerInitState(),
|
containerInitState(),
|
||||||
|
containerMethods(),
|
||||||
containerInjectContext(),
|
containerInjectContext(),
|
||||||
containerInjectDataSourceEngine(),
|
containerInjectDataSourceEngine(),
|
||||||
containerInjectUtils(),
|
containerInjectUtils(),
|
||||||
containerLifeCycle(),
|
containerLifeCycles(),
|
||||||
containerMethod(),
|
|
||||||
jsx(),
|
jsx(),
|
||||||
css(),
|
css(),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,12 +1,6 @@
|
|||||||
import {
|
import { JSExpression, JSFunction, NodeSchema } from '@ali/lowcode-types';
|
||||||
IBasicSchema,
|
import { CustomHandlerSet } from '../utils/compositeType';
|
||||||
IParseResult,
|
import { IBasicSchema, IParseResult, IProjectSchema, IResultDir, IResultFile, IComponentNodeItem } from './index';
|
||||||
IProjectSchema,
|
|
||||||
IResultDir,
|
|
||||||
IResultFile,
|
|
||||||
IComponentNodeItem,
|
|
||||||
IJSExpression,
|
|
||||||
} from './index';
|
|
||||||
|
|
||||||
export enum FileType {
|
export enum FileType {
|
||||||
CSS = 'css',
|
CSS = 'css',
|
||||||
@ -42,6 +36,7 @@ export interface ICodeChunk {
|
|||||||
subModule?: string;
|
subModule?: string;
|
||||||
content: ChunkContent;
|
content: ChunkContent;
|
||||||
linkAfter: string[];
|
linkAfter: string[];
|
||||||
|
ext?: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBaseCodeStruct {
|
export interface IBaseCodeStruct {
|
||||||
@ -54,17 +49,12 @@ export interface ICodeStruct extends IBaseCodeStruct {
|
|||||||
chunks: ICodeChunk[];
|
chunks: ICodeChunk[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BuilderComponentPlugin = (
|
export type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise<ICodeStruct>;
|
||||||
initStruct: ICodeStruct,
|
|
||||||
) => Promise<ICodeStruct>;
|
|
||||||
|
|
||||||
export type BuilderComponentPluginFactory<T> = (config?: T) => BuilderComponentPlugin;
|
export type BuilderComponentPluginFactory<T> = (config?: T) => BuilderComponentPlugin;
|
||||||
|
|
||||||
export interface IChunkBuilder {
|
export interface IChunkBuilder {
|
||||||
run(
|
run(ir: any, initialStructure?: ICodeStruct): Promise<{ chunks: ICodeChunk[][] }>;
|
||||||
ir: any,
|
|
||||||
initialStructure?: ICodeStruct,
|
|
||||||
): Promise<{ chunks: ICodeChunk[][] }>;
|
|
||||||
getPlugins(): BuilderComponentPlugin[];
|
getPlugins(): BuilderComponentPlugin[];
|
||||||
addPlugin(plugin: BuilderComponentPlugin): void;
|
addPlugin(plugin: BuilderComponentPlugin): void;
|
||||||
}
|
}
|
||||||
@ -81,10 +71,7 @@ export interface ICompiledModule {
|
|||||||
export interface IModuleBuilder {
|
export interface IModuleBuilder {
|
||||||
generateModule(input: unknown): Promise<ICompiledModule>;
|
generateModule(input: unknown): Promise<ICompiledModule>;
|
||||||
generateModuleCode(schema: IBasicSchema | string): Promise<IResultDir>;
|
generateModuleCode(schema: IBasicSchema | string): Promise<IResultDir>;
|
||||||
linkCodeChunks(
|
linkCodeChunks(chunks: Record<string, ICodeChunk[]>, fileName: string): IResultFile[];
|
||||||
chunks: Record<string, ICodeChunk[]>,
|
|
||||||
fileName: string,
|
|
||||||
): IResultFile[];
|
|
||||||
addPlugin(plugin: BuilderComponentPlugin): void;
|
addPlugin(plugin: BuilderComponentPlugin): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,21 +142,23 @@ export enum PIECE_TYPE {
|
|||||||
ATTR = 'NodeCodePieceAttr',
|
ATTR = 'NodeCodePieceAttr',
|
||||||
CHILDREN = 'NodeCodePieceChildren',
|
CHILDREN = 'NodeCodePieceChildren',
|
||||||
AFTER = 'NodeCodePieceAfter',
|
AFTER = 'NodeCodePieceAfter',
|
||||||
};
|
}
|
||||||
|
|
||||||
export interface CodePiece {
|
export interface CodePiece {
|
||||||
value: string;
|
value: string;
|
||||||
type: PIECE_TYPE;
|
type: PIECE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: 这个 HandlerSet 和 CustomHandlerSet 为啥定义还不一样?
|
||||||
export interface HandlerSet<T> {
|
export interface HandlerSet<T> {
|
||||||
string?: (input: string) => T[];
|
string?: (input: string) => T[];
|
||||||
expression?: (input: IJSExpression) => T[];
|
expression?: (input: JSExpression) => T[];
|
||||||
node?: (input: IComponentNodeItem) => T[];
|
function?: (input: JSFunction) => T[];
|
||||||
|
node?: (input: NodeSchema) => T[];
|
||||||
common?: (input: unknown) => T[];
|
common?: (input: unknown) => T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExtGeneratorPlugin = (nodeItem: IComponentNodeItem) => CodePiece[];
|
export type ExtGeneratorPlugin = (nodeItem: IComponentNodeItem, handlers: CustomHandlerSet) => CodePiece[];
|
||||||
|
|
||||||
// export interface InteratorScope {
|
// export interface InteratorScope {
|
||||||
// [$item: string]: string; // $item 默认取值 "item"
|
// [$item: string]: string; // $item 默认取值 "item"
|
||||||
|
|||||||
@ -16,10 +16,11 @@ export interface IParseResult {
|
|||||||
project?: IProjectInfo;
|
project?: IProjectInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IContainerInfo extends IContainerNodeItem, IWithDependency {
|
export type IContainerInfo = IContainerNodeItem &
|
||||||
|
IWithDependency & {
|
||||||
containerType: string;
|
containerType: string;
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface IWithDependency {
|
export interface IWithDependency {
|
||||||
deps?: IDependency[];
|
deps?: IDependency[];
|
||||||
|
|||||||
@ -1,5 +1,19 @@
|
|||||||
// 搭建基础协议、搭建入料协议的数据规范
|
import {
|
||||||
import { IExternalDependency } from './index';
|
ProjectSchema,
|
||||||
|
CompositeObject,
|
||||||
|
JSExpression,
|
||||||
|
JSONObject,
|
||||||
|
NpmInfo,
|
||||||
|
NodeData,
|
||||||
|
NodeSchema,
|
||||||
|
UtilItem,
|
||||||
|
PageSchema,
|
||||||
|
BlockSchema,
|
||||||
|
ComponentSchema,
|
||||||
|
DataSourceConfig,
|
||||||
|
} from '@ali/lowcode-types';
|
||||||
|
|
||||||
|
export * from '@ali/lowcode-types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搭建基础协议 - 函数表达式
|
* 搭建基础协议 - 函数表达式
|
||||||
@ -7,37 +21,12 @@ import { IExternalDependency } from './index';
|
|||||||
* @export
|
* @export
|
||||||
* @interface IJSExpression
|
* @interface IJSExpression
|
||||||
*/
|
*/
|
||||||
export interface IJSExpression {
|
export type IJSExpression = JSExpression;
|
||||||
type: 'JSExpression';
|
|
||||||
value: string;
|
|
||||||
[extConfigName: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON 基本类型
|
// JSON 基本类型
|
||||||
export interface IJSONObject {
|
export type IJSONObject = JSONObject;
|
||||||
[key: string]: JSONValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type JSONValue =
|
export type ICompositeObject = CompositeObject;
|
||||||
| boolean
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| null
|
|
||||||
| JSONArray
|
|
||||||
| IJSONObject;
|
|
||||||
export type JSONArray = JSONValue[];
|
|
||||||
|
|
||||||
export type CompositeArray = CompositeValue[];
|
|
||||||
export interface ICompositeObject {
|
|
||||||
[key: string]: CompositeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复合类型
|
|
||||||
export type CompositeValue =
|
|
||||||
| JSONValue
|
|
||||||
| IJSExpression
|
|
||||||
| CompositeArray
|
|
||||||
| ICompositeObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搭建基础协议 - 多语言描述
|
* 搭建基础协议 - 多语言描述
|
||||||
@ -57,38 +46,20 @@ export interface II18nMap {
|
|||||||
* @export
|
* @export
|
||||||
* @interface IBasicSchema
|
* @interface IBasicSchema
|
||||||
*/
|
*/
|
||||||
export interface IBasicSchema {
|
export interface IBasicSchema extends ProjectSchema {}
|
||||||
version: string; // 当前协议版本号
|
|
||||||
componentsMap: IComponentsMapItem[]; // 组件映射关系
|
|
||||||
componentsTree: Array<IContainerNodeItem | IComponentNodeItem>; // 描述模版/页面/区块/低代码业务组件的组件树 低代码业务组件树描述,固定长度为1,且顶层为低代码业务组件容器描述
|
|
||||||
utils?: IUtilItem[]; // 工具类扩展映射关系 低代码业务组件不包含
|
|
||||||
i18n?: II18nMap; // 国际化语料
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IProjectSchema extends IBasicSchema {
|
export interface IProjectSchema extends IBasicSchema {
|
||||||
|
// TODO: 下面的几个值真的需要吗?....
|
||||||
constants: Record<string, string>; // 应用范围内的全局常量;
|
constants: Record<string, string>; // 应用范围内的全局常量;
|
||||||
css: string; // 应用范围内的全局样式;
|
css: string; // 应用范围内的全局样式;
|
||||||
config: IAppConfig; // 当前应用配置信息
|
config: IAppConfig; // 当前应用配置信息
|
||||||
meta: IAppMeta; // 当前应用元数据信息
|
meta: IAppMeta; // 当前应用元数据信息
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export interface IComponentsMapItem extends NpmInfo {}
|
||||||
* 搭建基础协议 - 单个组件描述
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @interface IComponentsMapItem
|
|
||||||
*/
|
|
||||||
export interface IComponentsMapItem extends IExternalDependency {
|
|
||||||
componentName: string; // 组件名称
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUtilItem {
|
export type IUtilItem = UtilItem;
|
||||||
name: string;
|
export type ChildNodeItem = NodeData;
|
||||||
type: 'npm' | 'tnpm' | 'function';
|
|
||||||
content: IExternalDependency | IJSExpression;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ChildNodeItem = string | IJSExpression | IComponentNodeItem;
|
|
||||||
export type ChildNodeType = ChildNodeItem | ChildNodeItem[];
|
export type ChildNodeType = ChildNodeItem | ChildNodeItem[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,18 +69,7 @@ export type ChildNodeType = ChildNodeItem | ChildNodeItem[];
|
|||||||
* @export
|
* @export
|
||||||
* @interface IComponentNodeItem
|
* @interface IComponentNodeItem
|
||||||
*/
|
*/
|
||||||
export interface IComponentNodeItem {
|
export interface IComponentNodeItem extends NodeSchema {}
|
||||||
// TODO: 不需要 id 字段,暂时简单兼容
|
|
||||||
id?: string;
|
|
||||||
componentName: string; // 组件名称 必填、首字母大写
|
|
||||||
props: {
|
|
||||||
[propName: string]: CompositeValue; // 业务属性
|
|
||||||
}; // 组件属性对象
|
|
||||||
condition?: CompositeValue; // 渲染条件
|
|
||||||
loop?: CompositeValue; // 循环数据
|
|
||||||
loopArgs?: [string, string]; // 循环迭代对象、索引名称 ["item", "index"]
|
|
||||||
children?: ChildNodeType; // 子节点
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搭建基础协议 - 单个容器节点描述
|
* 搭建基础协议 - 单个容器节点描述
|
||||||
@ -118,31 +78,7 @@ export interface IComponentNodeItem {
|
|||||||
* @interface IContainerNodeItem
|
* @interface IContainerNodeItem
|
||||||
* @extends {IComponentNodeItem}
|
* @extends {IComponentNodeItem}
|
||||||
*/
|
*/
|
||||||
export interface IContainerNodeItem extends IComponentNodeItem {
|
export type IContainerNodeItem = PageSchema | BlockSchema | ComponentSchema;
|
||||||
componentName: 'Page' | 'Block' | 'Component'; // 'Page' | 'Block' | 'Component' 组件类型 必填、首字母大写
|
|
||||||
fileName: string; // 文件名称 必填、英文
|
|
||||||
state?: {
|
|
||||||
[stateName: string]: CompositeValue; // 容器初始数据
|
|
||||||
};
|
|
||||||
css?: string; // 样式文件 用于描述容器组件内部节点的样式,对应生成一个独立的样式文件,在对应容器组件生成的 .jsx 文件中 import 引入;
|
|
||||||
/**
|
|
||||||
* LifeCycle
|
|
||||||
* • constructor(props, context)
|
|
||||||
* • 说明:初始化渲染时执行,常用于设置state值;
|
|
||||||
* • render()
|
|
||||||
* • 说明:执行于容器组件React Class的render方法最前,常用于计算变量挂载到this对象上,供props上属性绑定。此render()方法不需要设置return返回值。
|
|
||||||
* • componentDidMount()
|
|
||||||
* • componentDidUpdate(prevProps, prevState, snapshot)
|
|
||||||
* • componentWillUnmount()
|
|
||||||
* • componentDidCatch(error, info)
|
|
||||||
*/
|
|
||||||
lifeCycles?: Record<string, IJSExpression>; // 生命周期Hook方法
|
|
||||||
methods?: Record<string, IJSExpression>; // 自定义方法设置
|
|
||||||
dataSource?: {
|
|
||||||
list: IDataSourceConfig[];
|
|
||||||
}; // 异步数据源配置
|
|
||||||
meta?: IBasicMeta | IPageMeta;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搭建基础协议 - 数据源单个配置
|
* 搭建基础协议 - 数据源单个配置
|
||||||
@ -150,69 +86,25 @@ export interface IContainerNodeItem extends IComponentNodeItem {
|
|||||||
* @export
|
* @export
|
||||||
* @interface IDataSourceConfig
|
* @interface IDataSourceConfig
|
||||||
*/
|
*/
|
||||||
export interface IDataSourceConfig {
|
export interface IDataSourceConfig extends DataSourceConfig {}
|
||||||
id: string; // 数据请求ID标识
|
|
||||||
isInit: boolean; // 是否为初始数据 支持表达式 值为true时,将在组件初始化渲染时自动发送当前数据请求
|
|
||||||
type: string; // 数据请求类型 'fetch' | 'mtop' | 'jsonp' | 'custom'
|
|
||||||
requestHandler?: IJSExpression; // 自定义扩展的外部请求处理器 仅type='custom'时生效
|
|
||||||
options?: IFetchOptions; // 请求参数配置 每种请求类型对应不同参数
|
|
||||||
dataHandler?: IJSExpression; // 数据结果处理函数,形如:(data, err) => Object
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 搭建基础协议 - 请求参数配置
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @interface IFetchOptions
|
|
||||||
*/
|
|
||||||
export interface IFetchOptions {
|
|
||||||
url: string; // 请求地址 支持表达式
|
|
||||||
params?: {
|
|
||||||
// 请求参数
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
|
||||||
method: 'GET' | 'POST';
|
|
||||||
isCors?: boolean; // 是否支持跨域,对应credentials = 'include'
|
|
||||||
timeout?: number; // 超时时长
|
|
||||||
headers?: {
|
|
||||||
// 自定义请求头
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
[extConfigName: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// TODO...
|
||||||
export interface IBasicMeta {
|
export interface IBasicMeta {
|
||||||
title: string; // 标题描述
|
title: string; // 标题描述
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO...
|
||||||
export interface IPageMeta extends IBasicMeta {
|
export interface IPageMeta extends IBasicMeta {
|
||||||
router: string; // 页面路由
|
router: string; // 页面路由
|
||||||
spmb?: string; // spm
|
spmb?: string; // spm
|
||||||
}
|
}
|
||||||
|
|
||||||
// "theme": {
|
|
||||||
// //for Fusion use dpl defined
|
|
||||||
// "package": "@alife/theme-fusion",
|
|
||||||
// "version": "^0.1.0",
|
|
||||||
|
|
||||||
// //for Antd use variable
|
|
||||||
// "primary": "#ff9966"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// "layout": {
|
|
||||||
// "componentName": "BasicLayout",
|
|
||||||
// "props": {
|
|
||||||
// "logo": "...",
|
|
||||||
// "name": "测试网站"
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
|
|
||||||
export interface IAppConfig {
|
export interface IAppConfig {
|
||||||
sdkVersion: string; // 渲染模块版本
|
sdkVersion?: string; // 渲染模块版本
|
||||||
historyMode: 'brower' | 'hash'; // 浏览器路由:brower 哈希路由:hash
|
historyMode?: 'browser' | 'hash'; // 浏览器路由:browser 哈希路由:hash
|
||||||
targetRootID: string; // 渲染根节点 ID
|
targetRootID?: string; // 渲染根节点 ID
|
||||||
layout: IComponentNodeItem;
|
layout?: IComponentNodeItem;
|
||||||
theme: object; // 主题配置,根据接入的主题模块不同
|
theme?: object; // 主题配置,根据接入的主题模块不同
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAppMeta {
|
export interface IAppMeta {
|
||||||
|
|||||||
@ -1,37 +1,43 @@
|
|||||||
import { CompositeArray, CompositeValue, ICompositeObject } from '../types';
|
import {
|
||||||
import { generateExpression, isJsExpression } from './jsExpression';
|
CompositeArray,
|
||||||
|
CompositeValue,
|
||||||
|
CompositeObject,
|
||||||
|
JSExpression,
|
||||||
|
JSFunction,
|
||||||
|
JSONArray,
|
||||||
|
JSONObject,
|
||||||
|
isJSExpression,
|
||||||
|
isJSFunction,
|
||||||
|
isJSSlot,
|
||||||
|
JSSlot,
|
||||||
|
NodeSchema,
|
||||||
|
NodeData,
|
||||||
|
} from '../types';
|
||||||
|
import { generateExpression, generateFunction } from './jsExpression';
|
||||||
|
|
||||||
type CustomHandler = (data: unknown) => string;
|
export interface CustomHandlerSet {
|
||||||
interface CustomHandlerSet {
|
boolean?: (bool: boolean) => string;
|
||||||
boolean?: CustomHandler;
|
number?: (num: number) => string;
|
||||||
number?: CustomHandler;
|
string?: (str: string) => string;
|
||||||
string?: CustomHandler;
|
array?: (arr: JSONArray | CompositeArray) => string;
|
||||||
array?: CustomHandler;
|
object?: (obj: JSONObject | CompositeObject) => string;
|
||||||
object?: CustomHandler;
|
expression?: (jsExpr: JSExpression) => string;
|
||||||
expression?: CustomHandler;
|
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(
|
function generateArray(value: CompositeArray, handlers: CustomHandlerSet): string {
|
||||||
value: CompositeArray,
|
const body = value.map((v) => generateUnknownType(v, handlers)).join(',');
|
||||||
handlers: CustomHandlerSet = {},
|
|
||||||
): string {
|
|
||||||
const body = value.map(v => generateUnknownType(v, handlers)).join(',');
|
|
||||||
return `[${body}]`;
|
return `[${body}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateObject(
|
function generateObject(value: CompositeObject, handlers: CustomHandlerSet): string {
|
||||||
value: ICompositeObject,
|
|
||||||
handlers: CustomHandlerSet = {},
|
|
||||||
): string {
|
|
||||||
if (isJsExpression(value)) {
|
|
||||||
if (handlers.expression) {
|
|
||||||
return handlers.expression(value);
|
|
||||||
}
|
|
||||||
return generateExpression(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = Object.keys(value)
|
const body = Object.keys(value)
|
||||||
.map(key => {
|
.map((key) => {
|
||||||
const v = generateUnknownType(value[key], handlers);
|
const v = generateUnknownType(value[key], handlers);
|
||||||
return `${key}: ${v}`;
|
return `${key}: ${v}`;
|
||||||
})
|
})
|
||||||
@ -40,39 +46,65 @@ function generateObject(
|
|||||||
return `{${body}}`;
|
return `{${body}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateUnknownType(
|
export function generateUnknownType(value: CompositeValue, handlers: CustomHandlerSet = {}): string {
|
||||||
value: CompositeValue,
|
|
||||||
handlers: CustomHandlerSet = {},
|
|
||||||
): string {
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
if (handlers.array) {
|
if (handlers.array) {
|
||||||
return handlers.array(value);
|
return handlers.array(value);
|
||||||
}
|
}
|
||||||
return generateArray(value as CompositeArray, handlers);
|
return generateArray(value, handlers);
|
||||||
} else if (typeof value === 'object') {
|
} else if (typeof value === 'object') {
|
||||||
|
if (value === null) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJSExpression(value)) {
|
||||||
|
if (handlers.expression) {
|
||||||
|
return handlers.expression(value);
|
||||||
|
}
|
||||||
|
return generateExpression(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJSFunction(value)) {
|
||||||
|
if (handlers.function) {
|
||||||
|
return handlers.function(value);
|
||||||
|
}
|
||||||
|
return generateFunction(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJSSlot(value)) {
|
||||||
|
if (handlers.slot) {
|
||||||
|
return handlers.slot(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateSlot(value, handlers);
|
||||||
|
}
|
||||||
|
|
||||||
if (handlers.object) {
|
if (handlers.object) {
|
||||||
return handlers.object(value);
|
return handlers.object(value);
|
||||||
}
|
}
|
||||||
return generateObject(value as ICompositeObject, handlers);
|
|
||||||
|
return generateObject(value, handlers);
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
if (handlers.string) {
|
if (handlers.string) {
|
||||||
return handlers.string(value);
|
return handlers.string(value);
|
||||||
}
|
}
|
||||||
return `'${value}'`;
|
|
||||||
|
return JSON.stringify(value);
|
||||||
} else if (typeof value === 'number' && handlers.number) {
|
} else if (typeof value === 'number' && handlers.number) {
|
||||||
return handlers.number(value);
|
return handlers.number(value);
|
||||||
} else if (typeof value === 'boolean' && handlers.boolean) {
|
} else if (typeof value === 'boolean' && handlers.boolean) {
|
||||||
return handlers.boolean(value);
|
return handlers.boolean(value);
|
||||||
|
} else if (typeof value === 'undefined') {
|
||||||
|
return 'undefined';
|
||||||
}
|
}
|
||||||
return `${value}`;
|
|
||||||
|
return JSON.stringify(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateCompositeType(
|
export function generateCompositeType(value: CompositeValue, handlers: CustomHandlerSet = {}): [boolean, string] {
|
||||||
value: CompositeValue,
|
|
||||||
handlers: CustomHandlerSet = {},
|
|
||||||
): [boolean, string] {
|
|
||||||
const result = generateUnknownType(value, handlers);
|
const result = generateUnknownType(value, handlers);
|
||||||
|
|
||||||
|
// TODO:什么场景下会返回这样的字符串??
|
||||||
if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") {
|
if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") {
|
||||||
return [true, result.substring(1, result.length - 1)];
|
return [true, result.substring(1, result.length - 1)];
|
||||||
}
|
}
|
||||||
@ -84,5 +116,50 @@ export function handleStringValueDefault([isString, result]: [boolean, string])
|
|||||||
if (isString) {
|
if (isString) {
|
||||||
return `'${result}'`;
|
return `'${result}'`;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, '*-/') + '*/';
|
||||||
|
}
|
||||||
|
|||||||
@ -1,39 +1,6 @@
|
|||||||
import traverse from '@babel/traverse';
|
import { CodeGeneratorError, isJSExpression, isJSFunction } from '../types';
|
||||||
import * as parser from '@babel/parser';
|
|
||||||
import { CodeGeneratorError, IJSExpression } from '../types';
|
|
||||||
|
|
||||||
let count = 0;
|
|
||||||
|
|
||||||
function test(functionBody: string) {
|
|
||||||
console.log(functionBody);
|
|
||||||
console.log('---->');
|
|
||||||
try {
|
|
||||||
const parseResult = parser.parse(functionBody);
|
|
||||||
// console.log(JSON.stringify(parseResult));
|
|
||||||
traverse(parseResult, {
|
|
||||||
enter(path) {
|
|
||||||
console.log('path: ', JSON.stringify(path));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (count === 0) {
|
|
||||||
count++;
|
|
||||||
|
|
||||||
test('this.aaa && this.bbb');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// console.log('Error');
|
|
||||||
console.log(error.message);
|
|
||||||
}
|
|
||||||
console.log('=====================');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformFuncExpr2MethodMember(
|
|
||||||
methodName: string,
|
|
||||||
functionBody: string,
|
|
||||||
): string {
|
|
||||||
// test(functionBody);
|
|
||||||
|
|
||||||
|
export function transformFuncExpr2MethodMember(methodName: string, functionBody: string): string {
|
||||||
const args = getFuncExprArguments(functionBody);
|
const args = getFuncExprArguments(functionBody);
|
||||||
const body = getFuncExprBody(functionBody);
|
const body = getFuncExprBody(functionBody);
|
||||||
|
|
||||||
@ -56,8 +23,6 @@ export function getFuncExprBody(functionBody: string) {
|
|||||||
const start = functionBody.indexOf('{');
|
const start = functionBody.indexOf('{');
|
||||||
const end = functionBody.lastIndexOf('}');
|
const end = functionBody.lastIndexOf('}');
|
||||||
|
|
||||||
// test(functionBody);
|
|
||||||
|
|
||||||
if (start < 0 || end < 0 || end < start) {
|
if (start < 0 || end < 0 || end < start) {
|
||||||
throw new CodeGeneratorError('JSExpression has no valid body.');
|
throw new CodeGeneratorError('JSExpression has no valid body.');
|
||||||
}
|
}
|
||||||
@ -67,19 +32,18 @@ export function getFuncExprBody(functionBody: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function generateExpression(value: any): string {
|
export function generateExpression(value: any): string {
|
||||||
if (value && (value as IJSExpression).type === 'JSExpression') {
|
if (isJSExpression(value)) {
|
||||||
// test((value as IJSExpression).value);
|
return value.value || 'null';
|
||||||
|
|
||||||
return (value as IJSExpression).value || 'null';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new CodeGeneratorError('Not a JSExpression');
|
throw new CodeGeneratorError('Not a JSExpression');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isJsExpression(value: any): boolean {
|
// TODO: 这样真的可以吗?
|
||||||
return (
|
export function generateFunction(value: any): string {
|
||||||
value &&
|
if (isJSFunction(value)) {
|
||||||
typeof value === 'object' &&
|
return value.value || 'null';
|
||||||
(value as IJSExpression).type === 'JSExpression'
|
}
|
||||||
);
|
|
||||||
|
throw new CodeGeneratorError('Not a isJSFunction');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,59 +1,73 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
import {
|
import {
|
||||||
ChildNodeType,
|
|
||||||
IComponentNodeItem,
|
|
||||||
IJSExpression,
|
|
||||||
ChildNodeItem,
|
|
||||||
CodeGeneratorError,
|
|
||||||
PIECE_TYPE,
|
PIECE_TYPE,
|
||||||
|
CodeGeneratorError,
|
||||||
CodePiece,
|
CodePiece,
|
||||||
HandlerSet,
|
HandlerSet,
|
||||||
ExtGeneratorPlugin,
|
ExtGeneratorPlugin,
|
||||||
|
isJSExpression,
|
||||||
|
isJSFunction,
|
||||||
|
NodeData,
|
||||||
|
CompositeValue,
|
||||||
|
NodeSchema,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { generateCompositeType } from './compositeType';
|
import { CustomHandlerSet, 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<T>(
|
export function handleChildren(children: NodeData | NodeData[], handlers: HandlerSet<string>): string[] {
|
||||||
children: ChildNodeType,
|
|
||||||
handlers: HandlerSet<T>,
|
|
||||||
): T[] {
|
|
||||||
if (Array.isArray(children)) {
|
if (Array.isArray(children)) {
|
||||||
const list: ChildNodeItem[] = children as ChildNodeItem[];
|
return children.map((child) => handleChildren(child, handlers)).reduce((p, c) => p.concat(c), []);
|
||||||
return list
|
|
||||||
.map(child => handleChildren(child, handlers))
|
|
||||||
.reduce((p, c) => p.concat(c), []);
|
|
||||||
} else if (typeof children === 'string') {
|
} else if (typeof children === 'string') {
|
||||||
const handler = handlers.string || handlers.common || noop;
|
const handler = handlers.string || handlers.common || noop;
|
||||||
return handler(children as string);
|
return handler(children);
|
||||||
} else if ((children as IJSExpression).type === 'JSExpression') {
|
} else if (isJSExpression(children)) {
|
||||||
const handler = handlers.expression || handlers.common || noop;
|
const handler = handlers.expression || handlers.common || noop;
|
||||||
return handler(children as IJSExpression);
|
return ['{', ...handler(children), '}'];
|
||||||
|
} 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 as IComponentNodeItem);
|
return handler(children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateAttr(attrName: string, attrValue: any): CodePiece[] {
|
export function generateAttr(attrName: string, attrValue: CompositeValue, handlers: CustomHandlerSet): CodePiece[] {
|
||||||
if (attrName === 'initValue' || attrName === 'labelCol') {
|
if (attrName === 'initValue' || attrName === 'labelCol') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const [isString, valueStr] = generateCompositeType(attrValue);
|
const [isString, valueStr] = generateCompositeType(attrValue, handlers);
|
||||||
return [{
|
return [
|
||||||
|
{
|
||||||
value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`,
|
value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`,
|
||||||
type: PIECE_TYPE.ATTR,
|
type: PIECE_TYPE.ATTR,
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateAttrs(nodeItem: IComponentNodeItem): CodePiece[] {
|
export function generateAttrs(nodeItem: NodeSchema, handlers: CustomHandlerSet): CodePiece[] {
|
||||||
const { props } = nodeItem;
|
const { props } = nodeItem;
|
||||||
|
|
||||||
let pieces: CodePiece[] = [];
|
let pieces: CodePiece[] = [];
|
||||||
|
|
||||||
Object.keys(props).forEach((propName: string) =>
|
if (props) {
|
||||||
pieces = pieces.concat(generateAttr(propName, props[propName])),
|
if (!Array.isArray(props)) {
|
||||||
);
|
Object.keys(props).forEach((propName: string) => {
|
||||||
|
pieces = pieces.concat(generateAttr(propName, props[propName], handlers));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
props.forEach((prop) => {
|
||||||
|
if (prop.name && !prop.spread) {
|
||||||
|
pieces = pieces.concat(generateAttr(prop.name, prop.value, handlers));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 处理 spread 场景(<Xxx {...(something)}/>)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return pieces;
|
return pieces;
|
||||||
}
|
}
|
||||||
@ -62,10 +76,11 @@ export function mapNodeName(src: string): string {
|
|||||||
if (src === 'Div') {
|
if (src === 'Div') {
|
||||||
return 'div';
|
return 'div';
|
||||||
}
|
}
|
||||||
|
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateBasicNode(nodeItem: IComponentNodeItem): CodePiece[] {
|
export function generateBasicNode(nodeItem: NodeSchema): CodePiece[] {
|
||||||
const pieces: CodePiece[] = [];
|
const pieces: CodePiece[] = [];
|
||||||
pieces.push({
|
pieces.push({
|
||||||
value: mapNodeName(nodeItem.componentName),
|
value: mapNodeName(nodeItem.componentName),
|
||||||
@ -75,20 +90,23 @@ export function generateBasicNode(nodeItem: IComponentNodeItem): CodePiece[] {
|
|||||||
return pieces;
|
return pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[] {
|
export function generateReactCtrlLine(nodeItem: NodeSchema, handlers: CustomHandlerSet): CodePiece[] {
|
||||||
const pieces: CodePiece[] = [];
|
const pieces: CodePiece[] = [];
|
||||||
|
|
||||||
if (nodeItem.loop && nodeItem.loopArgs) {
|
if (nodeItem.loop) {
|
||||||
let loopDataExp;
|
const loopItemName = nodeItem.loopArgs?.[0] || 'item';
|
||||||
if ((nodeItem.loop as IJSExpression).type === 'JSExpression') {
|
const loopIndexName = nodeItem.loopArgs?.[1] || 'index';
|
||||||
loopDataExp = `(${(nodeItem.loop as IJSExpression).value})`;
|
|
||||||
} else {
|
// TODO: 静态的值可以抽离出来?
|
||||||
loopDataExp = JSON.stringify(nodeItem.loop);
|
const loopDataExpr = (handlers.loopDataExpr || _.identity)(
|
||||||
}
|
isJSExpression(nodeItem.loop) ? `(${nodeItem.loop.value})` : `(${JSON.stringify(nodeItem.loop)})`,
|
||||||
|
);
|
||||||
|
|
||||||
pieces.unshift({
|
pieces.unshift({
|
||||||
value: `${loopDataExp}.map((${nodeItem.loopArgs[0]}, ${nodeItem.loopArgs[1]}) => (`,
|
value: `${loopDataExpr}.map((${loopItemName}, ${loopIndexName}) => (`,
|
||||||
type: PIECE_TYPE.BEFORE,
|
type: PIECE_TYPE.BEFORE,
|
||||||
});
|
});
|
||||||
|
|
||||||
pieces.push({
|
pieces.push({
|
||||||
value: '))',
|
value: '))',
|
||||||
type: PIECE_TYPE.AFTER,
|
type: PIECE_TYPE.AFTER,
|
||||||
@ -96,23 +114,26 @@ export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[]
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nodeItem.condition) {
|
if (nodeItem.condition) {
|
||||||
const [isString, value] = generateCompositeType(nodeItem.condition);
|
const [isString, value] = generateCompositeType(nodeItem.condition, handlers);
|
||||||
|
const conditionExpr = (handlers.conditionExpr || _.identity)(isString ? `'${value}'` : value);
|
||||||
|
|
||||||
pieces.unshift({
|
pieces.unshift({
|
||||||
value: `(${isString ? `'${value}'` : value}) && (`,
|
value: `(${conditionExpr}) && (`,
|
||||||
type: PIECE_TYPE.BEFORE,
|
type: PIECE_TYPE.BEFORE,
|
||||||
});
|
});
|
||||||
|
|
||||||
pieces.push({
|
pieces.push({
|
||||||
value: ')',
|
value: ')',
|
||||||
type: PIECE_TYPE.AFTER,
|
type: PIECE_TYPE.AFTER,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeItem.condition || (nodeItem.loop && nodeItem.loopArgs)) {
|
if (nodeItem.condition || nodeItem.loop) {
|
||||||
pieces.unshift({
|
pieces.unshift({
|
||||||
value: '{',
|
value: '{',
|
||||||
type: PIECE_TYPE.BEFORE,
|
type: PIECE_TYPE.BEFORE,
|
||||||
});
|
});
|
||||||
|
|
||||||
pieces.push({
|
pieces.push({
|
||||||
value: '}',
|
value: '}',
|
||||||
type: PIECE_TYPE.AFTER,
|
type: PIECE_TYPE.AFTER,
|
||||||
@ -122,30 +143,32 @@ export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[]
|
|||||||
return pieces;
|
return pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function linkPieces(pieces: CodePiece[]): string {
|
export function linkPieces(pieces: CodePiece[], handlers: CustomHandlerSet): string {
|
||||||
if (pieces.filter(p => p.type === PIECE_TYPE.TAG).length !== 1) {
|
const tagsPieces = pieces.filter((p) => p.type === PIECE_TYPE.TAG);
|
||||||
|
if (tagsPieces.length !== 1) {
|
||||||
throw new CodeGeneratorError('One node only need one tag define');
|
throw new CodeGeneratorError('One node only need one tag define');
|
||||||
}
|
}
|
||||||
const tagName = pieces.filter(p => p.type === PIECE_TYPE.TAG)[0].value;
|
|
||||||
|
const tagName = (handlers.tagName || _.identity)(tagsPieces[0].value);
|
||||||
|
|
||||||
const beforeParts = pieces
|
const beforeParts = pieces
|
||||||
.filter(p => p.type === PIECE_TYPE.BEFORE)
|
.filter((p) => p.type === PIECE_TYPE.BEFORE)
|
||||||
.map(p => p.value)
|
.map((p) => p.value)
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
const afterParts = pieces
|
const afterParts = pieces
|
||||||
.filter(p => p.type === PIECE_TYPE.AFTER)
|
.filter((p) => p.type === PIECE_TYPE.AFTER)
|
||||||
.map(p => p.value)
|
.map((p) => p.value)
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
const childrenParts = pieces
|
const childrenParts = pieces
|
||||||
.filter(p => p.type === PIECE_TYPE.CHILDREN)
|
.filter((p) => p.type === PIECE_TYPE.CHILDREN)
|
||||||
.map(p => p.value)
|
.map((p) => p.value)
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
let attrsParts = pieces
|
let attrsParts = pieces
|
||||||
.filter(p => p.type === PIECE_TYPE.ATTR)
|
.filter((p) => p.type === PIECE_TYPE.ATTR)
|
||||||
.map(p => p.value)
|
.map((p) => p.value)
|
||||||
.join(' ');
|
.join(' ');
|
||||||
|
|
||||||
attrsParts = !!attrsParts ? ` ${attrsParts}` : '';
|
attrsParts = !!attrsParts ? ` ${attrsParts}` : '';
|
||||||
@ -157,26 +180,36 @@ export function linkPieces(pieces: CodePiece[]): string {
|
|||||||
return `${beforeParts}<${tagName}${attrsParts} />${afterParts}`;
|
return `${beforeParts}<${tagName}${attrsParts} />${afterParts}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createNodeGenerator(handlers: HandlerSet<string>, plugins: ExtGeneratorPlugin[]) {
|
export function createNodeGenerator(
|
||||||
const generateNode = (nodeItem: IComponentNodeItem): string => {
|
handlers: HandlerSet<string>,
|
||||||
|
plugins: ExtGeneratorPlugin[],
|
||||||
|
customHandlers: CustomHandlerSet = {},
|
||||||
|
) {
|
||||||
|
const generateNode = (nodeItem: NodeSchema): string => {
|
||||||
let pieces: CodePiece[] = [];
|
let pieces: CodePiece[] = [];
|
||||||
|
|
||||||
plugins.forEach(p => {
|
plugins.forEach((p) => {
|
||||||
pieces = pieces.concat(p(nodeItem));
|
pieces = pieces.concat(p(nodeItem, customHandlers));
|
||||||
});
|
});
|
||||||
|
|
||||||
pieces = pieces.concat(generateBasicNode(nodeItem));
|
pieces = pieces.concat(generateBasicNode(nodeItem));
|
||||||
pieces = pieces.concat(generateAttrs(nodeItem));
|
pieces = pieces.concat(generateAttrs(nodeItem, customHandlers));
|
||||||
if (nodeItem.children && (nodeItem.children as unknown[]).length > 0) {
|
|
||||||
pieces = pieces.concat(handleChildren<string>(nodeItem.children, handlers).map(l => ({
|
if (nodeItem.children && !_.isEmpty(nodeItem.children)) {
|
||||||
|
pieces = pieces.concat(
|
||||||
|
handleChildren(nodeItem.children, handlers).map((l) => ({
|
||||||
type: PIECE_TYPE.CHILDREN,
|
type: PIECE_TYPE.CHILDREN,
|
||||||
value: l,
|
value: l,
|
||||||
})));
|
})),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return linkPieces(pieces);
|
return linkPieces(pieces, customHandlers);
|
||||||
};
|
};
|
||||||
|
|
||||||
handlers.node = (input: IComponentNodeItem) => [generateNode(input)];
|
handlers.node = (node: NodeSchema) => [generateNode(node)];
|
||||||
|
|
||||||
|
customHandlers.node = customHandlers.node || generateNode;
|
||||||
|
|
||||||
return generateNode;
|
return generateNode;
|
||||||
}
|
}
|
||||||
@ -184,10 +217,11 @@ export function createNodeGenerator(handlers: HandlerSet<string>, plugins: ExtGe
|
|||||||
export const generateString = (input: string) => [input];
|
export const generateString = (input: string) => [input];
|
||||||
|
|
||||||
export function createReactNodeGenerator() {
|
export function createReactNodeGenerator() {
|
||||||
return createNodeGenerator({
|
return createNodeGenerator(
|
||||||
|
{
|
||||||
string: generateString,
|
string: generateString,
|
||||||
expression: (input) => [generateExpression(input)],
|
expression: (input) => [generateExpression(input)],
|
||||||
}, [
|
},
|
||||||
generateReactCtrlLine,
|
[generateReactCtrlLine],
|
||||||
]);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,13 @@ import Text from 'rax-text';
|
|||||||
|
|
||||||
import { createDataSourceEngine } from '@ali/lowcode-datasource-engine';
|
import { createDataSourceEngine } from '@ali/lowcode-datasource-engine';
|
||||||
|
|
||||||
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
class Home$$Page extends Component {
|
class Home$$Page extends Component {
|
||||||
|
_methods = this._defineMethods();
|
||||||
|
|
||||||
_context = this._createContext();
|
_context = this._createContext();
|
||||||
|
|
||||||
_dataSourceList = this._defineDataSourceList();
|
_dataSourceList = this._defineDataSourceList();
|
||||||
@ -21,6 +25,8 @@ class Home$$Page extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const __$$context = this._context;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<Text>Hello world!</Text>
|
<Text>Hello world!</Text>
|
||||||
@ -66,8 +72,35 @@ class Home$$Page extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_defineUtils() {
|
_defineUtils() {
|
||||||
|
const utils = {
|
||||||
|
...__$$projectUtils,
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.entries(utils).forEach(([name, util]) => {
|
||||||
|
if (typeof util === 'function') {
|
||||||
|
utils[name] = util.bind(this._context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return utils;
|
||||||
|
}
|
||||||
|
|
||||||
|
_defineMethods() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Home$$Page;
|
export default Home$$Page;
|
||||||
|
|
||||||
|
function __$$eval(expr) {
|
||||||
|
try {
|
||||||
|
return expr();
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Failed to evaluate: ', expr, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __$$evalArray(expr) {
|
||||||
|
const res = __$$eval(expr);
|
||||||
|
return Array.isArray(res) ? res : [];
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
# http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
# 忽略目录
|
||||||
|
build/
|
||||||
|
tests/
|
||||||
|
demo/
|
||||||
|
|
||||||
|
# node 覆盖率文件
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# 忽略文件
|
||||||
|
**/*-min.js
|
||||||
|
**/*.min.js
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['rax'],
|
||||||
|
};
|
||||||
17
packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/.gitignore
vendored
Normal file
17
packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.log
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.temp/
|
||||||
|
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
lib/
|
||||||
|
coverage/
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
template.yml
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
# @ali/rax-component-demo
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### `npm run start`
|
||||||
|
|
||||||
|
Runs the app in development mode.
|
||||||
|
|
||||||
|
Open [http://localhost:9999](http://localhost:9999) to view it in the browser.
|
||||||
|
|
||||||
|
The page will reload if you make edits.
|
||||||
|
|
||||||
|
### `npm run build`
|
||||||
|
|
||||||
|
Builds the app for production to the `build` folder.
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"type": "rax",
|
||||||
|
"builder": "@ali/builder-rax-v1",
|
||||||
|
"info": {
|
||||||
|
"raxVersion": "1.x"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"inlineStyle": false,
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"build-plugin-rax-app",
|
||||||
|
{
|
||||||
|
"targets": ["web", "miniapp"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@ali/build-plugin-rax-app-def"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/rax-app-demo",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -f ./dist/miniapp.tar.gz && npm run build:miniapp && cd build/miniapp && tar czf ../../dist/miniapp.tar.gz *",
|
||||||
|
"build:miniapp": "build-scripts build",
|
||||||
|
"start": "build-scripts start",
|
||||||
|
"lint": "eslint --ext .js --ext .jsx ./"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/lowcode-datasource-engine": "^0.1.0",
|
||||||
|
"rax": "^1.1.0",
|
||||||
|
"rax-app": "^2.0.0",
|
||||||
|
"rax-document": "^0.1.0",
|
||||||
|
"rax-view": "^1.0.0",
|
||||||
|
"rax-text": "^1.0.0",
|
||||||
|
"rax-image": "^1.0.0",
|
||||||
|
"moment": "*",
|
||||||
|
"lodash": "*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"build-plugin-rax-app": "^5.0.0",
|
||||||
|
"@alib/build-scripts": "^0.1.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.11.0",
|
||||||
|
"@typescript-eslint/parser": "^2.11.0",
|
||||||
|
"babel-eslint": "^10.0.3",
|
||||||
|
"eslint": "^6.8.0",
|
||||||
|
"eslint-config-rax": "^0.1.0",
|
||||||
|
"eslint-plugin-import": "^2.20.0",
|
||||||
|
"eslint-plugin-module": "^0.1.0",
|
||||||
|
"eslint-plugin-react": "^7.18.0",
|
||||||
|
"@ali/build-plugin-rax-app-def": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
import { runApp } from 'rax-app';
|
||||||
|
import appConfig from './app.json';
|
||||||
|
|
||||||
|
runApp(appConfig);
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"path": "/",
|
||||||
|
"source": "pages/Home/index"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"window": {
|
||||||
|
"title": "Rax App Demo"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { createElement } from 'rax';
|
||||||
|
import { Root, Style, Script } from 'rax-document';
|
||||||
|
|
||||||
|
function Document() {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover"
|
||||||
|
/>
|
||||||
|
<title>Rax App Demo</title>
|
||||||
|
<Style />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{/* root container */}
|
||||||
|
<Root />
|
||||||
|
<Script />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Document;
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
// TODO: 引入默认全局样式
|
||||||
|
|
||||||
|
body {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
@ -0,0 +1,165 @@
|
|||||||
|
import { createElement, Component } from 'rax';
|
||||||
|
|
||||||
|
import View from 'rax-view';
|
||||||
|
|
||||||
|
import Text from 'rax-text';
|
||||||
|
|
||||||
|
import Image from 'rax-image';
|
||||||
|
|
||||||
|
import { createDataSourceEngine } from '@ali/lowcode-datasource-engine';
|
||||||
|
|
||||||
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
class Home$$Page extends Component {
|
||||||
|
state = {
|
||||||
|
user: { name: '张三', age: 18, avatar: 'https://gw.alicdn.com/tfs/TB1Ui9BMkY2gK0jSZFgXXc5OFXa-50-50.png' },
|
||||||
|
orders: [
|
||||||
|
{
|
||||||
|
title: '【小米智能生活】米家扫地机器人家用全自动扫拖一体机拖地吸尘器',
|
||||||
|
price: 1799,
|
||||||
|
coverUrl: 'https://gw.alicdn.com/tfs/TB1dGVlRfb2gK0jSZK9XXaEgFXa-258-130.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '【限时下单立减】Apple/苹果 iPhone 11 4G全网通智能手机正品苏宁易购官方旗舰店苹果11',
|
||||||
|
price: 4999,
|
||||||
|
coverUrl: 'https://gw.alicdn.com/tfs/TB18gdJddTfau8jSZFwXXX1mVXa-1298-1202.png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
_methods = this._defineMethods();
|
||||||
|
_context = this._createContext();
|
||||||
|
_dataSourceList = this._defineDataSourceList();
|
||||||
|
_dataSourceEngine = createDataSourceEngine(this._dataSourceList, this._context);
|
||||||
|
|
||||||
|
_utils = this._defineUtils();
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this._dataSourceEngine.reloadDataSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const __$$context = this._context;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<View>
|
||||||
|
<Text>Demo data source logic</Text>
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<Text>=== User Info: ===</Text>
|
||||||
|
</View>
|
||||||
|
{__$$eval(() => __$$context.state.user) && (
|
||||||
|
<View style={{ flexDirection: 'row' }}>
|
||||||
|
<Image
|
||||||
|
source={{ uri: __$$eval(() => __$$context.state.user.avatar) }}
|
||||||
|
style={{ width: '32px', height: '32px' }}
|
||||||
|
/>
|
||||||
|
<View>
|
||||||
|
<Text>{__$$eval(() => __$$context.state.user.name)}</Text>
|
||||||
|
<Text>{__$$eval(() => __$$context.state.user.age)}岁</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
<View>
|
||||||
|
<Text>=== Orders: ===</Text>
|
||||||
|
</View>
|
||||||
|
{__$$evalArray(() => __$$context.state.orders).map((item, index) => (
|
||||||
|
<View style={{ flexDirection: 'row' }}>
|
||||||
|
<View>
|
||||||
|
<Image source={{ uri: __$$eval(() => item.coverUrl) }} style={{ width: '80px', height: '60px' }} />
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<Text>{__$$eval(() => item.title)}</Text>
|
||||||
|
<Text>{__$$eval(() => __$$context.utils.formatPrice(item.price, '元'))}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createContext() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
get state() {
|
||||||
|
return self.state;
|
||||||
|
},
|
||||||
|
setState(newState) {
|
||||||
|
self.setState(newState);
|
||||||
|
},
|
||||||
|
get dataSourceMap() {
|
||||||
|
return self._dataSourceEngine.dataSourceMap || {};
|
||||||
|
},
|
||||||
|
async reloadDataSource() {
|
||||||
|
self._dataSourceEngine.reloadDataSource();
|
||||||
|
},
|
||||||
|
get utils() {
|
||||||
|
return self._utils;
|
||||||
|
},
|
||||||
|
get page() {
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
get component() {
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
get props() {
|
||||||
|
return self.props;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
_defineDataSourceList() {
|
||||||
|
return [
|
||||||
|
{ id: 'urlParams', type: 'urlParams' },
|
||||||
|
{ id: 'user', type: 'fetch', options: { method: 'GET', uri: 'https://shs.alibaba-inc.com/mock/1458/demo/user' } },
|
||||||
|
{
|
||||||
|
id: 'orders',
|
||||||
|
type: 'fetch',
|
||||||
|
options: { method: 'GET', uri: 'https://shs.alibaba-inc.com/mock/1458/demo/orders' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
_defineUtils() {
|
||||||
|
const utils = {
|
||||||
|
...__$$projectUtils,
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.entries(utils).forEach(([name, util]) => {
|
||||||
|
if (typeof util === 'function') {
|
||||||
|
utils[name] = util.bind(this._context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return utils;
|
||||||
|
}
|
||||||
|
|
||||||
|
_defineMethods() {
|
||||||
|
return {
|
||||||
|
hello: function hello() {
|
||||||
|
console.log('Hello world!');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home$$Page;
|
||||||
|
|
||||||
|
function __$$eval(expr) {
|
||||||
|
try {
|
||||||
|
return expr();
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Failed to evaluate: ', expr, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __$$evalArray(expr) {
|
||||||
|
const res = __$$eval(expr);
|
||||||
|
return Array.isArray(res) ? res : [];
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
import { clone } from 'lodash';
|
||||||
|
|
||||||
|
const formatPrice = function formatPrice(price, unit) {
|
||||||
|
return Number(price).toFixed(2) + unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
formatPrice,
|
||||||
|
|
||||||
|
moment,
|
||||||
|
|
||||||
|
clone,
|
||||||
|
};
|
||||||
263
packages/code-generator/test-cases/rax-app/demo2/schema.json5
Normal file
263
packages/code-generator/test-cases/rax-app/demo2/schema.json5
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
{
|
||||||
|
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
||||||
|
version: '1.0.0',
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
package: 'rax-view',
|
||||||
|
version: '^1.0.0',
|
||||||
|
destructuring: false,
|
||||||
|
exportName: 'View',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
package: 'rax-text',
|
||||||
|
version: '^1.0.0',
|
||||||
|
destructuring: false,
|
||||||
|
exportName: 'Text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Image',
|
||||||
|
package: 'rax-image',
|
||||||
|
version: '^1.0.0',
|
||||||
|
destructuring: false,
|
||||||
|
exportName: 'Image',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Page',
|
||||||
|
package: 'rax-view',
|
||||||
|
version: '^1.0.0',
|
||||||
|
destructuring: false,
|
||||||
|
exportName: 'Page',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
componentsTree: [
|
||||||
|
{
|
||||||
|
componentName: 'Page',
|
||||||
|
fileName: 'home',
|
||||||
|
state: {
|
||||||
|
user: { name: '张三', age: 18, avatar: 'https://gw.alicdn.com/tfs/TB1Ui9BMkY2gK0jSZFgXXc5OFXa-50-50.png' },
|
||||||
|
orders: [
|
||||||
|
{
|
||||||
|
title: '【小米智能生活】米家扫地机器人家用全自动扫拖一体机拖地吸尘器',
|
||||||
|
price: 1799,
|
||||||
|
coverUrl: 'https://gw.alicdn.com/tfs/TB1dGVlRfb2gK0jSZK9XXaEgFXa-258-130.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '【限时下单立减】Apple/苹果 iPhone 11 4G全网通智能手机正品苏宁易购官方旗舰店苹果11',
|
||||||
|
price: 4999,
|
||||||
|
coverUrl: 'https://gw.alicdn.com/tfs/TB18gdJddTfau8jSZFwXXX1mVXa-1298-1202.png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
lifeCycles: {},
|
||||||
|
methods: {
|
||||||
|
hello: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'function hello(){ console.log("Hello world!"); }',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dataSource: {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
id: 'urlParams',
|
||||||
|
type: 'urlParams',
|
||||||
|
},
|
||||||
|
// 示例数据源:https://shs.alibaba-inc.com/mock/1458/demo/user
|
||||||
|
{
|
||||||
|
id: 'user',
|
||||||
|
type: 'fetch',
|
||||||
|
options: {
|
||||||
|
method: 'GET',
|
||||||
|
uri: 'https://shs.alibaba-inc.com/mock/1458/demo/user',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 示例数据源:https://shs.alibaba-inc.com/mock/1458/demo/orders
|
||||||
|
{
|
||||||
|
id: 'orders',
|
||||||
|
type: 'fetch',
|
||||||
|
options: {
|
||||||
|
method: 'GET',
|
||||||
|
uri: 'https://shs.alibaba-inc.com/mock/1458/demo/orders',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
props: {},
|
||||||
|
children: 'Demo data source logic',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
props: {},
|
||||||
|
children: '=== User Info: ===',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
condition: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.state.user',
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
style: { flexDirection: 'row' },
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Image',
|
||||||
|
props: {
|
||||||
|
source: {
|
||||||
|
uri: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.state.user.avatar',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
width: '32px',
|
||||||
|
height: '32px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
children: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.state.user.name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.state.user.age',
|
||||||
|
},
|
||||||
|
'岁',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
props: {},
|
||||||
|
children: '=== Orders: ===',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
loop: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.state.orders',
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
style: { flexDirection: 'row' },
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Image',
|
||||||
|
props: {
|
||||||
|
source: {
|
||||||
|
uri: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.item.coverUrl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
width: '80px',
|
||||||
|
height: '60px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
children: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.item.title',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
children: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.utils.formatPrice(this.item.price, "元")',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
utils: [
|
||||||
|
{
|
||||||
|
name: 'formatPrice',
|
||||||
|
type: 'function',
|
||||||
|
content: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: 'function formatPrice(price, unit) { return Number(price).toFixed(2) + unit; }',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'moment',
|
||||||
|
type: 'npm',
|
||||||
|
content: {
|
||||||
|
package: 'moment',
|
||||||
|
version: '*',
|
||||||
|
exportName: 'moment',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'clone',
|
||||||
|
type: 'npm',
|
||||||
|
content: {
|
||||||
|
package: 'lodash',
|
||||||
|
version: '*',
|
||||||
|
exportName: 'clone',
|
||||||
|
destructuring: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
sdkVersion: '1.0.3',
|
||||||
|
historyMode: 'hash',
|
||||||
|
targetRootID: 'root',
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
name: 'Rax App Demo',
|
||||||
|
git_group: 'demo-group',
|
||||||
|
project_name: 'demo-project',
|
||||||
|
description: '这是一个示例应用',
|
||||||
|
spma: 'spmademo',
|
||||||
|
creator: '张三',
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -62,7 +62,7 @@ function runPrettierSync(files: string[], cwd: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function diffActualAndExpectedSync(caseFullDir: string): string {
|
function diffActualAndExpectedSync(caseFullDir: string): string {
|
||||||
const res = spawnSync('diff', ['-wur', 'expected', 'actual'], {
|
const res = spawnSync('diff', ['-wBur', 'expected', 'actual'], {
|
||||||
cwd: caseFullDir,
|
cwd: caseFullDir,
|
||||||
stdio: 'pipe',
|
stdio: 'pipe',
|
||||||
shell: true,
|
shell: true,
|
||||||
|
|||||||
@ -2,14 +2,11 @@
|
|||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"lib": [
|
"target": "ES2018",
|
||||||
"es6"
|
"lib": ["ES6", "ES2016", "ES2017", "ES2018", "ES2019", "ES2020"],
|
||||||
],
|
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
|
"baseUrl": "." /* Base directory to resolve non-absolute module names. */
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*"]
|
||||||
"src/**/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user