Compare commits

...

9 Commits

Author SHA1 Message Date
牧毅
7e43814008 chore(release): 1.0.4-beta.1 2022-04-11 12:19:13 +08:00
牧毅
987f4cea54 fix: 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 __$evalArray 的问题 2022-04-11 12:18:44 +08:00
Clarence-pan
c18bc0261c chore(release): 1.0.4-beta.0 2022-04-11 00:32:40 +08:00
Clarence-pan
c228907fe4 test: 💍 更新 i18n 相关测试用例的快照 2022-04-11 00:29:52 +08:00
Clarence-pan
1e9e388ce9 fix: 🐛 修正 i18n 里面的一个参数命名问题 2022-04-10 23:56:56 +08:00
Clarence-pan
67dabb04be fix: 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 __$eval 中用到 window 的问题
-- 解决方法: 将这个 __$$eval 的错误处理的默认行为搞成配置化的, 支持从外面传入...
2022-04-10 20:29:41 +08:00
Clarence-pan
9019c96f43 test: 💍 增加关于严格模式的测试用例 2022-04-10 19:23:35 +08:00
Clarence-pan
79db4ac97f fix: 修正 react 框架出码中在严格模式对 methods 和 context 的处理 2022-04-10 19:12:44 +08:00
Clarence-pan
1eb9addd8d fix: 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题
https://github.com/alibaba/lowcode-engine/issues/288

 Closes: #288
2022-04-10 18:38:28 +08:00
107 changed files with 4303 additions and 1012 deletions

View File

@ -2,6 +2,30 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [1.0.4-beta.1](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.4-beta.0...@alilc/lowcode-code-generator@1.0.4-beta.1) (2022-04-11)
### Bug Fixes
* 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 __$evalArray 的问题 ([987f4ce](https://github.com/alibaba/lowcode-engine/commit/987f4cea54ef8a75d0b63a0268b5a20b2938b8a7))
### [1.0.4-beta.0](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.3...@alilc/lowcode-code-generator@1.0.4-beta.0) (2022-04-10)
### Features
* **material-parser:** check module before install it; fix default value issue in ts parser ([fc452f7](https://github.com/alibaba/lowcode-engine/commit/fc452f7166f02acfba6076c1a9425e6f5880b5f6))
### Bug Fixes
* 🐛 修正 i18n 里面的一个参数命名问题 ([1e9e388](https://github.com/alibaba/lowcode-engine/commit/1e9e388ce9104d76c4f6d9bc513c57e5059d7982))
* 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题 ([1eb9add](https://github.com/alibaba/lowcode-engine/commit/1eb9addd8df2323f9aabac87af32ac2efcd6bf22)), closes [#288](https://github.com/alibaba/lowcode-engine/issues/288)
* 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 __$eval 中用到 window 的问题 ([67dabb0](https://github.com/alibaba/lowcode-engine/commit/67dabb04beb32b6e94eb1276222e53b416e47c9d))
* Fix the conversion failure of some props expressions under Slot props of low-code components ([7db5461](https://github.com/alibaba/lowcode-engine/commit/7db5461706c739fac673b2466bc2fda7661242e4))
* fix unnecessary props calculation ([f1fed75](https://github.com/alibaba/lowcode-engine/commit/f1fed75f39be8289ede1ec558b04428a69e25b5f))
* 修正 react 框架出码中在严格模式对 methods 和 context 的处理 ([79db4ac](https://github.com/alibaba/lowcode-engine/commit/79db4ac97f34f24b7f7460fb3fc67521967f8cc5))
### [1.0.3](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2...@alilc/lowcode-code-generator@1.0.3) (2022-03-29) ### [1.0.3](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2...@alilc/lowcode-code-generator@1.0.3) (2022-03-29)

View File

@ -6,4 +6,5 @@ module.exports = {
collectCoverage: false, collectCoverage: false,
collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/node_modules/**', '!**/vendor/**'], collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/node_modules/**', '!**/vendor/**'],
testMatch: ['<rootDir>/tests/**/*.test.ts'], testMatch: ['<rootDir>/tests/**/*.test.ts'],
setupFiles: ['./jest.setup.js'],
}; };

View File

@ -0,0 +1,12 @@
// 对于 standalone 模式的专门 polyfills
if (process.env.TEST_TARGET === 'standalone') {
// 模拟浏览器环境
global.window = global;
global.self = global;
// 将所有测试用例里面的 './src' 都替换为 './dist/standalone'
jest.mock('./src', () => require('./dist/standalone'));
}
// 如果在调试模式下,则不限制超时时间
jest.setTimeout(typeof v8debug === 'object' ? Infinity : 30 * 1000);

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-code-generator", "name": "@alilc/lowcode-code-generator",
"version": "1.0.3", "version": "1.0.4-beta.1",
"description": "出码引擎 for LowCode Engine", "description": "出码引擎 for LowCode Engine",
"license": "MIT", "license": "MIT",
"main": "lib/index.js", "main": "lib/index.js",
@ -75,6 +75,7 @@
"change-case": "^3.1.0", "change-case": "^3.1.0",
"commander": "^6.1.0", "commander": "^6.1.0",
"debug": "^4.3.2", "debug": "^4.3.2",
"fp-ts": "^2.11.9",
"fs-extra": "9.x", "fs-extra": "9.x",
"glob": "^7.2.0", "glob": "^7.2.0",
"html-entities": "^2.3.2", "html-entities": "^2.3.2",
@ -85,6 +86,7 @@
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mock-fs": "^5.1.2", "mock-fs": "^5.1.2",
"moment": "^2.29.1", "moment": "^2.29.1",
"nanomatch": "^1.2.13",
"node-fetch": "2.x", "node-fetch": "2.x",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"prettier": "^2.5.1", "prettier": "^2.5.1",

View File

@ -0,0 +1,55 @@
#!/usr/bin/env node
// @ts-check
const program = require('commander');
const { spawnSync } = require('child_process');
const glob = require('glob');
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
program
.option('--npm <npm>', 'specify the npm command location or alias')
.arguments('<project>')
.action((project, options) => {
try {
if (!fs.existsSync(project)) {
throw new Error(`Project ${project} does not exist`);
}
const getProjectActualPath = [
() => path.resolve(process.cwd(), project),
() =>
path.resolve(
process.cwd(),
path.join(
project,
path.dirname(glob.sync('*/package.json', { cwd: project })[0] || ''),
),
),
]
.map((x) => _.memoize(x))
.find((x) => fs.existsSync(path.join(x(), 'package.json')));
if (!getProjectActualPath) {
throw new Error(`Project ${project} is not a valid project(no package.json)`);
}
const projectActualPath = getProjectActualPath();
if (path.resolve(process.cwd(), project) !== projectActualPath) {
console.log('Changing directory to', path.relative(process.cwd(), projectActualPath));
}
process.chdir(projectActualPath);
const npm = options.npm || 'npm';
const cmd = `${npm} install && ${npm} start`;
console.log('# %s', cmd);
spawnSync(cmd, { stdio: 'inherit', shell: true });
} catch (err) {
console.log(err);
process.exit(1);
}
});
program.parse(process.argv);

View File

@ -638,6 +638,7 @@ export default function createHelloWorldProjectBuilder() {
CodeGen.plugins.react.reactCommonDeps(), CodeGen.plugins.react.reactCommonDeps(),
CodeGen.plugins.common.esmodule({ fileType: 'jsx' }), CodeGen.plugins.common.esmodule({ fileType: 'jsx' }),
CodeGen.plugins.react.containerClass(), CodeGen.plugins.react.containerClass(),
CodeGen.plugins.react.containerInjectContext(),
CodeGen.plugins.react.containerInjectUtils(), CodeGen.plugins.react.containerInjectUtils(),
CodeGen.plugins.react.containerInjectDataSourceEngine(), CodeGen.plugins.react.containerInjectDataSourceEngine(),
CodeGen.plugins.react.containerInjectI18n(), CodeGen.plugins.react.containerInjectI18n(),
@ -659,6 +660,7 @@ export default function createHelloWorldProjectBuilder() {
CodeGen.plugins.react.reactCommonDeps(), CodeGen.plugins.react.reactCommonDeps(),
CodeGen.plugins.common.esmodule({ fileType: 'jsx' }), CodeGen.plugins.common.esmodule({ fileType: 'jsx' }),
CodeGen.plugins.react.containerClass(), CodeGen.plugins.react.containerClass(),
CodeGen.plugins.react.containerInjectContext(),
CodeGen.plugins.react.containerInjectUtils(), CodeGen.plugins.react.containerInjectUtils(),
CodeGen.plugins.react.containerInjectDataSourceEngine(), CodeGen.plugins.react.containerInjectDataSourceEngine(),
CodeGen.plugins.react.containerInjectI18n(), CodeGen.plugins.react.containerInjectI18n(),

View File

@ -5,6 +5,7 @@ import {
CodeGeneratorError, CodeGeneratorError,
ICodeChunk, ICodeChunk,
ICompiledModule, ICompiledModule,
IContextData,
IModuleBuilder, IModuleBuilder,
IParseResult, IParseResult,
ISchemaParser, ISchemaParser,
@ -23,6 +24,7 @@ export function createModuleBuilder(
plugins: BuilderComponentPlugin[]; plugins: BuilderComponentPlugin[];
postProcessors: PostProcessor[]; postProcessors: PostProcessor[];
mainFileName?: string; mainFileName?: string;
contextData?: IContextData;
} = { } = {
plugins: [], plugins: [],
postProcessors: [], postProcessors: [],
@ -41,7 +43,13 @@ export function createModuleBuilder(
let files: ResultFile[] = []; let files: ResultFile[] = [];
const { chunks } = await chunkGenerator.run(input); const { chunks } = await chunkGenerator.run(input, {
ir: input,
chunks: [],
depNames: [],
contextData: options.contextData || {},
});
chunks.forEach((fileChunkList) => { chunks.forEach((fileChunkList) => {
const content = linker.link(fileChunkList); const content = linker.link(fileChunkList);
const file = createResultFile( const file = createResultFile(

View File

@ -14,7 +14,7 @@ import { SchemaParser } from '../parser/SchemaParser';
import { createResultDir, addDirectory, addFile } from '../utils/resultHelper'; import { createResultDir, addDirectory, addFile } from '../utils/resultHelper';
import { createModuleBuilder } from './ModuleBuilder'; import { createModuleBuilder } from './ModuleBuilder';
import { ProjectPreProcessor, ProjectPostProcessor } from '../types/core'; import { ProjectPreProcessor, ProjectPostProcessor, IContextData } from '../types/core';
import { CodeGeneratorError } from '../types/error'; import { CodeGeneratorError } from '../types/error';
interface IModuleInfo { interface IModuleInfo {
@ -36,6 +36,10 @@ export interface ProjectBuilderInitOptions {
projectPreProcessors?: ProjectPreProcessor[]; projectPreProcessors?: ProjectPreProcessor[];
/** 项目级别的后置处理器 */ /** 项目级别的后置处理器 */
projectPostProcessors?: ProjectPostProcessor[]; projectPostProcessors?: ProjectPostProcessor[];
/** 是否处于严格模式 */
inStrictMode?: boolean;
/** 一些额外的上下文数据 */
extraContextData?: Record<string, unknown>;
} }
export class ProjectBuilder implements IProjectBuilder { export class ProjectBuilder implements IProjectBuilder {
@ -57,6 +61,12 @@ export class ProjectBuilder implements IProjectBuilder {
/** 项目级别的后置处理器 */ /** 项目级别的后置处理器 */
private projectPostProcessors: ProjectPostProcessor[]; private projectPostProcessors: ProjectPostProcessor[];
/** 是否处于严格模式 */
public readonly inStrictMode: boolean;
/** 一些额外的上下文数据 */
public readonly extraContextData: IContextData;
constructor({ constructor({
template, template,
plugins, plugins,
@ -64,6 +74,8 @@ export class ProjectBuilder implements IProjectBuilder {
schemaParser = new SchemaParser(), schemaParser = new SchemaParser(),
projectPreProcessors = [], projectPreProcessors = [],
projectPostProcessors = [], projectPostProcessors = [],
inStrictMode = false,
extraContextData = {},
}: ProjectBuilderInitOptions) { }: ProjectBuilderInitOptions) {
this.template = template; this.template = template;
this.plugins = plugins; this.plugins = plugins;
@ -71,6 +83,8 @@ export class ProjectBuilder implements IProjectBuilder {
this.schemaParser = schemaParser; this.schemaParser = schemaParser;
this.projectPreProcessors = projectPreProcessors; this.projectPreProcessors = projectPreProcessors;
this.projectPostProcessors = projectPostProcessors; this.projectPostProcessors = projectPostProcessors;
this.inStrictMode = inStrictMode;
this.extraContextData = extraContextData;
} }
async generateProject(originalSchema: ProjectSchema | string): Promise<ResultDir> { async generateProject(originalSchema: ProjectSchema | string): Promise<ResultDir> {
@ -264,6 +278,12 @@ export class ProjectBuilder implements IProjectBuilder {
builders[pluginName] = createModuleBuilder({ builders[pluginName] = createModuleBuilder({
plugins: this.plugins[pluginName], plugins: this.plugins[pluginName],
postProcessors: this.postProcessors, postProcessors: this.postProcessors,
contextData: {
inStrictMode: this.inStrictMode,
tolerateEvalErrors: true,
evalErrorsHandler: '',
...this.extraContextData,
},
...options, ...options,
}); });
} }

View File

@ -25,16 +25,8 @@ import i18n from './plugins/project/i18n';
import utils from './plugins/project/utils'; import utils from './plugins/project/utils';
import prettier from './postprocessor/prettier'; import prettier from './postprocessor/prettier';
// 引入常用工具 // 引入全局常用工具
import * as utilsCommon from './utils/common'; import * as globalUtils from './utils';
import * as utilsCompositeType from './utils/compositeType';
import * as utilsJsExpression from './utils/jsExpression';
import * as utilsJsSlot from './utils/jsSlot';
import * as utilsNodeToJSX from './utils/nodeToJSX';
import * as utilsResultHelper from './utils/resultHelper';
import * as utilsTemplateHelper from './utils/templateHelper';
import * as utilsValidate from './utils/validate';
import * as utilsSchema from './utils/schema';
import * as CONSTANTS from './const'; import * as CONSTANTS from './const';
@ -85,17 +77,7 @@ export default {
postprocessor: { postprocessor: {
prettier, prettier,
}, },
utils: { utils: globalUtils,
common: utilsCommon,
compositeType: utilsCompositeType,
jsExpression: utilsJsExpression,
jsSlot: utilsJsSlot,
nodeToJSX: utilsNodeToJSX,
resultHelper: utilsResultHelper,
templateHelper: utilsTemplateHelper,
validate: utilsValidate,
schema: utilsSchema,
},
chunkNames: { chunkNames: {
COMMON_CHUNK_NAME, COMMON_CHUNK_NAME,
CLASS_DEFINE_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME,

View File

@ -134,19 +134,6 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
], ],
}); });
next.chunks.push({
type: ChunkType.STRING,
fileType: FileType.JSX,
name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,
content: `
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
`,
linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],
});
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: FileType.JSX, fileType: FileType.JSX,

View File

@ -10,6 +10,7 @@ import {
IContainerInfo, IContainerInfo,
} from '../../../types'; } from '../../../types';
import { RAX_CHUNK_NAME } from './const'; import { RAX_CHUNK_NAME } from './const';
import { DEFAULT_LINK_AFTER } from '../../../const';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType: string;
@ -46,6 +47,16 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
}); });
next.chunks.push({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
content: `
__$$i18n._inject2(this);
`,
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],
});
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,

View File

@ -29,6 +29,11 @@ import { RAX_CHUNK_NAME } from './const';
export interface PluginConfig extends RaxFrameworkOptions { export interface PluginConfig extends RaxFrameworkOptions {
fileType?: string; fileType?: string;
/**
* handlers
* @deprecated 使 datasourceConfig.handlersPackages
*/
dataSourceHandlersPackageMap?: Record<string, string>; dataSourceHandlersPackageMap?: Record<string, string>;
} }

View File

@ -62,6 +62,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
const ir = next.ir as IContainerInfo; const ir = next.ir as IContainerInfo;
const rootScope = Scope.createRootScope(); const rootScope = Scope.createRootScope();
const { tolerateEvalErrors = true, evalErrorsHandler = '' } = next.contextData;
// Rax 构建到小程序的时候,不能给组件起起别名,得直接引用,故这里将所有的别名替换掉 // Rax 构建到小程序的时候,不能给组件起起别名,得直接引用,故这里将所有的别名替换掉
// 先收集下所有的 alias 的映射 // 先收集下所有的 alias 的映射
@ -86,7 +87,9 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
// 3. 通过 this.xxx 能拿到的东西太多了,而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东 // 3. 通过 this.xxx 能拿到的东西太多了,而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东
const customHandlers: HandlerSet<string> = { const customHandlers: HandlerSet<string> = {
expression(input: JSExpression, scope: IScope) { expression(input: JSExpression, scope: IScope) {
return transformJsExpr(generateExpression(input, scope), scope); return transformJsExpr(generateExpression(input, scope), scope, {
dontWrapEval: !tolerateEvalErrors,
});
}, },
function(input, scope: IScope) { function(input, scope: IScope) {
return transformThis2Context(input.value || 'null', scope); return transformThis2Context(input.value || 'null', scope);
@ -138,17 +141,14 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: COMMON_CHUNK_NAME.CustomContent, name: COMMON_CHUNK_NAME.CustomContent,
content: ` content: [
tolerateEvalErrors &&
`
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {
try { ${evalErrorsHandler}
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
} }
} }
@ -156,16 +156,57 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
const res = __$$eval(expr); const res = __$$eval(expr);
return Array.isArray(res) ? res : []; return Array.isArray(res) ? res : [];
} }
`,
`
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
return Object.assign({}, oldContext, ext); return Object.assign({}, oldContext, ext);
} }
`, `,
]
.filter(Boolean)
.join('\n'),
linkAfter: [COMMON_CHUNK_NAME.FileExport], linkAfter: [COMMON_CHUNK_NAME.FileExport],
}); });
return next; return next;
function generateRaxLoopCtrl(
nodeItem: NodeSchema,
scope: IScope,
config?: NodeGeneratorConfig,
next?: NodePlugin,
): CodePiece[] {
if (nodeItem.loop) {
const loopItemName = nodeItem.loopArgs?.[0] || 'item';
const loopIndexName = nodeItem.loopArgs?.[1] || 'index';
const subScope = scope.createSubScope([loopItemName, loopIndexName]);
const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : [];
const loopDataExpr = tolerateEvalErrors
? `__$$evalArray(() => (${transformThis2Context(
generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }),
scope,
)}))`
: `(${transformThis2Context(
generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }),
scope,
)})`;
pieces.unshift({
value: `${loopDataExpr}.map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`,
type: PIECE_TYPE.BEFORE,
});
pieces.push({
value: `))(__$$createChildContext(__$$context, { ${loopItemName}, ${loopIndexName} })))`,
type: PIECE_TYPE.AFTER,
});
return pieces;
}
return next ? next(nodeItem, scope, config) : [];
}
}; };
return plugin; return plugin;
@ -189,39 +230,6 @@ function isImportAliasDefineChunk(chunk: ICodeChunk): chunk is ICodeChunk & {
); );
} }
function generateRaxLoopCtrl(
nodeItem: NodeSchema,
scope: IScope,
config?: NodeGeneratorConfig,
next?: NodePlugin,
): CodePiece[] {
if (nodeItem.loop) {
const loopItemName = nodeItem.loopArgs?.[0] || 'item';
const loopIndexName = nodeItem.loopArgs?.[1] || 'index';
const subScope = scope.createSubScope([loopItemName, loopIndexName]);
const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : [];
const loopDataExpr = `__$$evalArray(() => (${transformThis2Context(
generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }),
scope,
)}))`;
pieces.unshift({
value: `${loopDataExpr}.map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`,
type: PIECE_TYPE.BEFORE,
});
pieces.push({
value: `))(__$$createChildContext(__$$context, { ${loopItemName}, ${loopIndexName} })))`,
type: PIECE_TYPE.AFTER,
});
return pieces;
}
return next ? next(nodeItem, scope, config) : [];
}
function generateNodeAttrForRax( function generateNodeAttrForRax(
this: { cfg: PluginConfig }, this: { cfg: PluginConfig },
attrData: { attrName: string; attrValue: CompositeValue }, attrData: { attrName: string; attrValue: CompositeValue },

View File

@ -0,0 +1,91 @@
import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';
import { Scope } from '../../../utils/Scope';
import {
BuilderComponentPlugin,
BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IContainerInfo,
} from '../../../types';
import { DEFAULT_LINK_AFTER } from '../../../const';
export interface 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;
const scope = Scope.createRootScope();
const { inStrictMode } = next.contextData;
if (!inStrictMode) {
// 非严格模式下,上下文就是自己
next.chunks.push({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsVar,
content: `
_context = this;
`,
linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],
});
} else {
// 严格模式下的上下文只保留协议中规定的那些
next.chunks.push({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsVar,
content: `
_context = this._createContext();
`,
linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],
});
next.chunks.push({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,
content: `
_createContext() {
const self = this;
const context = {
get state() { return self.state; },
setState(newState, callback) { self.setState(newState, callback); },
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 self.constants; },
get $() { return self.$ },
get $$() { return self.$$ },
...this._methods,
};
return context;
}
`,
linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod],
});
}
return next;
};
return plugin;
};
export default pluginFactory;

View File

@ -31,13 +31,34 @@ import { isContainerSchema } from '../../../utils/schema';
import { REACT_CHUNK_NAME } from './const'; import { REACT_CHUNK_NAME } from './const';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType?: string;
/**
*
*/
datasourceConfig?: {
/** 数据源引擎的版本 */
engineVersion?: string;
/** 数据源引擎的包名 */
enginePackage?: string;
/** 数据源 handlers 的版本 */
handlersVersion?: {
[key: string]: string;
};
/** 数据源 handlers 的包名 */
handlersPackages?: {
[key: string]: string;
};
};
} }
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
const cfg: PluginConfig = { const cfg = {
fileType: FileType.JSX,
...config, ...config,
fileType: config?.fileType || FileType.JSX,
}; };
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
@ -65,7 +86,9 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
}; };
const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`; const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`;
const handlerPkgName = `@alilc/lowcode-datasource-${changeCase.kebab(dsType)}-handler`; const handlerPkgName =
cfg.datasourceConfig?.handlersPackages?.[dsType] ||
`@alilc/lowcode-datasource-${changeCase.kebab(dsType)}-handler`;
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,

View File

@ -33,7 +33,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
name: COMMON_CHUNK_NAME.InternalDepsImport, name: COMMON_CHUNK_NAME.InternalDepsImport,
// TODO: 下面这个路径有没有更好的方式来获取?而非写死 // TODO: 下面这个路径有没有更好的方式来获取?而非写死
content: ` content: `
import { i18n as _$$i18n } from '../../i18n'; import * as __$$i18n from '../../i18n';
`, `,
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
}); });
@ -41,13 +41,11 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsMethod, name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
content: ` content: `
i18n = (i18nKey) => { __$$i18n._inject2(this);
return _$$i18n(i18nKey);
}
`, `,
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],
}); });
return next; return next;

