mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-21 08:28:16 +00:00
Merge commit '94bd602d091fb8ac4274e3918378d46664af33a0' into feat/merge-rax-generator
This commit is contained in:
commit
fe327f4e19
@ -158,8 +158,8 @@ export class ProjectBuilder implements IProjectBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// i18n?
|
// i18n?
|
||||||
if (parseResult.globalI18n && builders.i18n && this.template.slots.i18n) {
|
if (builders.i18n && this.template.slots.i18n) {
|
||||||
const { files } = await builders.i18n.generateModule(parseResult.globalI18n);
|
const { files } = await builders.i18n.generateModule(parseResult.project);
|
||||||
|
|
||||||
buildResult.push({
|
buildResult.push({
|
||||||
path: this.template.slots.i18n.path,
|
path: this.template.slots.i18n.path,
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import { createProjectBuilder } from './generator/ProjectBuilder';
|
|||||||
import { createModuleBuilder } from './generator/ModuleBuilder';
|
import { createModuleBuilder } from './generator/ModuleBuilder';
|
||||||
import { createDiskPublisher } from './publisher/disk';
|
import { createDiskPublisher } from './publisher/disk';
|
||||||
import { createZipPublisher } from './publisher/zip';
|
import { createZipPublisher } from './publisher/zip';
|
||||||
// import createIceJsProjectBuilder from './solutions/icejs';
|
import createIceJsProjectBuilder from './solutions/icejs';
|
||||||
// import createRecoreProjectBuilder from './solutions/recore';
|
// import createRecoreProjectBuilder from './solutions/recore';
|
||||||
|
import createRaxAppProjectBuilder from './solutions/rax-app';
|
||||||
|
|
||||||
// 引入说明
|
// 引入说明
|
||||||
import { REACT_CHUNK_NAME } from './plugins/component/react/const';
|
import { REACT_CHUNK_NAME } from './plugins/component/react/const';
|
||||||
@ -42,6 +43,7 @@ import * as utilsValidate from './utils/validate';
|
|||||||
|
|
||||||
// 引入内置解决方案模块
|
// 引入内置解决方案模块
|
||||||
import icejs from './plugins/project/framework/icejs';
|
import icejs from './plugins/project/framework/icejs';
|
||||||
|
import rax from './plugins/project/framework/rax';
|
||||||
|
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
@ -49,11 +51,13 @@ export default {
|
|||||||
createProjectBuilder,
|
createProjectBuilder,
|
||||||
createModuleBuilder,
|
createModuleBuilder,
|
||||||
solutions: {
|
solutions: {
|
||||||
// icejs: createIceJsProjectBuilder,
|
icejs: createIceJsProjectBuilder,
|
||||||
// recore: createRecoreProjectBuilder,
|
// recore: createRecoreProjectBuilder,
|
||||||
|
rax: createRaxAppProjectBuilder,
|
||||||
},
|
},
|
||||||
solutionParts: {
|
solutionParts: {
|
||||||
icejs,
|
icejs,
|
||||||
|
rax,
|
||||||
},
|
},
|
||||||
publishers: {
|
publishers: {
|
||||||
disk: createDiskPublisher,
|
disk: createDiskPublisher,
|
||||||
|
|||||||
@ -32,6 +32,15 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
|
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: i18n 是可选的,如果没有 i18n 这个文件怎么办?该怎么判断?
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: COMMON_CHUNK_NAME.InternalDepsImport,
|
||||||
|
content: `import * as __$$i18n from '../../i18n';`,
|
||||||
|
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
|
||||||
|
});
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: cfg.fileType,
|
fileType: cfg.fileType,
|
||||||
@ -78,6 +87,16 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
get constants() {
|
get constants() {
|
||||||
return __$$constants;
|
return __$$constants;
|
||||||
},
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
...this._methods,
|
...this._methods,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,6 +106,34 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],
|
linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: CLASS_DEFINE_CHUNK_NAME.InsVar,
|
||||||
|
content: `
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
`,
|
||||||
|
linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],
|
||||||
|
});
|
||||||
|
|
||||||
|
next.chunks.push({
|
||||||
|
type: ChunkType.STRING,
|
||||||
|
fileType: cfg.fileType,
|
||||||
|
name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,
|
||||||
|
content: `
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],
|
||||||
|
});
|
||||||
return next;
|
return next;
|
||||||
};
|
};
|
||||||
return plugin;
|
return plugin;
|
||||||
|
|||||||
@ -43,14 +43,12 @@ 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 来访问上下文了
|
// 绑定下上下文,这样在所有的 utils 里面都能通过 this.xxx 来访问上下文了
|
||||||
// TODO: 要不要优化为通过 Proxy 的方式懒绑定?
|
|
||||||
content: `
|
content: `
|
||||||
_defineUtils() {
|
_defineUtils() {
|
||||||
const utils = {
|
const utils = {
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { NodeSchema, JSExpression, NpmInfo, CompositeValue } from '@ali/lowcode-types';
|
import { NodeSchema, JSExpression, NpmInfo, CompositeValue, isJSExpression } from '@ali/lowcode-types';
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import changeCase from 'change-case';
|
import changeCase from 'change-case';
|
||||||
|
import { Expression } from '@babel/types';
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
BuilderComponentPluginFactory,
|
BuilderComponentPluginFactory,
|
||||||
@ -23,7 +24,11 @@ import { createNodeGenerator, generateReactCtrlLine, generateAttr } from '../../
|
|||||||
import { generateCompositeType } from '../../../utils/compositeType';
|
import { generateCompositeType } from '../../../utils/compositeType';
|
||||||
|
|
||||||
import { IScopeBindings, ScopeBindings } from '../../../utils/ScopeBindings';
|
import { IScopeBindings, ScopeBindings } from '../../../utils/ScopeBindings';
|
||||||
import { parseExpressionConvertThis2Context, parseExpressionGetGlobalVariables } from '../../../utils/expressionParser';
|
import {
|
||||||
|
parseExpression,
|
||||||
|
parseExpressionConvertThis2Context,
|
||||||
|
parseExpressionGetGlobalVariables,
|
||||||
|
} from '../../../utils/expressionParser';
|
||||||
|
|
||||||
type PluginConfig = {
|
type PluginConfig = {
|
||||||
fileType: string;
|
fileType: string;
|
||||||
@ -37,23 +42,6 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
...config,
|
...config,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 什么都不做的的话,会有 3 个问题:
|
|
||||||
// 1. 小程序出码的时候,循环变量没法拿到
|
|
||||||
// 2. 小程序出码的时候,很容易出现 Uncaught TypeError: Cannot read property 'avatar' of undefined 这样的异常(如下图的 50 行) -- 因为若直接出码,Rax 构建到小程序的时候会立即计算所有在视图中用到的变量
|
|
||||||
// 3. 通过 this.xxx 能拿到的东西太多了,而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东
|
|
||||||
// const transformers = {
|
|
||||||
// transformThis2Context: (expr: string) => expr,
|
|
||||||
// transformJsExpr: (expr: string) => expr,
|
|
||||||
// transformLoopExpr: (expr: string) => expr,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// 不转换 this.xxx 到 __$$context.xxx 的话,依然会有上述的 1 和 3 的问题。
|
|
||||||
// const transformers = {
|
|
||||||
// transformThis2Context: (expr: string) => expr,
|
|
||||||
// transformJsExpr: (expr: string) => (isLiteralAtomicExpr(expr) ? expr : `__$$eval(() => (${expr}))`),
|
|
||||||
// transformLoopExpr: (expr: string) => `__$$evalArray(() => (${expr}))`,
|
|
||||||
// };
|
|
||||||
|
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
const next: ICodeStruct = {
|
const next: ICodeStruct = {
|
||||||
...pre,
|
...pre,
|
||||||
@ -70,12 +58,17 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 注意:这里其实隐含了一个假设:schema 中的 componentName 应该是一个有效的 JS 标识符,而且是大写字母打头的
|
||||||
const mapComponentNameToAliasOrKeepIt = (componentName: string) =>
|
const mapComponentNameToAliasOrKeepIt = (componentName: string) =>
|
||||||
componentsNameAliasMap.get(componentName) || componentName;
|
componentsNameAliasMap.get(componentName) || componentName;
|
||||||
|
|
||||||
// 然后过滤掉所有的别名 chunks
|
// 然后过滤掉所有的别名 chunks
|
||||||
next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk));
|
next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk));
|
||||||
|
|
||||||
|
// 如果直接按目前的 React 的方式之间出码 JSX 的话,会有 3 个问题:
|
||||||
|
// 1. 小程序出码的时候,循环变量没法拿到
|
||||||
|
// 2. 小程序出码的时候,很容易出现 Uncaught TypeError: Cannot read property 'avatar' of undefined 这样的异常(如下图的 50 行) -- 因为若直接出码,Rax 构建到小程序的时候会立即计算所有在视图中用到的变量
|
||||||
|
// 3. 通过 this.xxx 能拿到的东西太多了,而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东
|
||||||
const customHandlers: HandlerSet<string> = {
|
const customHandlers: HandlerSet<string> = {
|
||||||
expression(this: CustomHandlerSet, input: JSExpression) {
|
expression(this: CustomHandlerSet, input: JSExpression) {
|
||||||
return transformJsExpr(generateExpression(input), this);
|
return transformJsExpr(generateExpression(input), this);
|
||||||
@ -176,7 +169,49 @@ function transformLoopExpr(expr: string, handlers: CustomHandlerSet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function transformJsExpr(expr: string, handlers: CustomHandlerSet) {
|
function transformJsExpr(expr: string, handlers: CustomHandlerSet) {
|
||||||
return isLiteralAtomicExpr(expr) ? expr : `__$$eval(() => (${transformThis2Context(expr, handlers)}))`;
|
if (!expr) {
|
||||||
|
return 'undefined';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLiteralAtomicExpr(expr)) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const exprAst = parseExpression(expr);
|
||||||
|
|
||||||
|
// 对于下面这些比较安全的字面值,可以直接返回对应的表达式,而非包一层
|
||||||
|
if (isSimpleStraightLiteral(exprAst)) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (exprAst.type) {
|
||||||
|
// 对于直接写个函数的,则不用再包下,因为这样不会抛出异常的
|
||||||
|
case 'ArrowFunctionExpression':
|
||||||
|
case 'FunctionExpression':
|
||||||
|
return transformThis2Context(exprAst, handlers);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他的都需要包一层
|
||||||
|
return `__$$eval(() => (${transformThis2Context(exprAst, handlers)}))`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 判断是非是一些简单直接的字面值 */
|
||||||
|
function isSimpleStraightLiteral(expr: Expression): boolean {
|
||||||
|
switch (expr.type) {
|
||||||
|
case 'BigIntLiteral':
|
||||||
|
case 'BooleanLiteral':
|
||||||
|
case 'DecimalLiteral':
|
||||||
|
case 'NullLiteral':
|
||||||
|
case 'NumericLiteral':
|
||||||
|
case 'RegExpLiteral':
|
||||||
|
case 'StringLiteral':
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isImportAliasDefineChunk(
|
function isImportAliasDefineChunk(
|
||||||
@ -201,14 +236,15 @@ function isImportAliasDefineChunk(
|
|||||||
* 判断是否是原子类型的表达式
|
* 判断是否是原子类型的表达式
|
||||||
*/
|
*/
|
||||||
function isLiteralAtomicExpr(expr: string): boolean {
|
function isLiteralAtomicExpr(expr: string): boolean {
|
||||||
return expr === 'null' || expr === 'undefined' || expr === 'true' || expr === 'false' || /^\d+$/.test(expr);
|
return expr === 'null' || expr === 'undefined' || expr === 'true' || expr === 'false' || /^-?\d+(\.\d+)?$/.test(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将所有的 this.xxx 替换为 __$$context.xxx
|
* 将所有的 this.xxx 替换为 __$$context.xxx
|
||||||
* @param expr
|
* @param expr
|
||||||
*/
|
*/
|
||||||
function transformThis2Context(expr: string, customHandlers: CustomHandlerSet): string {
|
function transformThis2Context(expr: string | Expression, customHandlers: CustomHandlerSet): string {
|
||||||
|
// 下面这种字符串替换的方式虽然简单直接,但是对于复杂场景会误匹配,故后期改成了解析 AST 然后修改 AST 最后再重新生成代码的方式
|
||||||
// return expr
|
// return expr
|
||||||
// .replace(/\bthis\.item\./g, () => 'item.')
|
// .replace(/\bthis\.item\./g, () => 'item.')
|
||||||
// .replace(/\bthis\.index\./g, () => 'index.')
|
// .replace(/\bthis\.index\./g, () => 'index.')
|
||||||
@ -224,12 +260,24 @@ function generateNodeAttrForRax(this: CustomHandlerSet, attrName: string, attrVa
|
|||||||
nodeAttr: undefined,
|
nodeAttr: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// else: onXxx 的都是事件处理函数需要特殊处理下
|
||||||
|
|
||||||
// 先出个码
|
return generateEventHandlerAttrForRax(attrName, attrValue, this);
|
||||||
const valueExpr = generateCompositeType(attrValue, this);
|
}
|
||||||
|
|
||||||
|
function generateEventHandlerAttrForRax(
|
||||||
|
attrName: string,
|
||||||
|
attrValue: CompositeValue,
|
||||||
|
handlers: CustomHandlerSet,
|
||||||
|
): CodePiece[] {
|
||||||
|
// -- 事件处理函数中 JSExpression 转成 JSFunction 来处理,避免当 JSExpression 处理的时候多包一层 eval 而导致 Rax 转码成小程序的时候出问题
|
||||||
|
const valueExpr = generateCompositeType(
|
||||||
|
isJSExpression(attrValue) ? { type: 'JSFunction', value: attrValue.value } : attrValue,
|
||||||
|
handlers,
|
||||||
|
);
|
||||||
|
|
||||||
// 查询当前作用域下的变量
|
// 查询当前作用域下的变量
|
||||||
const currentScopeVariables = this.scopeBindings?.getAllBindings() || [];
|
const currentScopeVariables = handlers.scopeBindings?.getAllBindings() || [];
|
||||||
if (currentScopeVariables.length <= 0) {
|
if (currentScopeVariables.length <= 0) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,7 +9,18 @@ import {
|
|||||||
IProjectInfo,
|
IProjectInfo,
|
||||||
} from '../../../../../types';
|
} from '../../../../../types';
|
||||||
|
|
||||||
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
export type GlobalStylePluginConfig = {
|
||||||
|
fileType: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluginFactory: BuilderComponentPluginFactory<GlobalStylePluginConfig> = (
|
||||||
|
config?: Partial<GlobalStylePluginConfig>,
|
||||||
|
) => {
|
||||||
|
const cfg: GlobalStylePluginConfig = {
|
||||||
|
fileType: FileType.SCSS,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
const next: ICodeStruct = {
|
const next: ICodeStruct = {
|
||||||
...pre,
|
...pre,
|
||||||
@ -19,7 +30,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.SCSS, // TODO: 样式文件的类型定制化?
|
fileType: cfg.fileType,
|
||||||
name: COMMON_CHUNK_NAME.StyleDepsImport,
|
name: COMMON_CHUNK_NAME.StyleDepsImport,
|
||||||
content: ``,
|
content: ``,
|
||||||
linkAfter: [],
|
linkAfter: [],
|
||||||
@ -27,7 +38,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.SCSS,
|
fileType: cfg.fileType,
|
||||||
name: COMMON_CHUNK_NAME.StyleCssContent,
|
name: COMMON_CHUNK_NAME.StyleCssContent,
|
||||||
content: `
|
content: `
|
||||||
body {
|
body {
|
||||||
@ -39,7 +50,7 @@ body {
|
|||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
fileType: FileType.SCSS,
|
fileType: cfg.fileType,
|
||||||
name: COMMON_CHUNK_NAME.StyleCssContent,
|
name: COMMON_CHUNK_NAME.StyleCssContent,
|
||||||
content: ir.css || '',
|
content: ir.css || '',
|
||||||
linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
|
linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '../../const/generator';
|
import { COMMON_CHUNK_NAME } from '../../const/generator';
|
||||||
import { generateCompositeType } from '../../utils/compositeType';
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
BuilderComponentPluginFactory,
|
BuilderComponentPluginFactory,
|
||||||
@ -16,8 +16,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ir = next.ir as IProjectInfo;
|
const ir = next.ir as IProjectInfo;
|
||||||
if (ir.i18n) {
|
const i18nStr = ir.i18n ? JSON.stringify(ir.i18n, null, 2) : '{}';
|
||||||
const i18nStr = generateCompositeType(ir.i18n);
|
|
||||||
|
|
||||||
next.chunks.push({
|
next.chunks.push({
|
||||||
type: ChunkType.STRING,
|
type: ChunkType.STRING,
|
||||||
@ -25,9 +24,12 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
name: COMMON_CHUNK_NAME.FileMainContent,
|
name: COMMON_CHUNK_NAME.FileMainContent,
|
||||||
content: `
|
content: `
|
||||||
const i18nConfig = ${i18nStr};
|
const i18nConfig = ${i18nStr};
|
||||||
let locale = 'en_US';
|
|
||||||
|
|
||||||
const changeLocale = (target) => {
|
let locale = 'en-US';
|
||||||
|
|
||||||
|
const getLocale = () => locale;
|
||||||
|
|
||||||
|
const setLocale = (target) => {
|
||||||
locale = target;
|
locale = target;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,7 +50,8 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
name: COMMON_CHUNK_NAME.FileExport,
|
name: COMMON_CHUNK_NAME.FileExport,
|
||||||
content: `
|
content: `
|
||||||
export {
|
export {
|
||||||
changeLocale,
|
getLocale,
|
||||||
|
setLocale,
|
||||||
i18n,
|
i18n,
|
||||||
};
|
};
|
||||||
`,
|
`,
|
||||||
@ -61,8 +64,6 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
|||||||
COMMON_CHUNK_NAME.FileMainContent,
|
COMMON_CHUNK_NAME.FileMainContent,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
};
|
};
|
||||||
return plugin;
|
return plugin;
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import { isIdentifier, Node } from '@babel/types';
|
|||||||
import { OrderedSet } from './OrderedSet';
|
import { OrderedSet } from './OrderedSet';
|
||||||
|
|
||||||
export class ParseError extends Error {
|
export class ParseError extends Error {
|
||||||
constructor(readonly expr: string, readonly detail: unknown) {
|
constructor(readonly expr: string | t.Expression, readonly detail: unknown) {
|
||||||
super(`Failed to parse expression "${expr}"`);
|
super(`Failed to parse expression "${typeof expr === 'string' ? expr : generate(expr)}"`);
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
Object.setPrototypeOf(this, new.target.prototype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ export function parseExpressionGetGlobalVariables(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseExpressionConvertThis2Context(
|
export function parseExpressionConvertThis2Context(
|
||||||
expr: string,
|
expr: string | t.Expression,
|
||||||
contextName = '__$$context',
|
contextName = '__$$context',
|
||||||
localVariables: string[] = [],
|
localVariables: string[] = [],
|
||||||
): string {
|
): string {
|
||||||
@ -168,7 +168,7 @@ export function parseExpressionConvertThis2Context(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const exprAst = parser.parseExpression(expr);
|
const exprAst = typeof expr === 'string' ? parser.parseExpression(expr) : expr;
|
||||||
const exprWrapAst = t.expressionStatement(exprAst);
|
const exprWrapAst = t.expressionStatement(exprAst);
|
||||||
const fileAst = t.file(t.program([exprWrapAst]));
|
const fileAst = t.file(t.program([exprWrapAst]));
|
||||||
|
|
||||||
@ -229,11 +229,14 @@ export function parseExpressionConvertThis2Context(
|
|||||||
const { code } = generate(exprWrapAst.expression, { sourceMaps: false });
|
const { code } = generate(exprWrapAst.expression, { sourceMaps: false });
|
||||||
return code;
|
return code;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// throw new ParseError(expr, e);
|
throw new ParseError(expr, e);
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function indent(level: number) {
|
export function parseExpression(expr: string) {
|
||||||
return ' '.repeat(level);
|
try {
|
||||||
|
return parser.parseExpression(expr);
|
||||||
|
} catch (e) {
|
||||||
|
throw new ParseError(expr, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
const i18nConfig = {};
|
||||||
|
|
||||||
|
let locale = 'en-US';
|
||||||
|
|
||||||
|
const getLocale = () => locale;
|
||||||
|
|
||||||
|
const setLocale = (target) => {
|
||||||
|
locale = target;
|
||||||
|
};
|
||||||
|
|
||||||
|
const i18n = (key) => (i18nConfig && i18nConfig[locale] && i18nConfig[locale][key]) || '';
|
||||||
|
|
||||||
|
export { getLocale, setLocale, i18n };
|
||||||
@ -13,6 +13,8 @@ import { isMiniApp as __$$isMiniApp } from 'universal-env';
|
|||||||
|
|
||||||
import __$$constants from '../../constants';
|
import __$$constants from '../../constants';
|
||||||
|
|
||||||
|
import * as __$$i18n from '../../i18n';
|
||||||
|
|
||||||
import __$$projectUtils from '../../utils';
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
@ -22,6 +24,8 @@ class Home$$Page extends Component {
|
|||||||
|
|
||||||
_context = this._createContext();
|
_context = this._createContext();
|
||||||
|
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
|
||||||
_dataSourceConfig = this._defineDataSourceConfig();
|
_dataSourceConfig = this._defineDataSourceConfig();
|
||||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
||||||
|
|
||||||
@ -74,12 +78,33 @@ class Home$$Page extends Component {
|
|||||||
get constants() {
|
get constants() {
|
||||||
return __$$constants;
|
return __$$constants;
|
||||||
},
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
...this._methods,
|
...this._methods,
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_defineDataSourceConfig() {
|
_defineDataSourceConfig() {
|
||||||
const __$$context = this._context;
|
const __$$context = this._context;
|
||||||
return { list: [] };
|
return { list: [] };
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
// 本例是一个非常简单的 Hello world 页面
|
||||||
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
componentsMap: [
|
componentsMap: [
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
const i18nConfig = {};
|
||||||
|
|
||||||
|
let locale = 'en-US';
|
||||||
|
|
||||||
|
const getLocale = () => locale;
|
||||||
|
|
||||||
|
const setLocale = (target) => {
|
||||||
|
locale = target;
|
||||||
|
};
|
||||||
|
|
||||||
|
const i18n = (key) => (i18nConfig && i18nConfig[locale] && i18nConfig[locale][key]) || '';
|
||||||
|
|
||||||
|
export { getLocale, setLocale, i18n };
|
||||||
@ -19,6 +19,8 @@ import { isMiniApp as __$$isMiniApp } from 'universal-env';
|
|||||||
|
|
||||||
import __$$constants from '../../constants';
|
import __$$constants from '../../constants';
|
||||||
|
|
||||||
|
import * as __$$i18n from '../../i18n';
|
||||||
|
|
||||||
import __$$projectUtils from '../../utils';
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
@ -45,6 +47,8 @@ class Home$$Page extends Component {
|
|||||||
|
|
||||||
_context = this._createContext();
|
_context = this._createContext();
|
||||||
|
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
|
||||||
_dataSourceConfig = this._defineDataSourceConfig();
|
_dataSourceConfig = this._defineDataSourceConfig();
|
||||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, {
|
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, {
|
||||||
runtimeConfig: true,
|
runtimeConfig: true,
|
||||||
@ -171,12 +175,33 @@ class Home$$Page extends Component {
|
|||||||
get constants() {
|
get constants() {
|
||||||
return __$$constants;
|
return __$$constants;
|
||||||
},
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
...this._methods,
|
...this._methods,
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_defineDataSourceConfig() {
|
_defineDataSourceConfig() {
|
||||||
const __$$context = this._context;
|
const __$$context = this._context;
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
// 本例是一个比较复杂的,带有循环和条件渲染的,以及有各种事件处理函数的页面
|
||||||
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
componentsMap: [
|
componentsMap: [
|
||||||
@ -87,7 +88,7 @@
|
|||||||
isSync: true,
|
isSync: true,
|
||||||
},
|
},
|
||||||
dataHandler: {
|
dataHandler: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'function (response) {\nif (!response.success){\n throw new Error(response.message);\n }\n return response.data;\n}',
|
value: 'function (response) {\nif (!response.success){\n throw new Error(response.message);\n }\n return response.data;\n}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -104,13 +105,13 @@
|
|||||||
isSync: true,
|
isSync: true,
|
||||||
},
|
},
|
||||||
dataHandler: {
|
dataHandler: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'function (response) {\nif (!response.success){\n throw new Error(response.message);\n }\n return response.data.result;\n}',
|
value: 'function (response) {\nif (!response.success){\n throw new Error(response.message);\n }\n return response.data.result;\n}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
dataHandler: {
|
dataHandler: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}',
|
value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -164,7 +165,7 @@
|
|||||||
componentName: 'View',
|
componentName: 'View',
|
||||||
props: {
|
props: {
|
||||||
onClick: {
|
onClick: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'this.hello',
|
value: 'this.hello',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -210,7 +211,7 @@
|
|||||||
props: {
|
props: {
|
||||||
style: { flexDirection: 'row' },
|
style: { flexDirection: 'row' },
|
||||||
onClick: {
|
onClick: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'function(){ this.utils.recordEvent(`CLICK_ORDER`, this.order.title) }',
|
value: 'function(){ this.utils.recordEvent(`CLICK_ORDER`, this.order.title) }',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -260,7 +261,7 @@
|
|||||||
componentName: 'View',
|
componentName: 'View',
|
||||||
props: {
|
props: {
|
||||||
onClick: {
|
onClick: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'function (){ this.setState({ clickCount: this.state.clickCount + 1 }) }',
|
value: 'function (){ this.setState({ clickCount: this.state.clickCount + 1 }) }',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -312,7 +313,7 @@
|
|||||||
name: 'formatPrice',
|
name: 'formatPrice',
|
||||||
type: 'function',
|
type: 'function',
|
||||||
content: {
|
content: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'function formatPrice(price, unit) { return Number(price).toFixed(2) + unit; }',
|
value: 'function formatPrice(price, unit) { return Number(price).toFixed(2) + unit; }',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -321,7 +322,7 @@
|
|||||||
name: 'recordEvent',
|
name: 'recordEvent',
|
||||||
type: 'function',
|
type: 'function',
|
||||||
content: {
|
content: {
|
||||||
type: 'JSFunction',
|
type: 'JSExpression',
|
||||||
value: 'function recordEvent(eventName, eventDetail) { \n this.utils.Toast.show(`[EVENT]: ${eventName} ${eventDetail}`);\n console.log(`[EVENT]: ${eventName} (detail: %o) (user: %o)`, eventDetail, this.state.user); }',
|
value: 'function recordEvent(eventName, eventDetail) { \n this.utils.Toast.show(`[EVENT]: ${eventName} ${eventDetail}`);\n console.log(`[EVENT]: ${eventName} (detail: %o) (user: %o)`, eventDetail, this.state.user); }',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
const i18nConfig = {};
|
||||||
|
|
||||||
|
let locale = 'en-US';
|
||||||
|
|
||||||
|
const getLocale = () => locale;
|
||||||
|
|
||||||
|
const setLocale = (target) => {
|
||||||
|
locale = target;
|
||||||
|
};
|
||||||
|
|
||||||
|
const i18n = (key) => (i18nConfig && i18nConfig[locale] && i18nConfig[locale][key]) || '';
|
||||||
|
|
||||||
|
export { getLocale, setLocale, i18n };
|
||||||
@ -17,6 +17,8 @@ import { isMiniApp as __$$isMiniApp } from 'universal-env';
|
|||||||
|
|
||||||
import __$$constants from '../../constants';
|
import __$$constants from '../../constants';
|
||||||
|
|
||||||
|
import * as __$$i18n from '../../i18n';
|
||||||
|
|
||||||
import __$$projectUtils from '../../utils';
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
@ -28,6 +30,8 @@ class Detail$$Page extends Component {
|
|||||||
|
|
||||||
_context = this._createContext();
|
_context = this._createContext();
|
||||||
|
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
|
||||||
_dataSourceConfig = this._defineDataSourceConfig();
|
_dataSourceConfig = this._defineDataSourceConfig();
|
||||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
||||||
|
|
||||||
@ -85,12 +89,33 @@ class Detail$$Page extends Component {
|
|||||||
get constants() {
|
get constants() {
|
||||||
return __$$constants;
|
return __$$constants;
|
||||||
},
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
...this._methods,
|
...this._methods,
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_defineDataSourceConfig() {
|
_defineDataSourceConfig() {
|
||||||
const __$$context = this._context;
|
const __$$context = this._context;
|
||||||
return { list: [] };
|
return { list: [] };
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import { isMiniApp as __$$isMiniApp } from 'universal-env';
|
|||||||
|
|
||||||
import __$$constants from '../../constants';
|
import __$$constants from '../../constants';
|
||||||
|
|
||||||
|
import * as __$$i18n from '../../i18n';
|
||||||
|
|
||||||
import __$$projectUtils from '../../utils';
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
@ -28,6 +30,8 @@ class Home$$Page extends Component {
|
|||||||
|
|
||||||
_context = this._createContext();
|
_context = this._createContext();
|
||||||
|
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
|
||||||
_dataSourceConfig = this._defineDataSourceConfig();
|
_dataSourceConfig = this._defineDataSourceConfig();
|
||||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
||||||
|
|
||||||
@ -85,12 +89,33 @@ class Home$$Page extends Component {
|
|||||||
get constants() {
|
get constants() {
|
||||||
return __$$constants;
|
return __$$constants;
|
||||||
},
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
...this._methods,
|
...this._methods,
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_defineDataSourceConfig() {
|
_defineDataSourceConfig() {
|
||||||
const __$$context = this._context;
|
const __$$context = this._context;
|
||||||
return { list: [] };
|
return { list: [] };
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import { isMiniApp as __$$isMiniApp } from 'universal-env';
|
|||||||
|
|
||||||
import __$$constants from '../../constants';
|
import __$$constants from '../../constants';
|
||||||
|
|
||||||
|
import * as __$$i18n from '../../i18n';
|
||||||
|
|
||||||
import __$$projectUtils from '../../utils';
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
@ -28,6 +30,8 @@ class List$$Page extends Component {
|
|||||||
|
|
||||||
_context = this._createContext();
|
_context = this._createContext();
|
||||||
|
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
|
||||||
_dataSourceConfig = this._defineDataSourceConfig();
|
_dataSourceConfig = this._defineDataSourceConfig();
|
||||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
||||||
|
|
||||||
@ -88,12 +92,33 @@ class List$$Page extends Component {
|
|||||||
get constants() {
|
get constants() {
|
||||||
return __$$constants;
|
return __$$constants;
|
||||||
},
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
...this._methods,
|
...this._methods,
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_defineDataSourceConfig() {
|
_defineDataSourceConfig() {
|
||||||
const __$$context = this._context;
|
const __$$context = this._context;
|
||||||
return { list: [] };
|
return { list: [] };
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
// 本例是一个路由测试页面,里面有几个页面,相互之间有跳转关系的
|
||||||
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
componentsMap: [
|
componentsMap: [
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
const i18nConfig = {};
|
||||||
|
|
||||||
|
let locale = 'en-US';
|
||||||
|
|
||||||
|
const getLocale = () => locale;
|
||||||
|
|
||||||
|
const setLocale = (target) => {
|
||||||
|
locale = target;
|
||||||
|
};
|
||||||
|
|
||||||
|
const i18n = (key) => (i18nConfig && i18nConfig[locale] && i18nConfig[locale][key]) || '';
|
||||||
|
|
||||||
|
export { getLocale, setLocale, i18n };
|
||||||
@ -17,6 +17,8 @@ import { isMiniApp as __$$isMiniApp } from 'universal-env';
|
|||||||
|
|
||||||
import __$$constants from '../../constants';
|
import __$$constants from '../../constants';
|
||||||
|
|
||||||
|
import * as __$$i18n from '../../i18n';
|
||||||
|
|
||||||
import __$$projectUtils from '../../utils';
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
@ -28,6 +30,8 @@ class Home$$Page extends Component {
|
|||||||
|
|
||||||
_context = this._createContext();
|
_context = this._createContext();
|
||||||
|
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
|
||||||
_dataSourceConfig = this._defineDataSourceConfig();
|
_dataSourceConfig = this._defineDataSourceConfig();
|
||||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
||||||
|
|
||||||
@ -82,12 +86,33 @@ class Home$$Page extends Component {
|
|||||||
get constants() {
|
get constants() {
|
||||||
return __$$constants;
|
return __$$constants;
|
||||||
},
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
...this._methods,
|
...this._methods,
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_defineDataSourceConfig() {
|
_defineDataSourceConfig() {
|
||||||
const __$$context = this._context;
|
const __$$context = this._context;
|
||||||
return { list: [] };
|
return { list: [] };
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
// 本例是为了测试一下小程序的 runtime 模式
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
componentsMap: [
|
componentsMap: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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/demo5/expected/demo-project/.gitignore
vendored
Normal file
17
packages/code-generator/test-cases/rax-app/demo5/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,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/rax-app-demo",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "build-scripts build",
|
||||||
|
"start": "build-scripts start",
|
||||||
|
"lint": "eslint --ext .js --ext .jsx ./"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/lowcode-datasource-engine": "^0.1.0",
|
||||||
|
"universal-env": "^3.2.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"
|
||||||
|
},
|
||||||
|
"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,6 @@
|
|||||||
|
import { runApp } from 'rax-app';
|
||||||
|
import appConfig from './app.json';
|
||||||
|
|
||||||
|
import './global.scss';
|
||||||
|
|
||||||
|
runApp(appConfig);
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"path": "/",
|
||||||
|
"source": "pages/Home/index"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"window": {
|
||||||
|
"title": "Rax App Demo"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
const __$$constants = {};
|
||||||
|
|
||||||
|
export default __$$constants;
|
||||||
@ -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,3 @@
|
|||||||
|
body {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
const i18nConfig = {
|
||||||
|
'zh-CN': {
|
||||||
|
'hello-world': '你好,世界!',
|
||||||
|
},
|
||||||
|
'en-US': {
|
||||||
|
'hello-world': 'Hello world!',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let locale = 'en-US';
|
||||||
|
|
||||||
|
const getLocale = () => locale;
|
||||||
|
|
||||||
|
const setLocale = (target) => {
|
||||||
|
locale = target;
|
||||||
|
};
|
||||||
|
|
||||||
|
const i18n = (key) => (i18nConfig && i18nConfig[locale] && i18nConfig[locale][key]) || '';
|
||||||
|
|
||||||
|
export { getLocale, setLocale, i18n };
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。
|
||||||
|
// 例外:rax 框架的导出名和各种组件名除外。
|
||||||
|
import { createElement, Component } from 'rax';
|
||||||
|
import { withRouter as __$$withRouter } from 'rax-app';
|
||||||
|
|
||||||
|
import Page from 'rax-view';
|
||||||
|
|
||||||
|
import Text from 'rax-text';
|
||||||
|
|
||||||
|
import { create as __$$createDataSourceEngine } from '@ali/lowcode-datasource-engine';
|
||||||
|
|
||||||
|
import { isMiniApp as __$$isMiniApp } from 'universal-env';
|
||||||
|
|
||||||
|
import __$$constants from '../../constants';
|
||||||
|
|
||||||
|
import * as __$$i18n from '../../i18n';
|
||||||
|
|
||||||
|
import __$$projectUtils from '../../utils';
|
||||||
|
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
class Home$$Page extends Component {
|
||||||
|
_methods = this._defineMethods();
|
||||||
|
|
||||||
|
_context = this._createContext();
|
||||||
|
|
||||||
|
_i18n = this._createI18nDelegate();
|
||||||
|
|
||||||
|
_dataSourceConfig = this._defineDataSourceConfig();
|
||||||
|
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });
|
||||||
|
|
||||||
|
_utils = this._defineUtils();
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this._dataSourceEngine.reloadDataSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const __$$context = this._context;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<Text
|
||||||
|
onClick={function () {
|
||||||
|
__$$context.setLocale(__$$context.getLocale() === 'en-US' ? 'zh-CN' : 'en-US');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{__$$eval(() => __$$context.i18n['hello-world'])}
|
||||||
|
</Text>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createContext() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
get state() {
|
||||||
|
return self.state;
|
||||||
|
},
|
||||||
|
setState(newState) {
|
||||||
|
self.setState(newState);
|
||||||
|
},
|
||||||
|
get dataSourceMap() {
|
||||||
|
return self._dataSourceEngine.dataSourceMap || {};
|
||||||
|
},
|
||||||
|
async reloadDataSource() {
|
||||||
|
await self._dataSourceEngine.reloadDataSource();
|
||||||
|
},
|
||||||
|
get utils() {
|
||||||
|
return self._utils;
|
||||||
|
},
|
||||||
|
get page() {
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
get component() {
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
get props() {
|
||||||
|
return self.props;
|
||||||
|
},
|
||||||
|
get constants() {
|
||||||
|
return __$$constants;
|
||||||
|
},
|
||||||
|
get i18n() {
|
||||||
|
return self._i18n;
|
||||||
|
},
|
||||||
|
getLocale() {
|
||||||
|
return __$$i18n.getLocale();
|
||||||
|
},
|
||||||
|
setLocale(locale) {
|
||||||
|
__$$i18n.setLocale(locale);
|
||||||
|
self.forceUpdate();
|
||||||
|
},
|
||||||
|
...this._methods,
|
||||||
|
};
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createI18nDelegate() {
|
||||||
|
return new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
get(target, prop) {
|
||||||
|
return __$$i18n.i18n(prop);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_defineDataSourceConfig() {
|
||||||
|
const __$$context = this._context;
|
||||||
|
return { list: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
_defineUtils() {
|
||||||
|
const utils = {
|
||||||
|
...__$$projectUtils,
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.entries(utils).forEach(([name, util]) => {
|
||||||
|
if (typeof util === 'function') {
|
||||||
|
utils[name] = util.bind(this._context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return utils;
|
||||||
|
}
|
||||||
|
|
||||||
|
_defineMethods() {
|
||||||
|
const __$$methods = {};
|
||||||
|
|
||||||
|
// 为所有的方法绑定上下文
|
||||||
|
Object.entries(__$$methods).forEach(([methodName, method]) => {
|
||||||
|
if (typeof method === 'function') {
|
||||||
|
__$$methods[methodName] = (...args) => {
|
||||||
|
return method.apply(this._context, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return __$$methods;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default __$$withRouter(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 @@
|
|||||||
|
export default {};
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
// 这是一个关于国际化的 schema 示例
|
||||||
|
// Schema 参见:https://yuque.antfin-inc.com/mo/spec/spec-materials#eNCJr
|
||||||
|
version: '1.0.0',
|
||||||
|
componentsMap: [
|
||||||
|
{
|
||||||
|
componentName: 'Page',
|
||||||
|
package: 'rax-view',
|
||||||
|
version: '^1.0.0',
|
||||||
|
destructuring: false,
|
||||||
|
exportName: 'Page',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
package: 'rax-text',
|
||||||
|
version: '^1.0.0',
|
||||||
|
destructuring: false,
|
||||||
|
exportName: 'Text',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
componentsTree: [
|
||||||
|
{
|
||||||
|
componentName: 'Page',
|
||||||
|
props: {},
|
||||||
|
lifeCycles: {},
|
||||||
|
fileName: 'home',
|
||||||
|
meta: {
|
||||||
|
router: '/',
|
||||||
|
},
|
||||||
|
dataSource: {
|
||||||
|
list: [],
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
props: {
|
||||||
|
onClick: {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: "function () {\n this.setLocale(this.getLocale() === 'en-US' ? 'zh-CN' : 'en-US');\n}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: 'this.i18n["hello-world"]',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
i18n: {
|
||||||
|
'zh-CN': {
|
||||||
|
'hello-world': '你好,世界!',
|
||||||
|
},
|
||||||
|
'en-US': {
|
||||||
|
'hello-world': 'Hello world!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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: '张三',
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -7,8 +7,8 @@ import path from 'path';
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
|
||||||
import CodeGenerator from '../src';
|
import CodeGenerator from '../src';
|
||||||
import createRaxAppBuilder from '../src/solutions/rax-app';
|
|
||||||
import { IProjectSchema } from '../src/types/schema';
|
import type { IProjectSchema } from '../src/types/schema';
|
||||||
|
|
||||||
const TEST_CASES_DIR = path.join(__dirname, '../test-cases/rax-app');
|
const TEST_CASES_DIR = path.join(__dirname, '../test-cases/rax-app');
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ function defineTest(caseDirName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function exportProject(schemaJson: IProjectSchema, targetPath: string, projectName: string) {
|
async function exportProject(schemaJson: IProjectSchema, targetPath: string, projectName: string) {
|
||||||
const raxAppBuilder = createRaxAppBuilder();
|
const raxAppBuilder = CodeGenerator.solutions.rax();
|
||||||
const result = await raxAppBuilder.generateProject(schemaJson);
|
const result = await raxAppBuilder.generateProject(schemaJson);
|
||||||
const publisher = CodeGenerator.publishers.disk();
|
const publisher = CodeGenerator.publishers.disk();
|
||||||
await publisher.publish({
|
await publisher.publish({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user