View File

@ -83,6 +83,23 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
`, `,
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
}); });
} else {
// useRef 为 false 的时候是指没有组件在 props 中配置 ref 属性,但这个时候其实也可能有代码访问 this.$/$$ 所以还是加上个空的代码
next.chunks.push({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
content: ` $ = () => null; `,
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
});
next.chunks.push({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
content: ` $$ = () => []; `,
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
});
} }
return next; return next;

View File

@ -11,6 +11,7 @@ import {
ICodeStruct, ICodeStruct,
IContainerInfo, IContainerInfo,
} from '../../../types'; } from '../../../types';
import { isValidIdentifier } from '../../../utils/validate';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType: string;
@ -28,18 +29,37 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
}; };
const ir = next.ir as IContainerInfo; const ir = next.ir as IContainerInfo;
const { inStrictMode } = next.contextData;
if (ir.methods) { if (!ir.methods) {
const { methods } = ir; return next;
const chunks = Object.keys(methods).map<ICodeChunk>((methodName) => ({ }
// 将这些 methods 都定义到 class 上
const { methods } = ir;
const chunks = Object.keys(methods).map<ICodeChunk>((methodName) => ({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
content: generateFunction(methods[methodName], { name: methodName, isMember: true }),
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
}));
next.chunks.push(...chunks);
// 严格模式下需要将这些方法都挂到上下文中
if (inStrictMode) {
next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.InsMethod, name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
content: generateFunction(methods[methodName], { name: methodName, isMember: true }), content: Object.keys(ir.methods)
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], .map((methodName) =>
})); isValidIdentifier(methodName) ? `.${methodName}` : `[${JSON.stringify(methodName)}]`,
)
next.chunks.push(...chunks); .map((method) => `this._context${method} = this${method};`)
.join('\n'),
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],
});
} }
return next; return next;

View File

@ -42,12 +42,14 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
...pre, ...pre,
}; };
const { tolerateEvalErrors = true, evalErrorsHandler = '' } = next.contextData;
// 这里会将内部的一些子上下文的访问(this.xxx)转换为 __$$context.xxx 的形式 // 这里会将内部的一些子上下文的访问(this.xxx)转换为 __$$context.xxx 的形式
// 与 Rax 所不同的是,这里不会将最顶层的 this 转换掉 // 与 Rax 所不同的是,这里不会将最顶层的 this 转换掉
const customHandlers: HandlerSet<string> = { const customHandlers: HandlerSet<string> = {
expression(input: JSExpression, scope: IScope) { expression(input: JSExpression, scope: IScope, config) {
return transformJsExpr(generateExpression(input, scope), scope, { return transformJsExpr(generateExpression(input, scope), scope, {
dontWrapEval: true, dontWrapEval: !(config?.tolerateEvalErrors ?? tolerateEvalErrors),
dontTransformThis2ContextAtRootScope: true, dontTransformThis2ContextAtRootScope: true,
}); });
}, },
@ -69,6 +71,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
const generatorPlugins: NodeGeneratorConfig = { const generatorPlugins: NodeGeneratorConfig = {
handlers: customHandlers, handlers: customHandlers,
tagMapping: (v) => nodeTypeMapping[v] || v, tagMapping: (v) => nodeTypeMapping[v] || v,
tolerateEvalErrors,
}; };
if (next.contextData.useRefApi) { if (next.contextData.useRefApi) {
@ -100,8 +103,8 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
fileType: cfg.fileType, fileType: cfg.fileType,
name: REACT_CHUNK_NAME.ClassRenderJSX, name: REACT_CHUNK_NAME.ClassRenderJSX,
content: ` content: `
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ${jsxContent}; return ${jsxContent};
`, `,
linkAfter: [REACT_CHUNK_NAME.ClassRenderStart, REACT_CHUNK_NAME.ClassRenderPre], linkAfter: [REACT_CHUNK_NAME.ClassRenderStart, REACT_CHUNK_NAME.ClassRenderPre],
@ -111,7 +114,23 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: COMMON_CHUNK_NAME.CustomContent, name: COMMON_CHUNK_NAME.CustomContent,
content: ` content: [
tolerateEvalErrors &&
`
function __$$eval(expr) {
try {
return expr();
} catch (error) {
${evalErrorsHandler}
}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
`,
`
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,
@ -121,6 +140,9 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
return childContext; return childContext;
} }
`, `,
]
.filter(Boolean)
.join('\n'),
linkAfter: [COMMON_CHUNK_NAME.FileExport], linkAfter: [COMMON_CHUNK_NAME.FileExport],
}); });
return next; return next;

View File

@ -18,7 +18,10 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: FileType.JSX, fileType: FileType.JSX,
name: COMMON_CHUNK_NAME.ExternalDepsImport, name: COMMON_CHUNK_NAME.ExternalDepsImport,
content: 'import React from \'react\';', content: `
// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。
// 例外react 框架的导出名和各种组件名除外。
import React from \'react\';`,
linkAfter: [], linkAfter: [],
}); });

View File

@ -23,11 +23,9 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
fileType: FileType.JS, fileType: FileType.JS,
name: COMMON_CHUNK_NAME.FileMainContent, name: COMMON_CHUNK_NAME.FileMainContent,
content: ` content: `
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = ${i18nStr}; const i18nConfig = ${i18nStr};
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -35,23 +33,65 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = variables => (
const msg = i18nConfig && i18nConfig[locale] && i18nConfig[locale][id] || defaultMessage; Array.isArray(variables) && variables.length === 0
|| typeof variables === 'object' && (!variables || Object.keys(variables).length === 0)
);
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) => (
typeof msg === 'string'
? msg.replace(/\\\$\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')
: msg
);
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return \`\${id}\`; return fallback === undefined ? \`\${id}\` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg;
}
return new IntlMessageFormat(msg, locale).format(variables);
} }
const i18n = id => { const i18n = (id, params) => {
return i18nFormat({ id }); return i18nFormat({ id }, params);
}; };
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
}
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale, setLocale: target.setLocale
});
}
}
`, `,
linkAfter: [ linkAfter: [
COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.ExternalDepsImport,
@ -72,6 +112,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
setLocale, setLocale,
i18n, i18n,
i18nFormat, i18nFormat,
_inject2,
}; };
`, `,
linkAfter: [ linkAfter: [

View File

@ -1,10 +1,11 @@
import { IProjectBuilder } from '../types'; import { IProjectBuilder, IProjectBuilderOptions } from '../types';
import { createProjectBuilder } from '../generator/ProjectBuilder'; import { createProjectBuilder } from '../generator/ProjectBuilder';
import esmodule from '../plugins/common/esmodule'; import esmodule from '../plugins/common/esmodule';
import containerClass from '../plugins/component/react/containerClass'; import containerClass from '../plugins/component/react/containerClass';
import containerInitState from '../plugins/component/react/containerInitState'; import containerInitState from '../plugins/component/react/containerInitState';
import containerInjectContext from '../plugins/component/react/containerInjectContext';
import containerInjectUtils from '../plugins/component/react/containerInjectUtils'; import containerInjectUtils from '../plugins/component/react/containerInjectUtils';
import containerInjectDataSourceEngine from '../plugins/component/react/containerInjectDataSourceEngine'; import containerInjectDataSourceEngine from '../plugins/component/react/containerInjectDataSourceEngine';
import containerInjectI18n from '../plugins/component/react/containerInjectI18n'; import containerInjectI18n from '../plugins/component/react/containerInjectI18n';
@ -21,8 +22,14 @@ import icejs from '../plugins/project/framework/icejs';
import { prettier } from '../postprocessor'; import { prettier } from '../postprocessor';
export default function createIceJsProjectBuilder(): IProjectBuilder { export interface IceJsProjectBuilderOptions extends IProjectBuilderOptions {}
export default function createIceJsProjectBuilder(
options?: IceJsProjectBuilderOptions,
): IProjectBuilder {
return createProjectBuilder({ return createProjectBuilder({
inStrictMode: options?.inStrictMode,
extraContextData: { ...options },
template: icejs.template, template: icejs.template,
plugins: { plugins: {
components: [ components: [
@ -31,6 +38,7 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
fileType: 'jsx', fileType: 'jsx',
}), }),
containerClass(), containerClass(),
containerInjectContext(),
containerInjectUtils(), containerInjectUtils(),
containerInjectDataSourceEngine(), containerInjectDataSourceEngine(),
containerInjectI18n(), containerInjectI18n(),
@ -53,6 +61,7 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
fileType: 'jsx', fileType: 'jsx',
}), }),
containerClass(), containerClass(),
containerInjectContext(),
containerInjectUtils(), containerInjectUtils(),
containerInjectDataSourceEngine(), containerInjectDataSourceEngine(),
containerInjectI18n(), containerInjectI18n(),
@ -86,6 +95,7 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
export const plugins = { export const plugins = {
containerClass, containerClass,
containerInitState, containerInitState,
containerInjectContext,
containerInjectUtils, containerInjectUtils,
containerInjectI18n, containerInjectI18n,
containerInjectDataSourceEngine, containerInjectDataSourceEngine,

View File

@ -1,4 +1,4 @@
import { IProjectBuilder } from '../types'; import { IProjectBuilder, IProjectBuilderOptions } from '../types';
import { createProjectBuilder } from '../generator/ProjectBuilder'; import { createProjectBuilder } from '../generator/ProjectBuilder';
@ -22,8 +22,14 @@ import raxApp from '../plugins/project/framework/rax';
import { prettier } from '../postprocessor'; import { prettier } from '../postprocessor';
import { RaxFrameworkOptions } from '../plugins/project/framework/rax/types/RaxFrameworkOptions'; import { RaxFrameworkOptions } from '../plugins/project/framework/rax/types/RaxFrameworkOptions';
export default function createRaxProjectBuilder(options?: RaxFrameworkOptions): IProjectBuilder { export interface RaxProjectBuilderOptions extends IProjectBuilderOptions, RaxFrameworkOptions {}
export default function createRaxProjectBuilder(
options?: RaxProjectBuilderOptions,
): IProjectBuilder {
return createProjectBuilder({ return createProjectBuilder({
inStrictMode: options?.inStrictMode,
extraContextData: { ...options },
template: raxApp.template, template: raxApp.template,
plugins: { plugins: {
components: [ components: [

View File

@ -25,16 +25,8 @@ import i18n from './plugins/project/i18n';
import utils from './plugins/project/utils'; import utils from './plugins/project/utils';
import prettier from './postprocessor/prettier'; import prettier from './postprocessor/prettier';
// 引入常用工具 // 引入全局常用工具
import * as utilsCommon from './utils/common'; import * as globalUtils from './utils';
import * as utilsCompositeType from './utils/compositeType';
import * as utilsJsExpression from './utils/jsExpression';
import * as utilsJsSlot from './utils/jsSlot';
import * as utilsNodeToJSX from './utils/nodeToJSX';
import * as utilsResultHelper from './utils/resultHelper';
import * as utilsTemplateHelper from './utils/templateHelper';
import * as utilsValidate from './utils/validate';
import * as utilsSchema from './utils/schema';
import * as CONSTANTS from './const'; import * as CONSTANTS from './const';
@ -54,7 +46,6 @@ export default {
rax, rax,
}, },
publishers: { publishers: {
// TODO: 增加 web 端的 zip publisher
zip: createZipPublisher, zip: createZipPublisher,
}, },
plugins: { plugins: {
@ -85,17 +76,7 @@ export default {
postprocessor: { postprocessor: {
prettier, prettier,
}, },
utils: { utils: globalUtils,
common: utilsCommon,
compositeType: utilsCompositeType,
jsExpression: utilsJsExpression,
jsSlot: utilsJsSlot,
nodeToJSX: utilsNodeToJSX,
resultHelper: utilsResultHelper,
templateHelper: utilsTemplateHelper,
validate: utilsValidate,
schema: utilsSchema,
},
chunkNames: { chunkNames: {
COMMON_CHUNK_NAME, COMMON_CHUNK_NAME,
CLASS_DEFINE_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME,

View File

@ -59,8 +59,19 @@ export interface IBaseCodeStruct {
export interface ICodeStruct extends IBaseCodeStruct { export interface ICodeStruct extends IBaseCodeStruct {
ir: any; ir: any;
// FIXME: 这个方案不太好,想清楚场景,结构化表达,不要那么通用 contextData: IContextData;
contextData: Record<string, any>; }
/** 上下文数据,用来在插件之间共享一些数据 */
export interface IContextData extends IProjectBuilderOptions {
/** 是否使用了 Ref 的 API (this.$/this.$$) */
useRefApi?: boolean;
/**
*
*
*/
[key: string]: any;
} }
export type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise<ICodeStruct>; export type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise<ICodeStruct>;
@ -125,6 +136,33 @@ export interface IProjectPlugins {
[slotName: string]: BuilderComponentPlugin[]; [slotName: string]: BuilderComponentPlugin[];
} }
export interface IProjectBuilderOptions {
/** 是否处于严格模式(默认: 否) */
inStrictMode?: boolean;
/**
* JSExpression
* true
* : 如果容忍异常 try-catch
* catch CustomEvent
*/
tolerateEvalErrors?: boolean;
/**
*
* 默认:
*
* window.dispatchEvent(new CustomEvent('lowcode-eval-error', { error, expr }))
*
*
*
* :
* - error: 异常信息
* - expr: 求值的表达式
*/
evalErrorsHandler?: string;
}
export interface IProjectBuilder { export interface IProjectBuilder {
generateProject: (schema: ProjectSchema | string) => Promise<ResultDir>; generateProject: (schema: ProjectSchema | string) => Promise<ResultDir>;
} }
@ -179,6 +217,7 @@ export interface HandlerSet<T> {
export interface CompositeValueGeneratorOptions { export interface CompositeValueGeneratorOptions {
handlers?: HandlerSet<string>; handlers?: HandlerSet<string>;
nodeGenerator?: NodeGenerator<string>; nodeGenerator?: NodeGenerator<string>;
tolerateEvalErrors?: boolean;
} }
/** /**

View File

@ -15,7 +15,10 @@ export interface CodePiece {
type: PIECE_TYPE; type: PIECE_TYPE;
} }
export interface AttrData { attrName: string; attrValue: CompositeValue } export interface AttrData {
attrName: string;
attrValue: CompositeValue;
}
// 对 JSX 出码的理解,目前定制点包含 【包装】【标签名】【属性】 // 对 JSX 出码的理解,目前定制点包含 【包装】【标签名】【属性】
export type AttrPlugin = BaseGenerator<AttrData, CodePiece[], NodeGeneratorConfig>; export type AttrPlugin = BaseGenerator<AttrData, CodePiece[], NodeGeneratorConfig>;
export type NodePlugin = BaseGenerator<NodeSchema, CodePiece[], NodeGeneratorConfig>; export type NodePlugin = BaseGenerator<NodeSchema, CodePiece[], NodeGeneratorConfig>;
@ -26,4 +29,12 @@ export interface NodeGeneratorConfig {
attrPlugins?: AttrPlugin[]; attrPlugins?: AttrPlugin[];
nodePlugins?: NodePlugin[]; nodePlugins?: NodePlugin[];
self?: NodeGenerator<string>; self?: NodeGenerator<string>;
/**
* JSExpression
* true
* : 如果容忍异常 try-catch -- __$$eval / __$$evalArray
* catch CustomEvent
*/
tolerateEvalErrors?: boolean;
} }

View File

@ -0,0 +1 @@
declare module 'nanomatch';

View File

@ -57,7 +57,11 @@ function generateObject(
options: CompositeValueGeneratorOptions = {}, options: CompositeValueGeneratorOptions = {},
): string { ): string {
if (value.type === 'i18n') { if (value.type === 'i18n') {
return `this._i18nText(${JSON.stringify(value)})`; // params 可能会绑定变量,这里需要处理下
if (value.params && typeof value.params === 'object') {
return `this._i18nText(${generateUnknownType(_.omit(value, 'type'), scope, options)})`;
}
return `this._i18nText(${JSON.stringify(_.omit(value, 'type'))})`; // TODO: 优化:这里可以考虑提取成个常量...
} }
const body = Object.keys(value) const body = Object.keys(value)

View File

@ -0,0 +1,28 @@
// 本文件是要导出到外面的,注意只导出比较稳定的东西
import * as common from './common';
import * as compositeType from './compositeType';
import * as jsExpression from './jsExpression';
import * as jsSlot from './jsSlot';
import * as nodeToJSX from './nodeToJSX';
import * as resultHelper from './resultHelper';
import * as templateHelper from './templateHelper';
import * as validate from './validate';
import * as schema from './schema';
import * as version from './version';
import * as scope from './Scope';
import * as expressionParser from './expressionParser';
export {
common,
compositeType,
jsExpression,
jsSlot,
nodeToJSX,
resultHelper,
templateHelper,
validate,
schema,
version,
scope,
expressionParser,
};

View File

@ -79,10 +79,11 @@ export function isJsCode(value: unknown): boolean {
export function generateExpression(value: any, scope: IScope): string { export function generateExpression(value: any, scope: IScope): string {
if (isJSExpression(value)) { if (isJSExpression(value)) {
const exprVal = (value as JSExpression).value; const exprVal = (value as JSExpression).value.trim();
if (!exprVal) { if (!exprVal) {
return 'null'; return 'null';
} }
const afterProcessWithLocals = transformExpressionLocalRef(exprVal, scope); const afterProcessWithLocals = transformExpressionLocalRef(exprVal, scope);
return afterProcessWithLocals; return afterProcessWithLocals;
} }

View File

@ -1,4 +1,5 @@
import _ from 'lodash'; import _ from 'lodash';
import { pipe } from 'fp-ts/function';
import { NodeSchema, isNodeSchema, NodeDataType, CompositeValue } from '@alilc/lowcode-types'; import { NodeSchema, isNodeSchema, NodeDataType, CompositeValue } from '@alilc/lowcode-types';
import { import {
@ -17,6 +18,7 @@ import { getStaticExprValue } from './common';
import { executeFunctionStack } from './aopHelper'; import { executeFunctionStack } from './aopHelper';
import { encodeJsxStringNode } from './encodeJsxAttrString'; import { encodeJsxStringNode } from './encodeJsxAttrString';
import { unwrapJsExprQuoteInJsx } from './jsxHelpers'; import { unwrapJsExprQuoteInJsx } from './jsxHelpers';
import { transformThis2Context } from '../core/jsx/handlers/transformThis2Context';
function mergeNodeGeneratorConfig( function mergeNodeGeneratorConfig(
cfg1: NodeGeneratorConfig, cfg1: NodeGeneratorConfig,
@ -255,6 +257,8 @@ export function generateReactLoopCtrl(
next?: NodePlugin, next?: NodePlugin,
): CodePiece[] { ): CodePiece[] {
if (nodeItem.loop) { if (nodeItem.loop) {
const tolerateEvalErrors = config?.tolerateEvalErrors ?? true;
const loopItemName = nodeItem.loopArgs?.[0] || 'item'; const loopItemName = nodeItem.loopArgs?.[0] || 'item';
const loopIndexName = nodeItem.loopArgs?.[1] || 'index'; const loopIndexName = nodeItem.loopArgs?.[1] || 'index';
@ -262,9 +266,20 @@ export function generateReactLoopCtrl(
const subScope = scope.createSubScope([loopItemName, loopIndexName]); const subScope = scope.createSubScope([loopItemName, loopIndexName]);
const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : []; const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : [];
const loopDataExpr = generateCompositeType(nodeItem.loop, scope, { // 生成循环变量表达式
handlers: config?.handlers, const loopDataExpr = pipe(
}); nodeItem.loop,
// 将 JSExpression 转换为 JS 表达式代码:
(expr) =>
generateCompositeType(expr, scope, {
handlers: config?.handlers,
tolerateEvalErrors: false, // 这个内部不需要包 try catch, 下面会统一加的
}),
// 将 this.xxx 转换为 __$$context.xxx:
(expr) => transformThis2Context(expr, scope, { ignoreRootScope: true }),
// 如果要容忍错误,则包一层 try catch (基于助手函数 __$$evalArray)
(expr) => (tolerateEvalErrors ? `__$$evalArray(() => (${expr}))` : expr),
);
pieces.unshift({ pieces.unshift({
value: `(${loopDataExpr}).map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`, value: `(${loopDataExpr}).map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`,

View File

@ -1,4 +1,5 @@
import { ResultFile, ResultDir } from '@alilc/lowcode-types'; import { ResultFile, ResultDir } from '@alilc/lowcode-types';
import nm from 'nanomatch';
import { CodeGeneratorError } from '../types/error'; import { CodeGeneratorError } from '../types/error';
import { FlattenFile } from '../types/file'; import { FlattenFile } from '../types/file';
@ -47,12 +48,204 @@ export function flattenResult(dir: ResultDir, cwd = ''): FlattenFile[] {
return [ return [
...dir.files.map( ...dir.files.map(
(file): FlattenFile => ({ (file): FlattenFile => ({
pathName: `${cwd ? `${cwd}/` : ''}${file.name}${file.ext ? `.${file.ext}` : ''}`, pathName: joinPath(cwd, `${file.name}${file.ext ? `.${file.ext}` : ''}`),
content: file.content, content: file.content,
}), }),
), ),
].concat( ].concat(...dir.dirs.map((subDir) => flattenResult(subDir, joinPath(cwd, subDir.name))));
...dir.dirs.map((subDir) => }
flattenResult(subDir, [cwd, subDir.name].filter((x) => x !== '' && x !== '.').join('/'))),
); export type GlobOptions = {
/** 是否查找 ".xxx" 文件, 默认: 否 */
dot?: boolean;
};
/**
*
* @param result
* @param fileGlobExpr
* @param resultDirPath '.'
* @returns null
*/
export function findFile(
result: ResultDir,
fileGlobExpr: string,
options: GlobOptions = {},
resultDirPath = getResultNameOrDefault(result, ''),
): ResultFile | null {
const maxDepth = !/\/|\*\*/.test(fileGlobExpr) ? 1 : undefined; // 如果 glob 表达式里面压根不会匹配子目录,则深度限制为 1
const files = scanFiles(result, resultDirPath, maxDepth);
for (let [filePath, file] of files) {
if (nm.isMatch(filePath, fileGlobExpr, options)) {
return file;
}
}
return null;
}
/**
* 使 glob
* @param result
* @param fileGlobExpr
* @param resultDirPath '.'
* @returns [ [, ], ... ]
*/
export function* globFiles(
result: ResultDir,
fileGlobExpr: string,
options: GlobOptions = {},
resultDirPath = getResultNameOrDefault(result, ''),
): IterableIterator<[string, ResultFile]> {
const files = scanFiles(result, resultDirPath);
for (let [filePath, file] of files) {
if (nm.isMatch(filePath, fileGlobExpr, options)) {
yield [filePath, file];
}
}
}
/**
*
*/
export function* scanFiles(
result: ResultDir,
resultDirPath = getResultNameOrDefault(result, ''),
maxDepth = 10000,
): IterableIterator<[string, ResultFile]> {
for (let file of result.files) {
const fileName = getFileNameWithExt(file);
yield [joinPath(resultDirPath, fileName), file];
}
for (let subDir of result.dirs) {
yield* scanFiles(subDir, joinPath(resultDirPath, subDir.name), maxDepth - 1);
}
}
export function getFileNameWithExt(file: ResultFile) {
return `${file.name}${file.ext ? `.${file.ext}` : ''}`;
}
function getResultNameOrDefault(result: ResultDir, defaultDir = '/') {
return result.name && result.name !== '.' ? result.name : defaultDir;
}
function joinPath(...pathParts: string[]): string {
return pathParts
.filter((x) => x !== '' && x !== '.')
.join('/')
.replace(/\\+/g, '/')
.replace(/\/+/g, '/');
}
export function* scanDirs(
result: ResultDir,
resultDirPath = getResultNameOrDefault(result, ''),
maxDepth = 10000,
): IterableIterator<[string, ResultDir]> {
yield [resultDirPath, result];
for (let subDir of result.dirs) {
yield* scanDirs(subDir, joinPath(resultDirPath, subDir.name), maxDepth - 1);
}
}
export function* globDirs(
result: ResultDir,
dirGlobExpr: string,
options: GlobOptions = {},
resultDirPath = getResultNameOrDefault(result, ''),
): IterableIterator<[string, ResultDir]> {
const dirs = scanDirs(result, resultDirPath);
for (let [dirPath, dir] of dirs) {
if (nm.isMatch(dirPath, dirGlobExpr, options)) {
yield [dirPath, dir];
}
}
}
export function findDir(
result: ResultDir,
dirGlobExpr: string,
options: GlobOptions = {},
resultDirPath = getResultNameOrDefault(result, ''),
): ResultDir | null {
const dirs = scanDirs(result, resultDirPath);
for (let [dirPath, dir] of dirs) {
if (nm.isMatch(dirPath, dirGlobExpr, options)) {
return dir;
}
}
return null;
}
/**
*
* @param result
* @param filePathGlobExpr glob
* @param globOptions glob
* @returns
*/
export function removeFilesFromResult(
result: ResultDir,
filePathGlobExpr: string,
globOptions: GlobOptions = {},
): number {
let removedCount = 0;
const [dirPath, fileName] = splitPath(filePathGlobExpr);
const dirs = dirPath ? globDirs(result, dirPath) : [['', result] as const];
for (let [, dir] of dirs) {
const files = globFiles(dir, fileName, globOptions, '.');
for (let [, file] of files) {
dir.files.splice(dir.files.indexOf(file), 1);
removedCount += 1;
}
}
return removedCount;
}
/**
*
* @param result
* @param dirPathGlobExpr glob
* @param globOptions glob
* @returns
*/
export function removeDirsFromResult(
result: ResultDir,
dirPathGlobExpr: string,
globOptions: GlobOptions = {},
): number {
let removedCount = 0;
const [dirPath, fileName] = splitPath(dirPathGlobExpr);
const dirs = dirPath ? globDirs(result, dirPath) : [['', result] as const];
for (let [, dir] of dirs) {
const foundDirs = globDirs(dir, fileName, globOptions, '.');
for (let [, foundDir] of foundDirs) {
dir.dirs.splice(dir.dirs.indexOf(foundDir), 1);
removedCount += 1;
}
}
return removedCount;
}
/**
*
* @param filePath
* @returns [fileDirPath, fileName]
*/
function splitPath(filePath: string) {
const parts = filePath.split('/');
const fileName = parts.pop() || '';
return [joinPath(...parts), fileName];
} }

View File

@ -1,8 +1,6 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = {}; const i18nConfig = {};
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -10,22 +8,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -33,6 +33,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -63,11 +65,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -132,13 +129,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,8 +1,6 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = {}; const i18nConfig = {};
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -10,22 +8,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -68,6 +68,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -166,11 +168,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -339,13 +336,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,8 +1,6 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = {}; const i18nConfig = {};
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -10,22 +8,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -37,6 +37,8 @@ class Detail$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -72,11 +74,6 @@ class Detail$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -141,13 +138,7 @@ export default Detail$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -37,6 +37,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -72,11 +74,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -141,13 +138,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -37,6 +37,8 @@ class List$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -75,11 +77,6 @@ class List$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -144,13 +141,7 @@ export default List$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,8 +1,6 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = {}; const i18nConfig = {};
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -10,22 +8,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -35,6 +35,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -67,11 +69,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -136,13 +133,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = { const i18nConfig = {
'zh-CN': { 'zh-CN': {
'hello-world': '你好,世界!', 'hello-world': '你好,世界!',
@ -9,7 +7,7 @@ const i18nConfig = {
}, },
}; };
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -17,22 +15,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -33,6 +33,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -69,11 +71,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -138,13 +135,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = { const i18nConfig = {
'zh-CN': { 'zh-CN': {
'hello-world': '你好,世界!', 'hello-world': '你好,世界!',
@ -9,7 +7,7 @@ const i18nConfig = {
}, },
}; };
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -17,22 +15,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -35,6 +35,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -75,11 +77,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -144,13 +141,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = { const i18nConfig = {
'zh-CN': { 'zh-CN': {
'hello-world': '你好,世界!', 'hello-world': '你好,世界!',
@ -9,7 +7,7 @@ const i18nConfig = {
}, },
}; };
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -17,22 +15,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -33,6 +33,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -69,11 +71,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -138,13 +135,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = { const i18nConfig = {
'zh-CN': { 'zh-CN': {
'hello-world': '你好,世界!', 'hello-world': '你好,世界!',
@ -9,7 +7,7 @@ const i18nConfig = {
}, },
}; };
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -17,22 +15,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -35,6 +35,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -75,11 +77,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -144,13 +141,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = { const i18nConfig = {
'zh-CN': { 'zh-CN': {
'hello-world': '你好,世界!', 'hello-world': '你好,世界!',
@ -9,7 +7,7 @@ const i18nConfig = {
}, },
}; };
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -17,22 +15,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -35,6 +35,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -78,11 +80,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -147,13 +144,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = { const i18nConfig = {
'zh-CN': { 'zh-CN': {
'hello-world': '你好,世界!', 'hello-world': '你好,世界!',
@ -9,7 +7,7 @@ const i18nConfig = {
}, },
}; };
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -17,22 +15,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -35,6 +35,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -80,11 +82,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -149,13 +146,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,8 +1,6 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = {}; const i18nConfig = {};
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -10,22 +8,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -40,6 +40,8 @@ class Aaaa$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -70,11 +72,6 @@ class Aaaa$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -161,13 +158,7 @@ export default Aaaa$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = { const i18nConfig = {
'zh-CN': { 'zh-CN': {
'hello-world': '你好,世界!', 'hello-world': '你好,世界!',
@ -9,7 +7,7 @@ const i18nConfig = {
}, },
}; };
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -17,22 +15,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -33,6 +33,8 @@ class Home$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -70,11 +72,6 @@ class Home$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -152,13 +149,7 @@ export default Home$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,8 +1,6 @@
import IntlMessageFormat from 'intl-messageformat';
const i18nConfig = {}; const i18nConfig = {};
let locale = 'en-US'; let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';
const getLocale = () => locale; const getLocale = () => locale;
@ -10,22 +8,61 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
const msg = (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || defaultMessage; (Array.isArray(variables) && variables.length === 0) ||
(typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;
if (msg == null) { if (msg == null) {
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || 'zh_CN'] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -36,6 +36,8 @@ class Example$$Page extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
__$$i18n._inject2(this);
} /* end of constructor */ } /* end of constructor */
componentDidMount() { componentDidMount() {
@ -72,11 +74,6 @@ class Example$$Page extends Component {
); );
} /* end of render */ } /* end of render */
_i18nText(t) {
const locale = this._context.getLocale();
return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US;
}
_createContext() { _createContext() {
const self = this; const self = this;
const context = { const context = {
@ -163,13 +160,7 @@ export default Example$$Page;
function __$$eval(expr) { function __$$eval(expr) {
try { try {
return expr(); return expr();
} catch (err) { } catch (error) {}
try {
if (window.handleEvalError) {
window.handleEvalError('Failed to evaluate: ', expr, err);
}
} catch (e) {}
}
} }
function __$$evalArray(expr) { function __$$evalArray(expr) {

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { Form, Input, NumberPicker, Select, Button } from "@alifd/next"; import { Form, Input, NumberPicker, Select, Button } from "@alifd/next";
@ -10,11 +12,13 @@ import { create as __$$createDataSourceEngine } from "@alilc/lowcode-datasource-
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
_dataSourceConfig = this._defineDataSourceConfig(); _dataSourceConfig = this._defineDataSourceConfig();
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
runtimeConfig: true, runtimeConfig: true,
@ -39,6 +43,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { text: "outter" }; this.state = { text: "outter" };
} }
@ -113,10 +119,6 @@ class Test$$Page extends React.Component {
}; };
} }
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidMount() { componentDidMount() {
this._dataSourceEngine.reloadDataSource(); this._dataSourceEngine.reloadDataSource();
@ -124,12 +126,12 @@ class Test$$Page extends React.Component {
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div ref={this._refsManager.linkRef("outterView")} autoLoading={true}> <div ref={this._refsManager.linkRef("outterView")} autoLoading={true}>
<Form <Form
labelCol={this.state.colNum} labelCol={__$$eval(() => this.state.colNum)}
style={{}} style={{}}
ref={this._refsManager.linkRef("testForm")} ref={this._refsManager.linkRef("testForm")}
> >
@ -150,11 +152,11 @@ class Test$$Page extends React.Component {
</Form.Item> </Form.Item>
<div style={{ textAlign: "center" }}> <div style={{ textAlign: "center" }}>
<Button.Group> <Button.Group>
{["a", "b", "c"].map((item, index) => {__$$evalArray(() => ["a", "b", "c"]).map((item, index) =>
((__$$context) => ((__$$context) =>
!!(index >= 1) && ( !!__$$eval(() => index >= 1) && (
<Button type="primary" style={{ margin: "0 5px 0 5px" }}> <Button type="primary" style={{ margin: "0 5px 0 5px" }}>
{item} {__$$eval(() => item)}
</Button> </Button>
))(__$$createChildContext(__$$context, { item, index })) ))(__$$createChildContext(__$$context, { item, index }))
)} )}
@ -168,6 +170,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { Page } from "@alilc/b6-page"; import { Page } from "@alilc/b6-page";
@ -10,11 +12,13 @@ import { create as __$$createDataSourceEngine } from "@alilc/lowcode-datasource-
import utils from "../../utils"; import utils from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
class Aaaa$$Page extends React.Component { class Aaaa$$Page extends React.Component {
_context = this;
_dataSourceConfig = this._defineDataSourceConfig(); _dataSourceConfig = this._defineDataSourceConfig();
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
runtimeConfig: true, runtimeConfig: true,
@ -36,9 +40,15 @@ class Aaaa$$Page extends React.Component {
this.utils = utils; this.utils = utils;
__$$i18n._inject2(this);
this.state = {}; this.state = {};
} }
$ = () => null;
$$ = () => [];
_defineDataSourceConfig() { _defineDataSourceConfig() {
const _this = this; const _this = this;
return { return {
@ -60,17 +70,13 @@ class Aaaa$$Page extends React.Component {
}; };
} }
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidMount() { componentDidMount() {
this._dataSourceEngine.reloadDataSource(); this._dataSourceEngine.reloadDataSource();
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div title="" backgroundColor="#fff" textColor="#333" style={{}}> <div title="" backgroundColor="#fff" textColor="#333" style={{}}>
<Text <Text
@ -85,6 +91,17 @@ class Aaaa$$Page extends React.Component {
export default Aaaa$$Page; export default Aaaa$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = { const i18nConfig = {
"zh-CN": { "zh-CN": {
"i18n-jwg27yo4": "你好", "i18n-jwg27yo4": "你好",
@ -11,7 +9,10 @@ const i18nConfig = {
}, },
}; };
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -19,24 +20,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,14 +1,18 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { Form, Input, NumberPicker, Select, Button } from "@alifd/next"; import { Form, Input, NumberPicker, Select, Button } from "@alifd/next";
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
constructor(props, context) { constructor(props, context) {
super(props); super(props);
@ -16,6 +20,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { text: "outter" }; this.state = { text: "outter" };
} }
@ -27,26 +33,22 @@ class Test$$Page extends React.Component {
return this._refsManager.getAll(refName); return this._refsManager.getAll(refName);
}; };
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidMount() { componentDidMount() {
console.log("componentDidMount"); console.log("componentDidMount");
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div ref={this._refsManager.linkRef("outterView")} autoLoading={true}> <div ref={this._refsManager.linkRef("outterView")} autoLoading={true}>
<Form <Form
labelCol={this.state.colNum} labelCol={__$$eval(() => this.state.colNum)}
style={{}} style={{}}
ref={this._refsManager.linkRef("testForm")} ref={this._refsManager.linkRef("testForm")}
> >
<Form.Item <Form.Item
label={this.i18n("i18n-jwg27yo4")} label={__$$eval(() => this.i18n("i18n-jwg27yo4"))}
name="name" name="name"
initValue="李雷" initValue="李雷"
> >
@ -90,6 +92,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,5 +1,3 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = { const i18nConfig = {
"zh-CN": { "zh-CN": {
"i18n-jwg27yo4": "你好", "i18n-jwg27yo4": "你好",
@ -11,7 +9,10 @@ const i18nConfig = {
}, },
}; };
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -19,24 +20,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import Super, { import Super, {
@ -13,7 +15,7 @@ import SuperOther from "@alifd/next";
import utils from "../../utils"; import utils from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
@ -24,26 +26,30 @@ const SelectOption = Select.Option;
const SearchTable = SearchTableExport.default; const SearchTable = SearchTableExport.default;
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
constructor(props, context) { constructor(props, context) {
super(props); super(props);
this.utils = utils; this.utils = utils;
__$$i18n._inject2(this);
this.state = {}; this.state = {};
} }
i18n = (i18nKey) => { $ = () => null;
return _$$i18n(i18nKey);
}; $$ = () => [];
componentDidMount() {} componentDidMount() {}
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div> <div>
<Super title={this.state.title} /> <Super title={__$$eval(() => this.state.title)} />
<SuperSub /> <SuperSub />
<SuperOther /> <SuperOther />
<Button /> <Button />
@ -60,6 +66,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { import {
@ -15,7 +17,7 @@ import { create as __$$createDataSourceEngine } from "@alilc/lowcode-datasource-
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
@ -24,6 +26,8 @@ const NextBlockCell = NextBlock.Cell;
const AliSearchTable = AliSearchTableExport.default; const AliSearchTable = AliSearchTableExport.default;
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
_dataSourceConfig = this._defineDataSourceConfig(); _dataSourceConfig = this._defineDataSourceConfig();
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
runtimeConfig: true, runtimeConfig: true,
@ -45,6 +49,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { text: "outter", isShowDialog: false }; this.state = { text: "outter", isShowDialog: false };
} }
@ -81,10 +87,6 @@ class Test$$Page extends React.Component {
}; };
} }
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentWillUnmount() { componentWillUnmount() {
console.log("will umount"); console.log("will umount");
} }
@ -133,8 +135,8 @@ class Test$$Page extends React.Component {
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div <div
ref={this._refsManager.linkRef("outterView")} ref={this._refsManager.linkRef("outterView")}
@ -188,7 +190,7 @@ class Test$$Page extends React.Component {
flex={true} flex={true}
> >
<AliSearchTable <AliSearchTable
dataSource={this.state.users.data} dataSource={__$$eval(() => this.state.users.data)}
rowKey="workid" rowKey="workid"
columns={[ columns={[
{ title: "花名", dataIndex: "cname" }, { title: "花名", dataIndex: "cname" },
@ -263,6 +265,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { import {
@ -22,7 +24,7 @@ import { AliAutoSearchTable } from "@alife/mc-assets-1935/build/lowcode/index.js
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
@ -31,6 +33,8 @@ const NextBlockCell = NextBlock.Cell;
const AliAutoSearchTableDefault = AliAutoSearchTable.default; const AliAutoSearchTableDefault = AliAutoSearchTable.default;
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
constructor(props, context) { constructor(props, context) {
super(props); super(props);
@ -38,6 +42,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { this.state = {
name: "nongzhou", name: "nongzhou",
gateways: [], gateways: [],
@ -55,10 +61,6 @@ class Test$$Page extends React.Component {
return this._refsManager.getAll(refName); return this._refsManager.getAll(refName);
}; };
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentWillUnmount() { componentWillUnmount() {
/* ... */ /* ... */
} }
@ -90,8 +92,8 @@ class Test$$Page extends React.Component {
componentDidMount() {} componentDidMount() {}
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div <div
ref={this._refsManager.linkRef("outterView")} ref={this._refsManager.linkRef("outterView")}
@ -150,7 +152,7 @@ class Test$$Page extends React.Component {
width: "400px", width: "400px",
display: "inline-block", display: "inline-block",
}} }}
options={this.state.gateways} options={__$$eval(() => this.state.gateways)}
mode="single" mode="single"
defaultValue={["auto-edd-uniproxy"]} defaultValue={["auto-edd-uniproxy"]}
labelInValue={true} labelInValue={true}
@ -218,7 +220,7 @@ class Test$$Page extends React.Component {
</Button> </Button>
<Modal <Modal
title="创建发布单" title="创建发布单"
visible={this.state.modalVisible} visible={__$$eval(() => this.state.modalVisible)}
footer="" footer=""
__events={{ __events={{
eventDataList: [ eventDataList: [
@ -315,7 +317,7 @@ class Test$$Page extends React.Component {
</Modal> </Modal>
<AliAutoSearchTableDefault <AliAutoSearchTableDefault
rowKey="key" rowKey="key"
dataSource={this.state.records} dataSource={__$$eval(() => this.state.records)}
columns={[ columns={[
{ {
title: "发布名称", title: "发布名称",
@ -340,7 +342,7 @@ class Test$$Page extends React.Component {
}, },
{ title: "发布时间", dataIndex: "publish_id" }, { title: "发布时间", dataIndex: "publish_id" },
]} ]}
actions={this.actions || []} actions={__$$eval(() => this.actions || [])}
getActions={function () { getActions={function () {
return this.getActions.apply( return this.getActions.apply(
this, this,
@ -360,6 +362,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { Form, Input, NumberPicker, Select, Button } from "@alifd/next"; import { Form, Input, NumberPicker, Select, Button } from "@alifd/next";
@ -10,11 +12,13 @@ import { create as __$$createDataSourceEngine } from "@alilc/lowcode-datasource-
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
_dataSourceConfig = this._defineDataSourceConfig(); _dataSourceConfig = this._defineDataSourceConfig();
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
runtimeConfig: true, runtimeConfig: true,
@ -39,6 +43,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { text: "outter" }; this.state = { text: "outter" };
} }
@ -113,10 +119,6 @@ class Test$$Page extends React.Component {
}; };
} }
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidMount() { componentDidMount() {
this._dataSourceEngine.reloadDataSource(); this._dataSourceEngine.reloadDataSource();
@ -124,12 +126,12 @@ class Test$$Page extends React.Component {
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div ref={this._refsManager.linkRef("outterView")} autoLoading={true}> <div ref={this._refsManager.linkRef("outterView")} autoLoading={true}>
<Form <Form
labelCol={this.state.colNum} labelCol={__$$eval(() => this.state.colNum)}
style={{}} style={{}}
ref={this._refsManager.linkRef("testForm")} ref={this._refsManager.linkRef("testForm")}
> >
@ -150,11 +152,11 @@ class Test$$Page extends React.Component {
</Form.Item> </Form.Item>
<div style={{ textAlign: "center" }}> <div style={{ textAlign: "center" }}>
<Button.Group> <Button.Group>
{["a", "b", "c"].map((item, index) => {__$$evalArray(() => ["a", "b", "c"]).map((item, index) =>
((__$$context) => ((__$$context) =>
!!false && ( !!false && (
<Button type="primary" style={{ margin: "0 5px 0 5px" }}> <Button type="primary" style={{ margin: "0 5px 0 5px" }}>
{item} {__$$eval(() => item)}
</Button> </Button>
))(__$$createChildContext(__$$context, { item, index })) ))(__$$createChildContext(__$$context, { item, index }))
)} )}
@ -168,6 +170,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { import {
@ -21,13 +23,15 @@ import {
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
const NextBlockCell = NextBlock.Cell; const NextBlockCell = NextBlock.Cell;
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
constructor(props, context) { constructor(props, context) {
super(props); super(props);
@ -35,6 +39,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { this.state = {
books: [], books: [],
currentStep: 0, currentStep: 0,
@ -97,10 +103,6 @@ class Test$$Page extends React.Component {
return this._refsManager.getAll(refName); return this._refsManager.getAll(refName);
}; };
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidUpdate(prevProps, prevState, snapshot) {} componentDidUpdate(prevProps, prevState, snapshot) {}
componentWillUnmount() {} componentWillUnmount() {}
@ -189,8 +191,8 @@ class Test$$Page extends React.Component {
componentDidMount() {} componentDidMount() {}
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div <div
ref={this._refsManager.linkRef("outterView")} ref={this._refsManager.linkRef("outterView")}
@ -198,7 +200,7 @@ class Test$$Page extends React.Component {
> >
<Modal <Modal
title="是否修改" title="是否修改"
visible={this.state.isModifyDialogVisible} visible={__$$eval(() => this.state.isModifyDialogVisible)}
okText="确认" okText="确认"
okType="" okType=""
forceRender={false} forceRender={false}
@ -291,13 +293,13 @@ class Test$$Page extends React.Component {
flex={true} flex={true}
style={{ marginBottom: "24px" }} style={{ marginBottom: "24px" }}
> >
<Steps current={this.state.currentStep}> <Steps current={__$$eval(() => this.state.currentStep)}>
<Steps.Step title="版本申请" description="" /> <Steps.Step title="版本申请" description="" />
<Steps.Step title="机器配置" subTitle="" description="" /> <Steps.Step title="机器配置" subTitle="" description="" />
<Steps.Step title="项目审批" description="" /> <Steps.Step title="项目审批" description="" />
</Steps> </Steps>
</NextP> </NextP>
{!!(this.state.currentStep === 0) && ( {!!__$$eval(() => this.state.currentStep === 0) && (
<NextP <NextP
wrap={false} wrap={false}
type="body2" type="body2"
@ -345,7 +347,9 @@ class Test$$Page extends React.Component {
{ name: "onValuesChange", disabled: true }, { name: "onValuesChange", disabled: true },
], ],
}} }}
initialValues={this.state.customerProjectInfo} initialValues={__$$eval(
() => this.state.customerProjectInfo
)}
onValuesChange={function () { onValuesChange={function () {
this.onValuesChange.apply( this.onValuesChange.apply(
this, this,
@ -389,10 +393,11 @@ class Test$$Page extends React.Component {
{ label: "UI定制", value: "4", disabled: false }, { label: "UI定制", value: "4", disabled: false },
]} ]}
style={{ width: "600px" }} style={{ width: "600px" }}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -407,11 +412,12 @@ class Test$$Page extends React.Component {
> >
<Select <Select
style={{ width: "600px" }} style={{ width: "600px" }}
options={this.state.versionLinesArray} options={__$$eval(() => this.state.versionLinesArray)}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
placeholder="请选择版本线" placeholder="请选择版本线"
/> />
</Form.Item> </Form.Item>
@ -440,10 +446,11 @@ class Test$$Page extends React.Component {
<Input <Input
placeholder="公司简称-产品名称-版本类型" placeholder="公司简称-产品名称-版本类型"
style={{ width: "600px" }} style={{ width: "600px" }}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -460,10 +467,11 @@ class Test$$Page extends React.Component {
> >
<DatePicker <DatePicker
style={{ width: "600px" }} style={{ width: "600px" }}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -482,10 +490,11 @@ class Test$$Page extends React.Component {
value={3} value={3}
style={{ width: "600px" }} style={{ width: "600px" }}
placeholder="单位(台)使用该版本的机器数量+预计出货量,请如实填写" placeholder="单位(台)使用该版本的机器数量+预计出货量,请如实填写"
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
min={0} min={0}
size="middle" size="middle"
/> />
@ -541,7 +550,7 @@ class Test$$Page extends React.Component {
</Form> </Form>
</NextP> </NextP>
)} )}
{!!(this.state.currentStep === 1) && ( {!!__$$eval(() => this.state.currentStep === 1) && (
<NextP <NextP
wrap={false} wrap={false}
type="body2" type="body2"
@ -590,7 +599,9 @@ class Test$$Page extends React.Component {
{ name: "onValuesChange", disabled: true }, { name: "onValuesChange", disabled: true },
], ],
}} }}
initialValues={this.state.customerProjectInfo} initialValues={__$$eval(
() => this.state.customerProjectInfo
)}
onValuesChange={function () { onValuesChange={function () {
this.onValuesChange.apply( this.onValuesChange.apply(
this, this,
@ -612,11 +623,12 @@ class Test$$Page extends React.Component {
> >
<Select <Select
style={{ width: "600px" }} style={{ width: "600px" }}
options={this.state.projectModalsArray} options={__$$eval(() => this.state.projectModalsArray)}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
placeholder="请选择设备类型" placeholder="请选择设备类型"
/> />
</Form.Item> </Form.Item>
@ -636,10 +648,11 @@ class Test$$Page extends React.Component {
value={3} value={3}
style={{ width: "600px" }} style={{ width: "600px" }}
placeholder="例如1280" placeholder="例如1280"
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
min={0} min={0}
/> />
</Form.Item> </Form.Item>
@ -659,10 +672,11 @@ class Test$$Page extends React.Component {
value={3} value={3}
style={{ width: "600px" }} style={{ width: "600px" }}
placeholder="例如720" placeholder="例如720"
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
min={0} min={0}
/> />
</Form.Item> </Form.Item>
@ -682,10 +696,11 @@ class Test$$Page extends React.Component {
value={3} value={3}
style={{ width: "600px" }} style={{ width: "600px" }}
placeholder="请输入尺寸" placeholder="请输入尺寸"
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
min={0} min={0}
/> />
</Form.Item> </Form.Item>
@ -701,10 +716,11 @@ class Test$$Page extends React.Component {
value={3} value={3}
style={{ width: "600px" }} style={{ width: "600px" }}
placeholder="UI定制项目必填" placeholder="UI定制项目必填"
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
min={0} min={0}
/> />
</Form.Item> </Form.Item>
@ -725,10 +741,11 @@ class Test$$Page extends React.Component {
<Input <Input
placeholder="请输入芯片名称" placeholder="请输入芯片名称"
style={{ width: "600px" }} style={{ width: "600px" }}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -747,10 +764,11 @@ class Test$$Page extends React.Component {
value={3} value={3}
style={{ width: "600px" }} style={{ width: "600px" }}
placeholder="请输入芯片核数" placeholder="请输入芯片核数"
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
defaultValue="" defaultValue=""
min={0} min={0}
/> />
@ -765,11 +783,12 @@ class Test$$Page extends React.Component {
> >
<Select <Select
style={{ width: "600px" }} style={{ width: "600px" }}
options={this.state.instructionsArray} options={__$$eval(() => this.state.instructionsArray)}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -786,11 +805,12 @@ class Test$$Page extends React.Component {
> >
<Select <Select
style={{ width: "600px" }} style={{ width: "600px" }}
options={this.state.osVersionsArray} options={__$$eval(() => this.state.osVersionsArray)}
disabled={ disabled={__$$eval(
this.state.customerProjectInfo.id > 0 && () =>
!this.state.isModifyStatus this.state.customerProjectInfo.id > 0 &&
} !this.state.isModifyStatus
)}
placeholder="请选择系统版本" placeholder="请选择系统版本"
/> />
</Form.Item> </Form.Item>
@ -827,11 +847,12 @@ class Test$$Page extends React.Component {
type="primary" type="primary"
htmlType="submit" htmlType="submit"
style={{ float: "right", marginLeft: "20px" }} style={{ float: "right", marginLeft: "20px" }}
loading={ loading={__$$eval(
this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT () =>
} this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT
)}
> >
{this.state.secondCommitText} {__$$eval(() => this.state.secondCommitText)}
</Button> </Button>
<Button <Button
type="primary" type="primary"
@ -860,7 +881,7 @@ class Test$$Page extends React.Component {
</Form> </Form>
</NextP> </NextP>
)} )}
{!!(this.state.currentStep === 2) && ( {!!__$$eval(() => this.state.currentStep === 2) && (
<NextP <NextP
wrap={false} wrap={false}
type="body2" type="body2"
@ -923,7 +944,7 @@ class Test$$Page extends React.Component {
style={{ width: "200px" }} style={{ width: "200px" }}
/> />
<Steps.Step <Steps.Step
title={this.state.thirdAuditText} title={__$$eval(() => this.state.thirdAuditText)}
subTitle="" subTitle=""
description="" description=""
style={{ width: "200px" }} style={{ width: "200px" }}
@ -980,9 +1001,11 @@ class Test$$Page extends React.Component {
); );
}.bind(this)} }.bind(this)}
> >
{this.state.thirdButtonText} {__$$eval(() => this.state.thirdButtonText)}
</Button> </Button>
{!!(this.state.customerProjectInfo.status > 2) && ( {!!__$$eval(
() => this.state.customerProjectInfo.status > 2
) && (
<Button <Button
type="primary" type="primary"
htmlType="submit" htmlType="submit"
@ -1021,6 +1044,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { Page, Table } from "@alilc/lowcode-components"; import { Page, Table } from "@alilc/lowcode-components";
@ -8,11 +10,13 @@ import { create as __$$createDataSourceEngine } from "@alilc/lowcode-datasource-
import utils from "../../utils"; import utils from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
class Example$$Page extends React.Component { class Example$$Page extends React.Component {
_context = this;
_dataSourceConfig = this._defineDataSourceConfig(); _dataSourceConfig = this._defineDataSourceConfig();
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
runtimeConfig: true, runtimeConfig: true,
@ -32,9 +36,15 @@ class Example$$Page extends React.Component {
this.utils = utils; this.utils = utils;
__$$i18n._inject2(this);
this.state = {}; this.state = {};
} }
$ = () => null;
$$ = () => [];
_defineDataSourceConfig() { _defineDataSourceConfig() {
const _this = this; const _this = this;
return { return {
@ -56,21 +66,17 @@ class Example$$Page extends React.Component {
}; };
} }
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidMount() { componentDidMount() {
this._dataSourceEngine.reloadDataSource(); this._dataSourceEngine.reloadDataSource();
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div> <div>
<Table <Table
dataSource={this.dataSourceMap["userList"]} dataSource={__$$eval(() => this.dataSourceMap["userList"])}
columns={[ columns={[
{ dataIndex: "name", title: "姓名" }, { dataIndex: "name", title: "姓名" },
{ dataIndex: "age", title: "年龄" }, { dataIndex: "age", title: "年龄" },
@ -83,6 +89,17 @@ class Example$$Page extends React.Component {
export default Example$$Page; export default Example$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { Switch } from "@alifd/next"; import { Switch } from "@alifd/next";
@ -8,11 +10,13 @@ import { create as __$$createDataSourceEngine } from "@alilc/lowcode-datasource-
import utils from "../../utils"; import utils from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
class Index$$Page extends React.Component { class Index$$Page extends React.Component {
_context = this;
_dataSourceConfig = this._defineDataSourceConfig(); _dataSourceConfig = this._defineDataSourceConfig();
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
runtimeConfig: true, runtimeConfig: true,
@ -32,9 +36,15 @@ class Index$$Page extends React.Component {
this.utils = utils; this.utils = utils;
__$$i18n._inject2(this);
this.state = {}; this.state = {};
} }
$ = () => null;
$$ = () => [];
_defineDataSourceConfig() { _defineDataSourceConfig() {
const _this = this; const _this = this;
return { return {
@ -59,30 +69,27 @@ class Index$$Page extends React.Component {
}; };
} }
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidMount() { componentDidMount() {
this._dataSourceEngine.reloadDataSource(); this._dataSourceEngine.reloadDataSource();
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div> <div>
<div> <div>
{this.dataSourceMap.todos.data.map((item, index) => {__$$evalArray(() => this.dataSourceMap.todos.data).map(
((__$$context) => ( (item, index) =>
<div> ((__$$context) => (
<Switch <div>
checkedChildren="开" <Switch
unCheckedChildren="关" checkedChildren="开"
checked={item.done} unCheckedChildren="关"
/> checked={__$$eval(() => item.done)}
</div> />
))(__$$createChildContext(__$$context, { item, index })) </div>
))(__$$createChildContext(__$$context, { item, index }))
)} )}
</div> </div>
</div> </div>
@ -92,6 +99,17 @@ class Index$$Page extends React.Component {
export default Index$$Page; export default Index$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { import {
@ -25,7 +27,7 @@ import {
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
@ -36,6 +38,8 @@ const AliAutoSearchTableDefault = AliAutoSearchTable.default;
const NextBlockCell = NextBlock.Cell; const NextBlockCell = NextBlock.Cell;
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
constructor(props, context) { constructor(props, context) {
super(props); super(props);
@ -43,6 +47,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { this.state = {
pkgs: [], pkgs: [],
total: 0, total: 0,
@ -71,10 +77,6 @@ class Test$$Page extends React.Component {
return this._refsManager.getAll(refName); return this._refsManager.getAll(refName);
}; };
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidUpdate(prevProps, prevState, snapshot) {} componentDidUpdate(prevProps, prevState, snapshot) {}
componentWillUnmount() {} componentWillUnmount() {}
@ -181,8 +183,8 @@ class Test$$Page extends React.Component {
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div <div
ref={this._refsManager.linkRef("outterView")} ref={this._refsManager.linkRef("outterView")}
@ -190,7 +192,7 @@ class Test$$Page extends React.Component {
> >
<Modal <Modal
title="查看结果" title="查看结果"
visible={this.state.resultVisible} visible={__$$eval(() => this.state.resultVisible)}
footer={ footer={
<Button <Button
type="primary" type="primary"
@ -236,12 +238,13 @@ class Test$$Page extends React.Component {
width="720px" width="720px"
centered={true} centered={true}
> >
{this.state.results.map((item, index) => {__$$evalArray(() => this.state.results).map((item, index) =>
((__$$context) => ( ((__$$context) => (
<AliAutoDivDefault style={{ width: "100%" }}> <AliAutoDivDefault style={{ width: "100%" }}>
{!!( {!!__$$eval(
__$$context.state.results && () =>
__$$context.state.results.length > 0 __$$context.state.results &&
__$$context.state.results.length > 0
) && ( ) && (
<AliAutoDivDefault <AliAutoDivDefault
style={{ style={{
@ -275,16 +278,22 @@ class Test$$Page extends React.Component {
</AliAutoDivDefault> </AliAutoDivDefault>
)} )}
<Typography.Text> <Typography.Text>
{__$$context.formatResult(item)} {__$$eval(() => __$$context.formatResult(item))}
</Typography.Text> </Typography.Text>
{!!item.download_link && ( {!!__$$eval(() => item.download_link) && (
<Typography.Link href={item.download_link} target="_blank"> <Typography.Link
href={__$$eval(() => item.download_link)}
target="_blank"
>
{" "} {" "}
- 点击下载 - 点击下载
</Typography.Link> </Typography.Link>
)} )}
{!!item.release_notes && ( {!!__$$eval(() => item.release_notes) && (
<Typography.Link href={item.release_notes} target="_blank"> <Typography.Link
href={__$$eval(() => item.release_notes)}
target="_blank"
>
{" "} {" "}
- 跳转发布节点 - 跳转发布节点
</Typography.Link> </Typography.Link>
@ -363,7 +372,7 @@ class Test$$Page extends React.Component {
<Form.Item label="项目名称/渠道号" name="channel_id"> <Form.Item label="项目名称/渠道号" name="channel_id">
<Select <Select
style={{ width: "280px" }} style={{ width: "280px" }}
options={this.state.projects} options={__$$eval(() => this.state.projects)}
showArrow={true} showArrow={true}
tokenSeparators={[]} tokenSeparators={[]}
showSearch={true} showSearch={true}
@ -410,13 +419,14 @@ class Test$$Page extends React.Component {
flex={true} flex={true}
> >
<ConfigProvider locale="zh-CN"> <ConfigProvider locale="zh-CN">
{!!( {!!__$$eval(
!this.state.isSearch || () =>
(this.state.isSearch && this.state.pkgs.length > 0) !this.state.isSearch ||
(this.state.isSearch && this.state.pkgs.length > 0)
) && ( ) && (
<AliAutoSearchTableDefault <AliAutoSearchTableDefault
rowKey="key" rowKey="key"
dataSource={this.state.pkgs} dataSource={__$$eval(() => this.state.pkgs)}
columns={[ columns={[
{ {
title: "ID", title: "ID",
@ -431,14 +441,13 @@ class Test$$Page extends React.Component {
width: 142, width: 142,
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => ((__$$context) =>
text __$$evalArray(() => text.split(",")).map(
.split(",") (item, index) =>
.map((item, index) =>
((__$$context) => ( ((__$$context) => (
<Typography.Text <Typography.Text
style={{ display: "block" }} style={{ display: "block" }}
> >
{item} {__$$eval(() => item)}
</Typography.Text> </Typography.Text>
))( ))(
__$$createChildContext(__$$context, { __$$createChildContext(__$$context, {
@ -446,7 +455,7 @@ class Test$$Page extends React.Component {
index, index,
}) })
) )
))( ))(
__$$createChildContext(__$$context, { __$$createChildContext(__$$context, {
text, text,
record, record,
@ -461,26 +470,32 @@ class Test$$Page extends React.Component {
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => ( ((__$$context) => (
<Tooltip <Tooltip
title={(text || []).map((item, index) => title={__$$evalArray(() => text || []).map(
((__$$context) => ( (item, index) =>
<Typography.Text ((__$$context) => (
style={{ <Typography.Text
display: "block", style={{
color: "#FFFFFF", display: "block",
}} color: "#FFFFFF",
> }}
{item.channelId + " / " + item.version} >
</Typography.Text> {__$$eval(
))( () =>
__$$createChildContext(__$$context, { item.channelId +
item, " / " +
index, item.version
}) )}
) </Typography.Text>
))(
__$$createChildContext(__$$context, {
item,
index,
})
)
)} )}
> >
<Typography.Text> <Typography.Text>
{text[0].version} {__$$eval(() => text[0].version)}
</Typography.Text> </Typography.Text>
</Tooltip> </Tooltip>
))( ))(
@ -504,9 +519,9 @@ class Test$$Page extends React.Component {
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => [ ((__$$context) => [
<Typography.Text> <Typography.Text>
{__$$context.statusDesc[text]} {__$$eval(() => __$$context.statusDesc[text])}
</Typography.Text>, </Typography.Text>,
!!(text === 2) && ( !!__$$eval(() => text === 2) && (
<Icon <Icon
type="SyncOutlined" type="SyncOutlined"
size={16} size={16}
@ -550,12 +565,15 @@ class Test$$Page extends React.Component {
dataIndex: "jenkins_link", dataIndex: "jenkins_link",
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => [ ((__$$context) => [
!!text && ( !!__$$eval(() => text) && (
<Typography.Link href={text} target="_blank"> <Typography.Link
href={__$$eval(() => text)}
target="_blank"
>
查看 查看
</Typography.Link> </Typography.Link>
), ),
!!!text && ( !!__$$eval(() => !text) && (
<Typography.Text>暂无</Typography.Text> <Typography.Text>暂无</Typography.Text>
), ),
])( ])(
@ -573,7 +591,7 @@ class Test$$Page extends React.Component {
width: 120, width: 120,
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => [ ((__$$context) => [
!!text && ( !!__$$eval(() => text) && (
<Typography.Link <Typography.Link
href="http://rivermap.alibaba.net/dashboard/testExecute" href="http://rivermap.alibaba.net/dashboard/testExecute"
target="_blank" target="_blank"
@ -581,7 +599,7 @@ class Test$$Page extends React.Component {
查看 查看
</Typography.Link> </Typography.Link>
), ),
!!!text && ( !!__$$eval(() => !text) && (
<Typography.Text>暂无</Typography.Text> <Typography.Text>暂无</Typography.Text>
), ),
])( ])(
@ -666,7 +684,7 @@ class Test$$Page extends React.Component {
); );
}.bind(__$$context)} }.bind(__$$context)}
ghost={false} ghost={false}
href={text} href={__$$eval(() => text)}
> >
查看 查看
</Button> </Button>
@ -738,7 +756,7 @@ class Test$$Page extends React.Component {
]} ]}
actions={[]} actions={[]}
pagination={{ pagination={{
total: this.state.total, total: __$$eval(() => this.state.total),
defaultPageSize: 8, defaultPageSize: 8,
onPageChange: function () { onPageChange: function () {
return this.onPageChange.apply( return this.onPageChange.apply(
@ -764,9 +782,9 @@ class Test$$Page extends React.Component {
align="left" align="left"
flex={true} flex={true}
> >
{!!(this.state.pkgs.length < 1 && this.state.isSearch) && ( {!!__$$eval(
<Empty description="暂无数据" /> () => this.state.pkgs.length < 1 && this.state.isSearch
)} ) && <Empty description="暂无数据" />}
</NextP> </NextP>
</NextBlockCell> </NextBlockCell>
</NextBlock> </NextBlock>
@ -778,6 +796,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -1,8 +1,9 @@
import IntlMessageFormat from "intl-messageformat";
const i18nConfig = {}; const i18nConfig = {};
let locale = "en-US"; let locale =
typeof navigator === "object" && typeof navigator.language === "string"
? navigator.language
: "zh-CN";
const getLocale = () => locale; const getLocale = () => locale;
@ -10,24 +11,67 @@ const setLocale = (target) => {
locale = target; locale = target;
}; };
const i18nFormat = ({ id, defaultMessage }, variables) => { const isEmptyVariables = (variables) =>
(Array.isArray(variables) && variables.length === 0) ||
(typeof variables === "object" &&
(!variables || Object.keys(variables).length === 0));
// 按低代码规范里面的要求进行变量替换
const format = (msg, variables) =>
typeof msg === "string"
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? "")
: msg;
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
const msg = const msg =
(i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) || i18nConfig[locale]?.[id] ??
i18nConfig[locale.replace("-", "_")]?.[id] ??
defaultMessage; defaultMessage;
if (msg == null) { if (msg == null) {
console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale); console.warn("[i18n]: unknown message id: %o (locale=%o)", id, locale);
return `${id}`; return fallback === undefined ? `${id}` : fallback;
} }
if (!variables || !variables.length) { return format(msg, variables);
return msg; };
const i18n = (id, params) => {
return i18nFormat({ id }, params);
};
// 将国际化的一些方法注入到目标对象&上下文中
const _inject2 = (target) => {
target.i18n = i18n;
target.getLocale = getLocale;
target.setLocale = (locale) => {
setLocale(locale);
target.forceUpdate();
};
target._i18nText = (t) => {
// 优先取直接传过来的语料
const localMsg = t[locale] ?? t[String(locale).replace("-", "_")];
if (localMsg != null) {
return format(localMsg, t.params);
}
// 其次用项目级别的
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
if (projectMsg != null) {
return projectMsg;
}
// 兜底用 use 指定的或默认语言的
return format(t[t.use || "zh_CN"] ?? t.en_US, t.params);
};
// 注入到上下文中去
if (target._context && target._context !== target) {
Object.assign(target._context, {
i18n,
getLocale,
setLocale: target.setLocale,
});
} }
return new IntlMessageFormat(msg, locale).format(variables);
}; };
const i18n = (id) => { export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
return i18nFormat({ id });
};
export { getLocale, setLocale, i18n, i18nFormat };

View File

@ -1,3 +1,5 @@
// : "__$$" 访
// react
import React from "react"; import React from "react";
import { import {
@ -25,7 +27,7 @@ import {
import utils, { RefsManager } from "../../utils"; import utils, { RefsManager } from "../../utils";
import { i18n as _$$i18n } from "../../i18n"; import * as __$$i18n from "../../i18n";
import "./index.css"; import "./index.css";
@ -36,6 +38,8 @@ const AliAutoSearchTableDefault = AliAutoSearchTable.default;
const NextBlockCell = NextBlock.Cell; const NextBlockCell = NextBlock.Cell;
class Test$$Page extends React.Component { class Test$$Page extends React.Component {
_context = this;
constructor(props, context) { constructor(props, context) {
super(props); super(props);
@ -43,6 +47,8 @@ class Test$$Page extends React.Component {
this._refsManager = new RefsManager(); this._refsManager = new RefsManager();
__$$i18n._inject2(this);
this.state = { this.state = {
pkgs: [], pkgs: [],
total: 0, total: 0,
@ -79,10 +85,6 @@ class Test$$Page extends React.Component {
return this._refsManager.getAll(refName); return this._refsManager.getAll(refName);
}; };
i18n = (i18nKey) => {
return _$$i18n(i18nKey);
};
componentDidUpdate(prevProps, prevState, snapshot) {} componentDidUpdate(prevProps, prevState, snapshot) {}
componentWillUnmount() {} componentWillUnmount() {}
@ -207,8 +209,8 @@ class Test$$Page extends React.Component {
} }
render() { render() {
const __$$context = this; const __$$context = this._context || this;
const { state } = this; const { state } = __$$context;
return ( return (
<div <div
ref={this._refsManager.linkRef("outterView")} ref={this._refsManager.linkRef("outterView")}
@ -216,7 +218,7 @@ class Test$$Page extends React.Component {
> >
<Modal <Modal
title="查看结果" title="查看结果"
visible={this.state.resultVisible} visible={__$$eval(() => this.state.resultVisible)}
footer={ footer={
<Button <Button
type="primary" type="primary"
@ -267,7 +269,9 @@ class Test$$Page extends React.Component {
maskClosable={true} maskClosable={true}
> >
<AliAutoDivDefault style={{ width: "100%" }}> <AliAutoDivDefault style={{ width: "100%" }}>
{!!(this.state.results && this.state.results.length > 0) && ( {!!__$$eval(
() => this.state.results && this.state.results.length > 0
) && (
<AliAutoDivDefault <AliAutoDivDefault
style={{ style={{
width: "100%", width: "100%",
@ -299,20 +303,26 @@ class Test$$Page extends React.Component {
</Button> </Button>
</AliAutoDivDefault> </AliAutoDivDefault>
)} )}
{this.state.results.map((item, index) => {__$$evalArray(() => this.state.results).map((item, index) =>
((__$$context) => ( ((__$$context) => (
<AliAutoDivDefault style={{ width: "100%", marginTop: "10px" }}> <AliAutoDivDefault style={{ width: "100%", marginTop: "10px" }}>
<Typography.Text> <Typography.Text>
{__$$context.formatResult(item)} {__$$eval(() => __$$context.formatResult(item))}
</Typography.Text> </Typography.Text>
{!!item.download_link && ( {!!__$$eval(() => item.download_link) && (
<Typography.Link href={item.download_link} target="_blank"> <Typography.Link
href={__$$eval(() => item.download_link)}
target="_blank"
>
{" "} {" "}
- 点击下载 - 点击下载
</Typography.Link> </Typography.Link>
)} )}
{!!item.release_notes && ( {!!__$$eval(() => item.release_notes) && (
<Typography.Link href={item.release_notes} target="_blank"> <Typography.Link
href={__$$eval(() => item.release_notes)}
target="_blank"
>
{" "} {" "}
- 跳转发布节点 - 跳转发布节点
</Typography.Link> </Typography.Link>
@ -376,7 +386,7 @@ class Test$$Page extends React.Component {
preserve={true} preserve={true}
scrollToFirstError={true} scrollToFirstError={true}
size="middle" size="middle"
values={this.state.searchValues} values={__$$eval(() => this.state.searchValues)}
> >
<Form.Item <Form.Item
label="项目名称/渠道号" label="项目名称/渠道号"
@ -386,7 +396,7 @@ class Test$$Page extends React.Component {
> >
<Select <Select
style={{ width: "320px" }} style={{ width: "320px" }}
options={this.state.projects} options={__$$eval(() => this.state.projects)}
showArrow={false} showArrow={false}
tokenSeparators={[]} tokenSeparators={[]}
showSearch={true} showSearch={true}
@ -452,14 +462,16 @@ class Test$$Page extends React.Component {
<Form.Item label="构建人" name="user_id"> <Form.Item label="构建人" name="user_id">
<Select <Select
style={{ width: "210px" }} style={{ width: "210px" }}
options={this.state.userOptions} options={__$$eval(() => this.state.userOptions)}
showSearch={true} showSearch={true}
defaultActiveFirstOption={false} defaultActiveFirstOption={false}
size="middle" size="middle"
bordered={true} bordered={true}
filterOption={true} filterOption={true}
optionFilterProp="label" optionFilterProp="label"
notFoundContent={this.userNotFoundContent} notFoundContent={__$$eval(
() => this.userNotFoundContent
)}
showArrow={false} showArrow={false}
placeholder="请输入构建人" placeholder="请输入构建人"
__events={{ __events={{
@ -566,13 +578,14 @@ class Test$$Page extends React.Component {
align="left" align="left"
flex={true} flex={true}
> >
{!!( {!!__$$eval(
!this.state.isSearch || () =>
(this.state.isSearch && this.state.pkgs.length > 0) !this.state.isSearch ||
(this.state.isSearch && this.state.pkgs.length > 0)
) && ( ) && (
<AliAutoSearchTableDefault <AliAutoSearchTableDefault
rowKey="key" rowKey="key"
dataSource={this.state.pkgs} dataSource={__$$eval(() => this.state.pkgs)}
columns={[ columns={[
{ title: "ID", dataIndex: "id", key: "name", width: 80 }, { title: "ID", dataIndex: "id", key: "name", width: 80 },
{ {
@ -582,12 +595,11 @@ class Test$$Page extends React.Component {
width: 142, width: 142,
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => ((__$$context) =>
text __$$evalArray(() => text.split(",")).map(
.split(",") (item, index) =>
.map((item, index) =>
((__$$context) => ( ((__$$context) => (
<Typography.Text style={{ display: "block" }}> <Typography.Text style={{ display: "block" }}>
{item} {__$$eval(() => item)}
</Typography.Text> </Typography.Text>
))( ))(
__$$createChildContext(__$$context, { __$$createChildContext(__$$context, {
@ -595,7 +607,7 @@ class Test$$Page extends React.Component {
index, index,
}) })
) )
))( ))(
__$$createChildContext(__$$context, { __$$createChildContext(__$$context, {
text, text,
record, record,
@ -610,26 +622,30 @@ class Test$$Page extends React.Component {
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => ( ((__$$context) => (
<Tooltip <Tooltip
title={(text || []).map((item, index) => title={__$$evalArray(() => text || []).map(
((__$$context) => ( (item, index) =>
<Typography.Text ((__$$context) => (
style={{ <Typography.Text
display: "block", style={{
color: "#FFFFFF", display: "block",
}} color: "#FFFFFF",
> }}
{item.channelId + " / " + item.version} >
</Typography.Text> {__$$eval(
))( () =>
__$$createChildContext(__$$context, { item.channelId + " / " + item.version
item, )}
index, </Typography.Text>
}) ))(
) __$$createChildContext(__$$context, {
item,
index,
})
)
)} )}
> >
<Typography.Text> <Typography.Text>
{text[0].version} {__$$eval(() => text[0].version)}
</Typography.Text> </Typography.Text>
</Tooltip> </Tooltip>
))( ))(
@ -653,9 +669,9 @@ class Test$$Page extends React.Component {
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => [ ((__$$context) => [
<Typography.Text> <Typography.Text>
{__$$context.statusDesc[text]} {__$$eval(() => __$$context.statusDesc[text])}
</Typography.Text>, </Typography.Text>,
!!(text === 2) && ( !!__$$eval(() => text === 2) && (
<Icon <Icon
type="SyncOutlined" type="SyncOutlined"
size={16} size={16}
@ -699,12 +715,17 @@ class Test$$Page extends React.Component {
dataIndex: "jenkins_link", dataIndex: "jenkins_link",
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => [ ((__$$context) => [
!!text && ( !!__$$eval(() => text) && (
<Typography.Link href={text} target="_blank"> <Typography.Link
href={__$$eval(() => text)}
target="_blank"
>
查看 查看
</Typography.Link> </Typography.Link>
), ),
!!!text && <Typography.Text>暂无</Typography.Text>, !!__$$eval(() => !text) && (
<Typography.Text>暂无</Typography.Text>
),
])( ])(
__$$createChildContext(__$$context, { __$$createChildContext(__$$context, {
text, text,
@ -720,7 +741,7 @@ class Test$$Page extends React.Component {
width: 120, width: 120,
render: (text, record, index) => render: (text, record, index) =>
((__$$context) => [ ((__$$context) => [
!!text && ( !!__$$eval(() => text) && (
<Typography.Link <Typography.Link
href="http://rivermap.alibaba.net/dashboard/testExecute" href="http://rivermap.alibaba.net/dashboard/testExecute"
target="_blank" target="_blank"
@ -728,7 +749,9 @@ class Test$$Page extends React.Component {
查看 查看
</Typography.Link> </Typography.Link>
), ),
!!!text && <Typography.Text>暂无</Typography.Text>, !!__$$eval(() => !text) && (
<Typography.Text>暂无</Typography.Text>
),
])( ])(
__$$createChildContext(__$$context, { __$$createChildContext(__$$context, {
text, text,
@ -811,7 +834,7 @@ class Test$$Page extends React.Component {
); );
}.bind(__$$context)} }.bind(__$$context)}
ghost={false} ghost={false}
href={text} href={__$$eval(() => text)}
> >
查看 查看
</Button> </Button>
@ -883,7 +906,7 @@ class Test$$Page extends React.Component {
]} ]}
actions={[]} actions={[]}
pagination={{ pagination={{
total: this.state.total, total: __$$eval(() => this.state.total),
defaultPageSize: 10, defaultPageSize: 10,
onPageChange: function () { onPageChange: function () {
return this.onPageChange.apply( return this.onPageChange.apply(
@ -915,9 +938,9 @@ class Test$$Page extends React.Component {
align="left" align="left"
flex={true} flex={true}
> >
{!!(this.state.pkgs.length < 1 && this.state.isSearch) && ( {!!__$$eval(
<Empty description="暂无数据" /> () => this.state.pkgs.length < 1 && this.state.isSearch
)} ) && <Empty description="暂无数据" />}
</NextP> </NextP>
</NextBlockCell> </NextBlockCell>
</NextBlock> </NextBlock>
@ -929,6 +952,17 @@ class Test$$Page extends React.Component {
export default Test$$Page; export default Test$$Page;
function __$$eval(expr) {
try {
return expr();
} catch (error) {}
}
function __$$evalArray(expr) {
const res = __$$eval(expr);
return Array.isArray(res) ? res : [];
}
function __$$createChildContext(oldContext, ext) { function __$$createChildContext(oldContext, ext) {
const childContext = { const childContext = {
...oldContext, ...oldContext,

View File

@ -0,0 +1,52 @@
{
"version": "1.0.0",
"componentsMap": [
{
"package": "react-greetings",
"version": "1.0.0",
"componentName": "Greetings",
"exportName": "Greetings",
"destructuring": true
}
],
"componentsTree": [
{
"componentName": "Page",
"id": "node_ocl137q7oc1",
"fileName": "test",
"props": { "style": {} },
"lifeCycles": {},
"dataSource": { "list": [] },
"state": {
"name": "lowcode world"
},
"methods": {},
"children": [
{
"componentName": "Greetings",
"id": "node_ocl137q7oc4",
"props": {
"content": {
"type": "i18n",
"key": "greetings.hello",
"params": {
"name": {
"type": "JSExpression",
"value": "this.state.name"
}
}
}
}
}
]
}
],
"i18n": {
"zh_CN": {
"greetings.hello": "${name}, 你好!"
},
"en_US": {
"greetings.hello": "Hello, ${name}!"
}
}
}

View File

@ -0,0 +1,54 @@
import CodeGenerator from '../../src';
import * as fs from 'fs';
import * as path from 'path';
import { ProjectSchema } from '@alilc/lowcode-types';
import { createDiskPublisher } from '../helpers/solutionHelper';
const testCaseBaseName = path.basename(__filename, '.test.ts');
const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);
const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);
jest.setTimeout(60 * 60 * 1000);
describe(testCaseBaseName, () => {
test('default import', async () => {
await exportProject(inputSchemaJsonFile, outputDir, {});
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
expect(generatedPageFileContent).toContain(
`
<Greetings
content={this._i18nText({
key: "greetings.hello",
params: { name: this.state.name },
})}
/>
`.trim(),
);
});
});
function exportProject(
importPath: string,
outputPath: string,
mergeSchema?: Partial<ProjectSchema>,
) {
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };
const builder = CodeGenerator.solutions.icejs({ tolerateEvalErrors: false });
return builder.generateProject(schema).then(async (result) => {
const publisher = createDiskPublisher();
await publisher.publish({
project: result,
outputPath,
projectSlug: 'demo-project',
createProjectFolder: true,
});
return result;
});
}
function readOutputTextFile(outputFilePath: string): string {
return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');
}

View File

@ -2,6 +2,7 @@ import CodeGenerator from '../../src';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { ProjectSchema } from '@alilc/lowcode-types'; import { ProjectSchema } from '@alilc/lowcode-types';
import { createDiskPublisher } from '../helpers/solutionHelper';
const testCaseBaseName = path.basename(__filename, '.test.ts'); const testCaseBaseName = path.basename(__filename, '.test.ts');
const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`); const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);
@ -205,7 +206,7 @@ function exportProject(
return builder.generateProject(schema).then(async (result) => { return builder.generateProject(schema).then(async (result) => {
// displayResultInConsole(result); // displayResultInConsole(result);
const publisher = CodeGenerator.publishers.disk(); const publisher = createDiskPublisher();
await publisher.publish({ await publisher.publish({
project: result, project: result,
outputPath, outputPath,

View File

@ -1,6 +1,7 @@
import CodeGenerator from '../../src'; import CodeGenerator from '../../src';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { createDiskPublisher } from '../helpers/solutionHelper';
const testCaseBaseName = path.basename(__filename, '.test.ts'); const testCaseBaseName = path.basename(__filename, '.test.ts');
@ -31,7 +32,7 @@ function exportProject(inputPath: string, outputPath: string) {
return builder.generateProject(newSchema).then(async (result) => { return builder.generateProject(newSchema).then(async (result) => {
// displayResultInConsole(result); // displayResultInConsole(result);
const publisher = CodeGenerator.publishers.disk(); const publisher = createDiskPublisher();
await publisher.publish({ await publisher.publish({
project: result, project: result,
outputPath, outputPath,

View File

@ -1,6 +1,7 @@
import CodeGenerator from '../../src'; import CodeGenerator from '../../src';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { createDiskPublisher } from '../helpers/solutionHelper';
const testCaseBaseName = path.basename(__filename, '.test.ts'); const testCaseBaseName = path.basename(__filename, '.test.ts');
@ -31,7 +32,7 @@ function exportProject(inputPath: string, outputPath: string) {
return builder.generateProject(newSchema).then(async (result) => { return builder.generateProject(newSchema).then(async (result) => {
// displayResultInConsole(result); // displayResultInConsole(result);
const publisher = CodeGenerator.publishers.disk(); const publisher = createDiskPublisher();
await publisher.publish({ await publisher.publish({
project: result, project: result,
outputPath, outputPath,

View File

@ -1,6 +1,7 @@
import CodeGenerator from '../../src'; import CodeGenerator from '../../src';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { createDiskPublisher } from '../helpers/solutionHelper';
const testCaseBaseName = path.basename(__filename, '.test.ts'); const testCaseBaseName = path.basename(__filename, '.test.ts');
@ -37,7 +38,7 @@ function exportProject(inputPath: string, outputPath: string) {
return builder.generateProject(newSchema).then(async (result) => { return builder.generateProject(newSchema).then(async (result) => {
// displayResultInConsole(result); // displayResultInConsole(result);
const publisher = CodeGenerator.publishers.disk(); const publisher = createDiskPublisher();
await publisher.publish({ await publisher.publish({
project: result, project: result,
outputPath, outputPath,

View File

@ -1,6 +1,7 @@
import CodeGenerator from '../../src'; import CodeGenerator from '../../src';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { createDiskPublisher } from '../helpers/solutionHelper';
const testCaseBaseName = path.basename(__filename, '.test.ts'); const testCaseBaseName = path.basename(__filename, '.test.ts');
@ -25,7 +26,7 @@ function exportProject(inputPath: string, outputPath: string) {
return builder.generateProject(newSchema).then(async (result) => { return builder.generateProject(newSchema).then(async (result) => {
// displayResultInConsole(result); // displayResultInConsole(result);
const publisher = CodeGenerator.publishers.disk(); const publisher = createDiskPublisher();
await publisher.publish({ await publisher.publish({
project: result, project: result,
outputPath, outputPath,

View File

@ -1,6 +1,7 @@
import CodeGenerator from '../../src'; import CodeGenerator from '../../src';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { createDiskPublisher } from '../helpers/solutionHelper';
test('page-element1', async () => { test('page-element1', async () => {
const inputSchemaJsonFile = path.join(__dirname, 'page-element1.schema.json'); const inputSchemaJsonFile = path.join(__dirname, 'page-element1.schema.json');
@ -67,7 +68,7 @@ function exportProject(inputPath: string, outputPath: string) {
return builder.generateProject(newSchema).then(async (result) => { return builder.generateProject(newSchema).then(async (result) => {
// displayResultInConsole(result); // displayResultInConsole(result);
const publisher = CodeGenerator.publishers.disk(); const publisher = createDiskPublisher();
await publisher.publish({ await publisher.publish({
project: result, project: result,
outputPath, outputPath,

View File

@ -1,6 +1,7 @@
import CodeGenerator from '../../src'; import CodeGenerator from '../../src';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { createDiskPublisher } from '../helpers/solutionHelper';
test('page-element2', async () => { test('page-element2', async () => {
const inputSchemaJsonFile = path.join(__dirname, 'page-element2.schema.json'); const inputSchemaJsonFile = path.join(__dirname, 'page-element2.schema.json');
@ -67,7 +68,7 @@ function exportProject(inputPath: string, outputPath: string) {
return builder.generateProject(newSchema).then(async (result) => { return builder.generateProject(newSchema).then(async (result) => {
// displayResultInConsole(result); // displayResultInConsole(result);
const publisher = CodeGenerator.publishers.disk(); const publisher = createDiskPublisher();
await publisher.publish({ await publisher.publish({
project: result, project: result,
outputPath, outputPath,

View File

@ -0,0 +1,677 @@
{
"version": "1.0.0",
"componentsMap": [
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Typography",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"subName": "Text",
"componentName": "Typography.Text"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Select",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"componentName": "Select"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Space",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"componentName": "Space"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Button",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"componentName": "Button"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "InputNumber",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"componentName": "InputNumber"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Form",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"subName": "Item",
"componentName": "Form.Item"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Input",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"subName": "TextArea",
"componentName": "Input.TextArea"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Form",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"componentName": "Form"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Modal",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"componentName": "Modal"
},
{
"package": "@alife/mc-assets-1935",
"version": "0.1.16",
"exportName": "AliAutoSearchTable",
"main": "build/lowcode/index.js",
"destructuring": true,
"subName": "default",
"componentName": "AliAutoSearchTableDefault"
},
{
"package": "@alilc/antd-lowcode",
"version": "0.5.4",
"exportName": "Card",
"main": "dist/antd-lowcode.esm.js",
"destructuring": true,
"componentName": "Card"
},
{
"package": "@alife/container",
"version": "0.3.7",
"exportName": "P",
"main": "lib/index.js",
"destructuring": true,
"subName": "",
"componentName": "NextP"
},
{
"package": "@alife/container",
"version": "0.3.7",
"exportName": "Block",
"main": "lib/index.js",
"destructuring": true,
"subName": "Cell",
"componentName": "NextBlockCell"
},
{
"package": "@alife/container",
"version": "0.3.7",
"exportName": "Block",
"main": "lib/index.js",
"destructuring": true,
"subName": "",
"componentName": "NextBlock"
},
{
"devMode": "lowcode",
"componentName": "Slot"
},
{
"package": "@alife/container",
"version": "0.3.7",
"exportName": "Page",
"main": "lib/index.js",
"destructuring": true,
"subName": "",
"componentName": "NextPage"
},
{
"devMode": "lowcode",
"componentName": "Page"
}
],
"componentsTree": [
{
"componentName": "Page",
"id": "node_dockcviv8fo1",
"props": {
"ref": "outterView",
"style": {
"height": "100%"
}
},
"fileName": "test",
"dataSource": {
"list": []
},
"css": "body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}",
"lifeCycles": {
"componentDidMount": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
},
"componentWillUnmount": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
},
"componentDidUpdate": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
}
},
"methods": {
"onChange": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
},
"getActions": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
},
"onCreateOrder": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
},
"onCancelModal": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
},
"onConfirmCreateOrder": {
"type": "JSFunction",
"value": "function() { /* ... */ }"
}
},
"state": {
"name": "nongzhou",
"gateways": [],
"selectedGateway": null,
"records": [],
"modalVisible": false
},
"children": [
{
"componentName": "NextPage",
"id": "node_ocknqx3esma",
"props": {
"columns": 12,
"headerDivider": true,
"placeholderStyle": {
"gridRowEnd": "span 1",
"gridColumnEnd": "span 12"
},
"placeholder": "页面主体内容拖拽Block布局组件到这里",
"header": {
"type": "JSSlot",
"title": "header"
},
"headerProps": {
"background": "surface"
},
"footer": {
"type": "JSSlot",
"title": "footer"
},
"minHeight": "100vh",
"style": {
"cursor": "pointer"
}
},
"title": "页面",
"children": [
{
"componentName": "NextBlock",
"id": "node_ocknqx3esmb",
"props": {
"prefix": "next-",
"placeholderStyle": {
"height": "100%"
},
"noPadding": false,
"noBorder": false,
"background": "surface",
"layoutmode": "O",
"colSpan": 12,
"rowSpan": 1,
"childTotalColumns": 12
},
"title": "区块",
"children": [
{
"componentName": "NextBlockCell",
"id": "node_ocknqx3esmc",
"props": {
"title": "",
"prefix": "next-",
"placeholderStyle": {
"height": "100%"
},
"layoutmode": "O",
"childTotalColumns": 12,
"isAutoContainer": true,
"colSpan": 12,
"rowSpan": 1
},
"children": [
{
"componentName": "NextP",
"id": "node_ocknqx3esm1j",
"props": {
"wrap": false,
"type": "body2",
"verAlign": "middle",
"textSpacing": true,
"align": "left",
"full": true,
"flex": true
},
"title": "段落",
"children": [
{
"componentName": "Card",
"id": "node_ocknqx3esm1k",
"props": {
"title": ""
},
"children": [
{
"componentName": "Space",
"id": "node_ocknqx3esm1n",
"props": {
"size": 0,
"align": "center",
"direction": "horizontal"
},
"children": [
{
"componentName": "Typography.Text",
"id": "node_ocknqx3esm1l",
"props": {
"children": "所在网关:"
}
},
{
"componentName": "Select",
"id": "node_ocknqx3esm1m",
"props": {
"style": {
"marginTop": "16px",
"marginRight": "16px",
"marginBottom": "16px",
"marginLeft": "16px",
"width": "400px",
"display": "inline-block"
},
"options": {
"type": "JSExpression",
"value": "this.state.gateways"
},
"mode": "single",
"defaultValue": ["auto-edd-uniproxy"],
"labelInValue": true,
"showSearch": true,
"allowClear": false,
"placeholder": "请选取网关",
"showArrow": true,
"loading": false,
"tokenSeparators": [],
"__events": {
"eventDataList": [
{
"type": "componentEvent",
"name": "onChange",
"relatedEventName": "onChange"
}
],
"eventList": [
{
"name": "onBlur",
"disabled": false
},
{
"name": "onChange",
"disabled": true
},
{
"name": "onDeselect",
"disabled": false
},
{
"name": "onFocus",
"disabled": false
},
{
"name": "onInputKeyDown",
"disabled": false
},
{
"name": "onMouseEnter",
"disabled": false
},
{
"name": "onMouseLeave",
"disabled": false
},
{
"name": "onPopupScroll",
"disabled": false
},
{
"name": "onSearch",
"disabled": false
},
{
"name": "onSelect",
"disabled": false
},
{
"name": "onDropdownVisibleChange",
"disabled": false
}
]
},
"onChange": {
"type": "JSFunction",
"value": "function(){this.onChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
}
}
}
]
},
{
"componentName": "Button",
"id": "node_ockntwgdsn7",
"props": {
"type": "primary",
"children": "创建发布单",
"style": {
"display": "block",
"marginTop": "20px",
"marginBottom": "20px"
},
"__events": {
"eventDataList": [
{
"type": "componentEvent",
"name": "onClick",
"relatedEventName": "onCreateOrder"
}
],
"eventList": [
{
"name": "onClick",
"disabled": true
}
]
},
"onClick": {
"type": "JSFunction",
"value": "function(){this.onCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
}
}
},
{
"componentName": "Modal",
"id": "node_ockntx4eo9p",
"props": {
"title": "创建发布单",
"visible": {
"type": "JSExpression",
"value": "this.state.modalVisible"
},
"footer": "",
"__events": {
"eventDataList": [
{
"type": "componentEvent",
"name": "onCancel",
"relatedEventName": "onCancelModal"
}
],
"eventList": [
{
"name": "onCancel",
"disabled": true
},
{
"name": "onOk",
"disabled": false
}
]
},
"onCancel": {
"type": "JSFunction",
"value": "function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
},
"zIndex": 2000
},
"hidden": true,
"children": [
{
"componentName": "Form",
"id": "node_ockntx4eo9s",
"props": {
"labelCol": {
"span": 6
},
"wrapperCol": {
"span": 14
},
"onFinish": {
"type": "JSFunction",
"value": "function(){this.onConfirmCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
},
"name": "basic",
"__events": {
"eventDataList": [
{
"type": "componentEvent",
"name": "onFinish",
"relatedEventName": "onConfirmCreateOrder"
}
],
"eventList": [
{
"name": "onFinish",
"disabled": true
},
{
"name": "onFinishFailed",
"disabled": false
},
{
"name": "onFieldsChange",
"disabled": false
},
{
"name": "onValuesChange",
"disabled": false
}
]
}
},
"children": [
{
"componentName": "Form.Item",
"id": "node_ockntx4eo91k",
"props": {
"label": "发布批次"
},
"children": [
{
"componentName": "InputNumber",
"id": "node_ockntx4eo91l",
"props": {
"value": 3,
"min": 1
}
}
]
},
{
"componentName": "Form.Item",
"id": "node_ockntx4eo91r",
"props": {
"label": "批次间隔时间"
},
"children": [
{
"componentName": "InputNumber",
"id": "node_ockntx4eo91s",
"props": {
"value": 3
}
}
]
},
{
"componentName": "Form.Item",
"id": "node_ockntx4eo91y",
"props": {
"label": "备注 "
},
"children": [
{
"componentName": "Input.TextArea",
"id": "node_ockntx4eo91z",
"props": {
"rows": 3,
"placeholder": "请输入"
}
}
]
},
{
"componentName": "Form.Item",
"id": "node_ockntx4eo9v",
"props": {
"wrapperCol": {
"offset": 6
},
"style": {
"flexDirection": "row",
"alignItems": "flex-end",
"justifyContent": "center",
"display": "flex"
},
"labelAlign": "right"
},
"children": [
{
"componentName": "Button",
"id": "node_ockntx4eo9w",
"props": {
"type": "primary",
"children": "提交",
"htmlType": "submit"
}
},
{
"componentName": "Button",
"id": "node_ockntx4eo9x",
"props": {
"style": {
"marginLeft": 20
},
"children": "取消",
"__events": {
"eventDataList": [
{
"type": "componentEvent",
"name": "onClick",
"relatedEventName": "onCancelModal"
}
],
"eventList": [
{
"name": "onClick",
"disabled": true
}
]
},
"onClick": {
"type": "JSFunction",
"value": "function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
}
}
}
]
}
]
}
]
},
{
"componentName": "AliAutoSearchTableDefault",
"id": "node_ocknqx3esm1q",
"props": {
"rowKey": "key",
"dataSource": {
"type": "JSExpression",
"value": "this.state.records"
},
"columns": [
{
"title": "发布名称",
"dataIndex": "order_name",
"key": "name"
},
{
"title": "类型",
"dataIndex": "order_type_desc",
"key": "age"
},
{
"title": "发布状态",
"dataIndex": "order_status_desc",
"key": "address"
},
{
"title": "发布人",
"dataIndex": "creator_name"
},
{
"title": "当前批次/总批次",
"dataIndex": "cur_batch_no"
},
{
"title": "发布机器/总机器",
"dataIndex": "pubblish_ip_finish_num"
},
{
"title": "发布时间",
"dataIndex": "publish_id"
}
],
"actions": {
"type": "JSExpression",
"value": "this.actions || []"
},
"getActions": {
"type": "JSFunction",
"value": "function(){ return this.getActions.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
}
}
}
]
}
]
}
]
}
]
}
]
}
]
}
],
"i18n": {}
}

View File

@ -0,0 +1,57 @@
import CodeGenerator from '../../src';
import * as fs from 'fs';
import * as path from 'path';
import { ProjectSchema } from '@alilc/lowcode-types';
import { createDiskPublisher } from '../helpers/solutionHelper';
import { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';
const testCaseBaseName = path.basename(__filename, '.test.ts');
const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);
const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);
jest.setTimeout(60 * 60 * 1000);
describe(testCaseBaseName, () => {
test('methods will be set to context in constructor', async () => {
await exportProject(inputSchemaJsonFile, outputDir, {}, { inStrictMode: true });
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
expect(generatedPageFileContent).not.toContain('_context = this;');
expect(generatedPageFileContent).toContain('_context = this._createContext();');
expect(generatedPageFileContent).toContain(
`
this._context.onChange = this.onChange;
this._context.getActions = this.getActions;
this._context.onCreateOrder = this.onCreateOrder;
this._context.onCancelModal = this.onCancelModal;
this._context.onConfirmCreateOrder = this.onConfirmCreateOrder;
`.trim(),
);
});
});
function exportProject(
importPath: string,
outputPath: string,
mergeSchema?: Partial<ProjectSchema>,
options?: IceJsProjectBuilderOptions,
) {
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };
const builder = CodeGenerator.solutions.icejs(options);
return builder.generateProject(schema).then(async (result) => {
const publisher = createDiskPublisher();
await publisher.publish({
project: result,
outputPath,
projectSlug: 'demo-project',
createProjectFolder: true,
});
return result;
});
}
function readOutputTextFile(outputFilePath: string): string {
return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');
}

View File

@ -0,0 +1,58 @@
{
"version": "1.0.0",
"componentsMap": [
{
"package": "react-greetings",
"version": "1.0.0",
"componentName": "Greetings",
"exportName": "Greetings",
"destructuring": true
}
],
"componentsTree": [
{
"componentName": "Page",
"id": "node_ocl137q7oc1",
"fileName": "test",
"props": { "style": {} },
"lifeCycles": {},
"dataSource": { "list": [] },
"state": {
"name": "lowcode world",
"users": null
},
"methods": {},
"children": [
{
"componentName": "Greetings",
"id": "node_ocl137q7oc4",
"loop": {
"type": "JSExpression",
"value": "this.state.users"
},
"loopArgs": ["item", ""],
"props": {
"content": {
"type": "i18n",
"key": "greetings.hello",
"params": {
"name": {
"type": "JSExpression",
"value": "this.item"
}
}
}
}
}
]
}
],
"i18n": {
"zh_CN": {
"greetings.hello": "${name}, 你好!"
},
"en_US": {
"greetings.hello": "Hello, ${name}!"
}
}
}

View File

@ -0,0 +1,52 @@
import CodeGenerator from '../../src';
import * as fs from 'fs';
import * as path from 'path';
import { ProjectSchema } from '@alilc/lowcode-types';
import { createDiskPublisher } from '../helpers/solutionHelper';
import { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';
const testCaseBaseName = path.basename(__filename, '.test.ts');
const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);
const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);
jest.setTimeout(60 * 60 * 1000);
test('loop should be generated link __$$evalArray(xxx).map', async () => {
await exportProject(
inputSchemaJsonFile,
outputDir,
{},
{ inStrictMode: true, tolerateEvalErrors: true },
);
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
expect(generatedPageFileContent).toContain(
'{__$$evalArray(() => this.state.users).map((item, index) =>',
);
});
function exportProject(
importPath: string,
outputPath: string,
mergeSchema?: Partial<ProjectSchema>,
options?: IceJsProjectBuilderOptions,
) {
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };
const builder = CodeGenerator.solutions.icejs(options);
return builder.generateProject(schema).then(async (result) => {
const publisher = createDiskPublisher();
await publisher.publish({
project: result,
outputPath,
projectSlug: 'demo-project',
createProjectFolder: true,
});
return result;
});
}
function readOutputTextFile(outputFilePath: string): string {
return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');
}

View File

@ -0,0 +1,70 @@
{
"version": "1.0.0",
"componentsMap": [
{
"package": "react-greetings",
"version": "1.0.0",
"componentName": "Greetings",
"exportName": "Greetings",
"destructuring": true
}
],
"componentsTree": [
{
"componentName": "Page",
"id": "node_ocl137q7oc1",
"fileName": "test",
"props": { "style": {} },
"lifeCycles": {},
"dataSource": { "list": [] },
"state": {
"name": "lowcode world",
"users": null
},
"methods": {},
"children": [
{
"componentName": "Greetings",
"id": "node_ocl137q7oc4",
"loop": {
"type": "JSExpression",
"value": "this.state.users"
},
"loopArgs": ["item", ""],
"props": {
"content": {
"type": "i18n",
"key": "greetings.hello",
"params": { "name": { "type": "JSExpression", "value": "this.item" } }
}
},
"children": [
{
"componentName": "Greetings",
"id": "node_ocl137q7oc4",
"loop": {
"type": "JSExpression",
"value": "this.state.messages"
},
"loopArgs": ["msg", ""],
"props": {
"content": {
"type": "JSExpression",
"value": "this.msg"
}
}
}
]
}
]
}
],
"i18n": {
"zh_CN": {
"greetings.hello": "${name}, 你好!"
},
"en_US": {
"greetings.hello": "Hello, ${name}!"
}
}
}

View File

@ -0,0 +1,56 @@
import CodeGenerator from '../../src';
import * as fs from 'fs';
import * as path from 'path';
import { ProjectSchema } from '@alilc/lowcode-types';
import { createDiskPublisher } from '../helpers/solutionHelper';
import { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';
const testCaseBaseName = path.basename(__filename, '.test.ts');
const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);
const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);
jest.setTimeout(60 * 60 * 1000);
test('loop should be generated link __$$evalArray(xxx).map', async () => {
await exportProject(
inputSchemaJsonFile,
outputDir,
{},
{ inStrictMode: true, tolerateEvalErrors: true },
);
const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');
expect(generatedPageFileContent).toContain(
'{__$$evalArray(() => this.state.users).map((item, index) =>',
);
expect(generatedPageFileContent).toContain(
'{__$$evalArray(() => __$$context.state.messages).map(',
);
});
function exportProject(
importPath: string,
outputPath: string,
mergeSchema?: Partial<ProjectSchema>,
options?: IceJsProjectBuilderOptions,
) {
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };
const builder = CodeGenerator.solutions.icejs(options);
return builder.generateProject(schema).then(async (result) => {
const publisher = createDiskPublisher();
await publisher.publish({
project: result,
outputPath,
projectSlug: 'demo-project',
createProjectFolder: true,
});
return result;
});
}
function readOutputTextFile(outputFilePath: string): string {
return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');
}

View File

@ -1,6 +1,14 @@
import { run } from '../src/cli'; import { run } from '../src/cli';
describe('cli', () => { describe('cli', () => {
// standalone 模式下不需要测试 cli
if (process.env.TEST_TARGET === 'standalone') {
it('should ignore', () => {
expect(true).toBe(true);
});
return;
}
it('should works for the default example-schema.json', async () => { it('should works for the default example-schema.json', async () => {
const res = await run(['example-schema.json'], { const res = await run(['example-schema.json'], {
solution: 'icejs', solution: 'icejs',

Some files were not shown because too many files have changed in this diff Show More