Merge pull request #1698 from alibaba/feat/0228

feat: 出码引擎 1.0.8
This commit is contained in:
刘菊萍(絮黎) 2023-03-14 11:07:44 +08:00 committed by GitHub
commit 41753de24a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 412 additions and 171 deletions

View File

@ -15,7 +15,6 @@ module.exports = {
'no-prototype-builtins': 1, 'no-prototype-builtins': 1,
'no-useless-constructor': 1, 'no-useless-constructor': 1,
'no-empty-function': 1, 'no-empty-function': 1,
'@typescript-eslint/member-ordering': 0,
'lines-between-class-members': 0, 'lines-between-class-members': 0,
'no-await-in-loop': 0, 'no-await-in-loop': 0,
'no-plusplus': 0, 'no-plusplus': 0,
@ -35,23 +34,24 @@ module.exports = {
'@typescript-eslint/indent': 0, '@typescript-eslint/indent': 0,
'import/no-cycle': 0, 'import/no-cycle': 0,
'@typescript-eslint/no-shadow': 0, '@typescript-eslint/no-shadow': 0,
"@typescript-eslint/method-signature-style": 0, '@typescript-eslint/method-signature-style': 0,
"@typescript-eslint/consistent-type-assertions": 0, '@typescript-eslint/consistent-type-assertions': 0,
"@typescript-eslint/no-useless-constructor": 0, '@typescript-eslint/no-useless-constructor': 0,
'@typescript-eslint/dot-notation': 0, // for lint performance '@typescript-eslint/dot-notation': 0, // for lint performance
'@typescript-eslint/restrict-plus-operands': 0, // for lint performance '@typescript-eslint/restrict-plus-operands': 0, // for lint performance
'no-unexpected-multiline': 1, 'no-unexpected-multiline': 1,
'no-multiple-empty-lines': ['error', { "max": 1 }], 'no-multiple-empty-lines': ['error', { max: 1 }],
'lines-around-comment': ['error', { 'lines-around-comment': ['error', {
"beforeBlockComment": true, beforeBlockComment: true,
"afterBlockComment": false, afterBlockComment: false,
"afterLineComment": false, afterLineComment: false,
"allowBlockStart": true, allowBlockStart: true,
}], }],
"no-unused-vars": ['error', { "destructuredArrayIgnorePattern": "^_" }], 'comma-dangle': ['error', 'always-multiline'],
"@typescript-eslint/member-ordering": [ '@typescript-eslint/member-ordering': [
"error", 'error',
{ "default": ["signature", "field", "constructor", "method"] } { default: ['signature', 'field', 'constructor', 'method'] }
], ],
} 'no-unused-vars': ['error', { "destructuredArrayIgnorePattern": "^_" }]
},
}; };

View File

@ -71,7 +71,7 @@
}, },
"lifeCycles": { "lifeCycles": {
"componentDidMount": { "componentDidMount": {
"type": "JSExpression", "type": "JSFunction",
"value": "function() { console.log('componentDidMount'); }" "value": "function() { console.log('componentDidMount'); }"
} }
}, },
@ -91,7 +91,7 @@
"isSync": true "isSync": true
}, },
"dataHandler": { "dataHandler": {
"type": "JSExpression", "type": "JSFunction",
"value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}" "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}"
} }
}, },
@ -105,13 +105,13 @@
"isSync": true "isSync": true
}, },
"dataHandler": { "dataHandler": {
"type": "JSExpression", "type": "JSFunction",
"value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}" "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}"
} }
} }
], ],
"dataHandler": { "dataHandler": {
"type": "JSExpression", "type": "JSFunction",
"value": "function (dataMap) {\n console.info(\"All datasources loaded:\", dataMap);\n}" "value": "function (dataMap) {\n console.info(\"All datasources loaded:\", dataMap);\n}"
} }
}, },

View File

@ -71,7 +71,7 @@
}, },
lifeCycles: { lifeCycles: {
componentDidMount: { componentDidMount: {
type: 'JSExpression', type: 'JSFunction',
value: "function() { console.log('componentDidMount'); }", value: "function() { console.log('componentDidMount'); }",
}, },
}, },
@ -91,7 +91,7 @@
isSync: true, isSync: true,
}, },
dataHandler: { dataHandler: {
type: 'JSExpression', type: 'JSFunction',
value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}',
}, },
}, },
@ -105,13 +105,13 @@
isSync: true, isSync: true,
}, },
dataHandler: { dataHandler: {
type: 'JSExpression', type: 'JSFunction',
value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}',
}, },
}, },
], ],
dataHandler: { dataHandler: {
type: 'JSExpression', type: 'JSFunction',
value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}', value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}',
}, },
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-code-generator", "name": "@alilc/lowcode-code-generator",
"version": "1.0.7", "version": "1.0.8",
"description": "出码引擎 for LowCode Engine", "description": "出码引擎 for LowCode Engine",
"license": "MIT", "license": "MIT",
"main": "lib/index.js", "main": "lib/index.js",

View File

@ -8,5 +8,26 @@ export const CONTAINER_TYPE = {
export const SUPPORT_SCHEMA_VERSION_LIST = ['0.0.1', '1.0.0']; export const SUPPORT_SCHEMA_VERSION_LIST = ['0.0.1', '1.0.0'];
// built-in slot names which have been handled in ProjectBuilder
export const BUILTIN_SLOT_NAMES = [
'pages',
'components',
'router',
'entry',
'appConfig',
'buildConfig',
'constants',
'utils',
'i18n',
'globalStyle',
'htmlEntry',
'packageJSON',
'demo',
];
export const isBuiltinSlotName = function (name: string) {
return BUILTIN_SLOT_NAMES.includes(name);
};
export * from './file'; export * from './file';
export * from './generator'; export * from './generator';

View File

@ -62,10 +62,9 @@ export function createModuleBuilder(
if (options.postProcessors.length > 0) { if (options.postProcessors.length > 0) {
files = files.map((file) => { files = files.map((file) => {
let { content } = file; let { content, ext: type, name } = file;
const type = file.ext;
options.postProcessors.forEach((processer) => { options.postProcessors.forEach((processer) => {
content = processer(content, type); content = processer(content, type, name);
}); });
return createResultFile(file.name, type, content); return createResultFile(file.name, type, content);

View File

@ -16,6 +16,7 @@ import { createResultDir, addDirectory, addFile } from '../utils/resultHelper';
import { createModuleBuilder } from './ModuleBuilder'; import { createModuleBuilder } from './ModuleBuilder';
import { ProjectPreProcessor, ProjectPostProcessor, IContextData } from '../types/core'; import { ProjectPreProcessor, ProjectPostProcessor, IContextData } from '../types/core';
import { CodeGeneratorError } from '../types/error'; import { CodeGeneratorError } from '../types/error';
import { isBuiltinSlotName } from '../const';
interface IModuleInfo { interface IModuleInfo {
moduleName?: string; moduleName?: string;
@ -24,22 +25,31 @@ interface IModuleInfo {
} }
export interface ProjectBuilderInitOptions { export interface ProjectBuilderInitOptions {
/** 项目模板 */ /** 项目模板 */
template: IProjectTemplate; template: IProjectTemplate;
/** 项目插件 */ /** 项目插件 */
plugins: IProjectPlugins; plugins: IProjectPlugins;
/** 模块后置处理器 */ /** 模块后置处理器 */
postProcessors: PostProcessor[]; postProcessors: PostProcessor[];
/** Schema 解析器 */ /** Schema 解析器 */
schemaParser?: ISchemaParser; schemaParser?: ISchemaParser;
/** 项目级别的前置处理器 */ /** 项目级别的前置处理器 */
projectPreProcessors?: ProjectPreProcessor[]; projectPreProcessors?: ProjectPreProcessor[];
/** 项目级别的后置处理器 */ /** 项目级别的后置处理器 */
projectPostProcessors?: ProjectPostProcessor[]; projectPostProcessors?: ProjectPostProcessor[];
/** 是否处于严格模式 */ /** 是否处于严格模式 */
inStrictMode?: boolean; inStrictMode?: boolean;
/** 一些额外的上下文数据 */ /** 一些额外的上下文数据 */
extraContextData?: Record<string, unknown>; extraContextData?: Record<string, unknown>;
/** /**
* Hook which is used to customize original options, we can reorder/add/remove plugins/processors * Hook which is used to customize original options, we can reorder/add/remove plugins/processors
* of the existing solution. * of the existing solution.
@ -126,6 +136,7 @@ export class ProjectBuilder implements IProjectBuilder {
const builders = this.createModuleBuilders({ const builders = this.createModuleBuilders({
extraContextData: { extraContextData: {
projectRemark: parseResult?.project?.projectRemark, projectRemark: parseResult?.project?.projectRemark,
template: this.template,
}, },
}); });
// Generator Code module // Generator Code module
@ -263,7 +274,8 @@ export class ProjectBuilder implements IProjectBuilder {
}); });
} }
// TODO: 更多 slots 的处理??是不是可以考虑把 template 中所有的 slots 都处理下? // handle extra slots
await this.generateExtraSlots(builders, parseResult, buildResult);
// Post Process // Post Process
const isSingleComponent = parseResult?.project?.projectRemark?.isSingleComponent; const isSingleComponent = parseResult?.project?.projectRemark?.isSingleComponent;
@ -320,6 +332,22 @@ export class ProjectBuilder implements IProjectBuilder {
return builders; return builders;
} }
private async generateExtraSlots(
builders: Record<string, IModuleBuilder>,
parseResult: IParseResult,
buildResult: IModuleInfo[],
) {
for (const slotName in this.template.slots) {
if (!isBuiltinSlotName(slotName)) {
const { files } = await builders[slotName].generateModule(parseResult);
buildResult.push({
path: this.template.slots[slotName].path,
files,
});
}
}
}
} }
export function createProjectBuilder(initOptions: ProjectBuilderInitOptions): IProjectBuilder { export function createProjectBuilder(initOptions: ProjectBuilderInitOptions): IProjectBuilder {

View File

@ -1,6 +1,6 @@
/** /**
* Schema * Schema
* API , API * API API
* export { xxx } from 'xx' export * from 'xxx') * export { xxx } from 'xx' export * from 'xxx')
* API tests/public * API tests/public
*/ */
@ -51,6 +51,7 @@ export default {
}, },
plugins: { plugins: {
common: { common: {
/** /**
* ES Module * ES Module
* @deprecated please use esModule * @deprecated please use esModule

View File

@ -443,6 +443,7 @@ function buildPackageImport(
export interface PluginConfig { export interface PluginConfig {
fileType?: string; // 导出的文件类型 fileType?: string; // 导出的文件类型
useAliasName?: boolean; // 是否使用 componentName 重命名组件 identifier useAliasName?: boolean; // 是否使用 componentName 重命名组件 identifier
filter?: (deps: IDependency[]) => IDependency[]; // 支持过滤能力
} }
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?: PluginConfig) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?: PluginConfig) => {
@ -460,7 +461,8 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?: Plu
const ir = next.ir as IWithDependency; const ir = next.ir as IWithDependency;
if (ir && ir.deps && ir.deps.length > 0) { if (ir && ir.deps && ir.deps.length > 0) {
const packs = groupDepsByPack(ir.deps); const deps = cfg.filter ? cfg.filter(ir.deps) : ir.deps;
const packs = groupDepsByPack(deps);
Object.keys(packs).forEach((pkg) => { Object.keys(packs).forEach((pkg) => {
const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType, cfg.useAliasName); const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType, cfg.useAliasName);

View File

@ -13,6 +13,7 @@ import {
IContainerInfo, IContainerInfo,
} from '../../../types'; } from '../../../types';
import { debug } from '../../../utils/debug'; import { debug } from '../../../utils/debug';
import { isJSExpressionFn } from '../../../utils/common';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType: string;
@ -49,6 +50,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
// 过滤掉非法数据(有些场景下会误传入空字符串或 null) // 过滤掉非法数据(有些场景下会误传入空字符串或 null)
if ( if (
!isJSFunction(lifeCycles[lifeCycleName]) && !isJSFunction(lifeCycles[lifeCycleName]) &&
!isJSExpressionFn(lifeCycles[lifeCycleName]) &&
!isJSExpression(lifeCycles[lifeCycleName]) !isJSExpression(lifeCycles[lifeCycleName])
) { ) {
return; return;

View File

@ -75,8 +75,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
// 注意这里其实隐含了一个假设schema 中的 componentName 应该是一个有效的 JS 标识符,而且是大写字母打头的 // 注意这里其实隐含了一个假设schema 中的 componentName 应该是一个有效的 JS 标识符,而且是大写字母打头的
// FIXME: 为了快速修复临时加的逻辑,需要用 pre-process 的方式替代处理。 // FIXME: 为了快速修复临时加的逻辑,需要用 pre-process 的方式替代处理。
const mapComponentNameToAliasOrKeepIt = (componentName: string) => const mapComponentNameToAliasOrKeepIt = (componentName: string) => componentsNameAliasMap.get(componentName) || componentName;
componentsNameAliasMap.get(componentName) || componentName;
// 然后过滤掉所有的别名 chunks // 然后过滤掉所有的别名 chunks
next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk)); next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk));

View File

@ -26,7 +26,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
// 将模块名转换成 PascalCase 的格式,并添加特定后缀,防止命名冲突 // 将模块名转换成 PascalCase 的格式,并添加特定后缀,防止命名冲突
const componentClassName = ensureValidClassName( const componentClassName = ensureValidClassName(
`${changeCase.pascalCase(ir.moduleName)}$$Page`, `${changeCase.pascalCase(ir.moduleName)}$$${ir.containerType}`,
); );
next.chunks.push({ next.chunks.push({
@ -43,6 +43,18 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
], ],
}); });
if (ir.containerType === 'Component') {
next.chunks.push({
type: ChunkType.STRING,
fileType: FileType.JSX,
name: CLASS_DEFINE_CHUNK_NAME.InsVar,
content: `static displayName = '${changeCase.pascalCase(ir.moduleName)}';`,
linkAfter: [
CLASS_DEFINE_CHUNK_NAME.Start,
],
});
}
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: FileType.JSX, fileType: FileType.JSX,

View File

@ -13,12 +13,12 @@ import {
} from '../../../types'; } from '../../../types';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType?: string;
implementType: 'inConstructor' | 'insMember' | 'hooks'; implementType: 'inConstructor' | 'insMember' | 'hooks';
} }
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
const cfg: PluginConfig = { const cfg: PluginConfig & { fileType: string } = {
fileType: FileType.JSX, fileType: FileType.JSX,
implementType: 'inConstructor', implementType: 'inConstructor',
...config, ...config,

View File

@ -29,6 +29,7 @@ import { generateCompositeType } from '../../../utils/compositeType';
import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser';
import { isValidContainerType } from '../../../utils/schema'; import { isValidContainerType } from '../../../utils/schema';
import { REACT_CHUNK_NAME } from './const'; import { REACT_CHUNK_NAME } from './const';
import { isJSExpressionFn } from '../../../utils/common';
export interface PluginConfig { export interface PluginConfig {
fileType?: string; fileType?: string;
@ -37,6 +38,7 @@ export interface PluginConfig {
* *
*/ */
datasourceConfig?: { datasourceConfig?: {
/** 数据源引擎的版本 */ /** 数据源引擎的版本 */
engineVersion?: string; engineVersion?: string;
@ -188,15 +190,15 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
export default pluginFactory; export default pluginFactory;
function wrapAsFunction(value: IPublicTypeCompositeValue, scope: IScope): IPublicTypeCompositeValue { function wrapAsFunction(value: IPublicTypeCompositeValue, scope: IScope): IPublicTypeCompositeValue {
if (isJSExpression(value) || isJSFunction(value)) { if (isJSExpression(value) || isJSFunction(value) || isJSExpressionFn(value)) {
return { return {
type: 'JSExpression', type: 'JSExpression',
value: `function(){ return ((${value.value}))}`, value: `function(){ return ((${value.value}))}.bind(this)`,
}; };
} }
return { return {
type: 'JSExpression', type: 'JSExpression',
value: `function(){return((${generateCompositeType(value, scope)}))}`, value: `function(){return((${generateCompositeType(value, scope)}))}.bind(this)`,
}; };
} }

View File

@ -11,6 +11,7 @@ import {
FileType, FileType,
ICodeStruct, ICodeStruct,
} from '../../../types'; } from '../../../types';
import { getSlotRelativePath } from '../../../utils/pathHelper';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType: string;
@ -31,9 +32,8 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: COMMON_CHUNK_NAME.InternalDepsImport, name: COMMON_CHUNK_NAME.InternalDepsImport,
// TODO: 下面这个路径有没有更好的方式来获取?而非写死
content: ` content: `
import * as __$$i18n from '../../i18n'; import * as __$$i18n from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'i18n' })}';
`, `,
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
}); });

View File

@ -11,15 +11,18 @@ import {
FileType, FileType,
ICodeStruct, ICodeStruct,
IContainerInfo, IContainerInfo,
IProjectTemplate,
} from '../../../types'; } from '../../../types';
import { getSlotRelativePath } from '../../../utils/pathHelper';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType?: string;
/** prefer using class property to define utils */
preferClassProperty?: boolean;
} }
const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {
const cfg: PluginConfig = { const cfg: PluginConfig & { fileType: string } = {
fileType: FileType.JSX, fileType: FileType.JSX,
...config, ...config,
}; };
@ -33,37 +36,35 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
next.contextData.useRefApi = true; next.contextData.useRefApi = true;
const useRef = !!ir.analyzeResult?.isUsingRef; const useRef = !!ir.analyzeResult?.isUsingRef;
// const isSingleComponent = next.contextData?.projectRemark?.isSingleComponent;
// const template = next.contextData?.template;
// function getRelativeUtilsPath(template: IProjectTemplate, isSingleComponent: boolean) {
// let relativeUtilsPath = '../../utils';
// const utilsPath = template.slots.utils.path;
// if (ir.containerType === 'Component') {
// // TODO: isSingleComponent
// relativeUtilsPath = getRelativePath(template.slots.components.path.join('/'), utilsPath.join('/'));
// }
// return relativeUtilsPath;
// }
next.chunks.push({ next.chunks.push({
type: ChunkType.STRING, type: ChunkType.STRING,
fileType: cfg.fileType, fileType: cfg.fileType,
name: COMMON_CHUNK_NAME.InternalDepsImport, name: COMMON_CHUNK_NAME.InternalDepsImport,
// TODO: 下面这个路径有没有更好的方式来获取?而非写死
content: ` content: `
import utils${useRef ? ', { RefsManager }' : ''} from '../../utils'; import utils${useRef ? ', { RefsManager }' : ''} from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'utils' })}';
`, `,
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
}); });
next.chunks.push({ if (cfg.preferClassProperty) {
type: ChunkType.STRING, // mode: class property
fileType: cfg.fileType, next.chunks.push({
name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, type: ChunkType.STRING,
content: 'this.utils = utils;', fileType: cfg.fileType,
linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], name: CLASS_DEFINE_CHUNK_NAME.InsVar,
}); content: 'utils = utils;',
linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],
});
} else {
// mode: assign in constructor
next.chunks.push({
type: ChunkType.STRING,
fileType: cfg.fileType,
name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
content: 'this.utils = utils;',
linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],
});
}
if (useRef) { if (useRef) {
next.chunks.push({ next.chunks.push({

View File

@ -13,6 +13,7 @@ import {
IContainerInfo, IContainerInfo,
} from '../../../types'; } from '../../../types';
import { isJSFunction, isJSExpression } from '@alilc/lowcode-types'; import { isJSFunction, isJSExpression } from '@alilc/lowcode-types';
import { isJSExpressionFn } from '../../../utils/common';
export interface PluginConfig { export interface PluginConfig {
fileType: string; fileType: string;
@ -41,6 +42,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
// 过滤掉非法数据(有些场景下会误传入空字符串或 null) // 过滤掉非法数据(有些场景下会误传入空字符串或 null)
if ( if (
!isJSFunction(lifeCycles[lifeCycleName]) && !isJSFunction(lifeCycles[lifeCycleName]) &&
!isJSExpressionFn(lifeCycles[lifeCycleName]) &&
!isJSExpression(lifeCycles[lifeCycleName]) !isJSExpression(lifeCycles[lifeCycleName])
) { ) {
return null; return null;

View File

@ -22,6 +22,8 @@ const factory: PostProcessorFactory<ProcessorConfig> = (config?: ProcessorConfig
let parser: prettier.BuiltInParserName | any; let parser: prettier.BuiltInParserName | any;
if (fileType === 'js' || fileType === 'jsx') { if (fileType === 'js' || fileType === 'jsx') {
parser = 'babel'; parser = 'babel';
} else if (fileType === 'json') {
parser = 'json-stringify';
} else if (PARSERS.indexOf(fileType) >= 0) { } else if (PARSERS.indexOf(fileType) >= 0) {
parser = fileType; parser = fileType;
} else if (cfg.customFileTypeParser[fileType]) { } else if (cfg.customFileTypeParser[fileType]) {

View File

@ -1,20 +1,15 @@
import { import {
IPublicTypeJSONArray,
IPublicTypeJSONObject,
IPublicTypeCompositeArray, IPublicTypeCompositeArray,
IPublicTypeCompositeObject, IPublicTypeCompositeObject, IPublicTypeJSExpression,
ResultDir, IPublicTypeJSFunction, IPublicTypeJSONArray,
IPublicTypeJSONObject, IPublicTypeJSSlot, IPublicTypeNodeDataType,
IPublicTypeProjectSchema, ResultDir,
ResultFile, ResultFile,
IPublicTypeNodeDataType,
IPublicTypeProjectSchema,
IPublicTypeJSExpression,
IPublicTypeJSFunction,
IPublicTypeJSSlot,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { IParseResult } from './intermediate';
import { IScopeBindings } from '../utils/ScopeBindings';
import type { ProjectBuilderInitOptions } from '../generator/ProjectBuilder'; import type { ProjectBuilderInitOptions } from '../generator/ProjectBuilder';
import { IScopeBindings } from '../utils/ScopeBindings';
import { IParseResult } from './intermediate';
export enum FileType { export enum FileType {
CSS = 'css', CSS = 'css',
@ -22,8 +17,10 @@ export enum FileType {
LESS = 'less', LESS = 'less',
HTML = 'html', HTML = 'html',
JS = 'js', JS = 'js',
MJS = 'mjs',
JSX = 'jsx', JSX = 'jsx',
TS = 'ts', TS = 'ts',
MTS = 'mts',
TSX = 'tsx', TSX = 'tsx',
JSON = 'json', JSON = 'json',
MD = 'md', MD = 'md',
@ -67,16 +64,16 @@ export interface ICodeStruct extends IBaseCodeStruct {
/** 上下文数据,用来在插件之间共享一些数据 */ /** 上下文数据,用来在插件之间共享一些数据 */
export interface IContextData extends IProjectBuilderOptions { export interface IContextData extends IProjectBuilderOptions {
/**
* 使 Ref API (this.$/this.$$)
* */
useRefApi?: boolean;
/** /**
* *
* *
*/ */
[key: string]: any; [key: string]: any;
/**
* 使 Ref API (this.$/this.$$)
* */
useRefApi?: boolean;
} }
export type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise<ICodeStruct>; export type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise<ICodeStruct>;
@ -168,6 +165,7 @@ export interface IProjectBuilderOptions {
* - expr: 求值的表达式 * - expr: 求值的表达式
*/ */
evalErrorsHandler?: string; evalErrorsHandler?: string;
/** /**
* Hook which is used to customize original options, we can reorder/add/remove plugins/processors * Hook which is used to customize original options, we can reorder/add/remove plugins/processors
* of the existing solution. * of the existing solution.
@ -180,7 +178,8 @@ export interface IProjectBuilder {
} }
/** 项目级别的前置处理器 */ /** 项目级别的前置处理器 */
export type ProjectPreProcessor = (schema: IPublicTypeProjectSchema) => Promise<IPublicTypeProjectSchema> | IPublicTypeProjectSchema; export type ProjectPreProcessor = (schema: IPublicTypeProjectSchema) =>
Promise<IPublicTypeProjectSchema> | IPublicTypeProjectSchema;
export interface ProjectPostProcessorOptions { export interface ProjectPostProcessorOptions {
parseResult?: IParseResult; parseResult?: IParseResult;
@ -199,7 +198,7 @@ export type ProjectPostProcessor = (
export type PostProcessorFactory<T> = (config?: T) => PostProcessor; export type PostProcessorFactory<T> = (config?: T) => PostProcessor;
/** 模块级别的后置处理器 */ /** 模块级别的后置处理器 */
export type PostProcessor = (content: string, fileType: string) => string; export type PostProcessor = (content: string, fileType: string, name?: string) => string;
// TODO: temp interface, need modify // TODO: temp interface, need modify
export interface IPluginOptions { export interface IPluginOptions {

View File

@ -35,4 +35,4 @@ export interface IDependency {
main?: string; // 包导出组件入口文件路径 /lib/input main?: string; // 包导出组件入口文件路径 /lib/input
dependencyType?: DependencyType; // 依赖类型 内/外 dependencyType?: DependencyType; // 依赖类型 内/外
componentName?: string; // 导入后名称 componentName?: string; // 导入后名称
} }

View File

@ -42,6 +42,7 @@ export interface IRouterInfo extends IWithDependency {
* project's remarks * project's remarks
*/ */
export interface ProjectRemark { export interface ProjectRemark {
/** if current project only contain one container which type is `Component` */ /** if current project only contain one container which type is `Component` */
isSingleComponent?: boolean; isSingleComponent?: boolean;
} }

View File

@ -1,5 +1,7 @@
import type { IPublicTypeJSExpression, IPublicTypeJSFunction } from '@alilc/lowcode-types';
import changeCase from 'change-case'; import changeCase from 'change-case';
import short from 'short-uuid'; import short from 'short-uuid';
import { DependencyType, IDependency, IExternalDependency, IInternalDependency } from '../types';
// Doc: https://www.npmjs.com/package/change-case // Doc: https://www.npmjs.com/package/change-case
@ -39,3 +41,19 @@ export function getStaticExprValue<T>(expr: string): T {
// eslint-disable-next-line no-new-func // eslint-disable-next-line no-new-func
return Function(`"use strict";return (${expr})`)(); return Function(`"use strict";return (${expr})`)();
} }
export function isJSExpressionFn(data: any): data is IPublicTypeJSFunction {
return data?.type === 'JSExpression' && data?.extType === 'function';
}
export function isInternalDependency(
dependency: IDependency,
): dependency is IInternalDependency {
return dependency.dependencyType === DependencyType.Internal;
}
export function isExternalDependency(
dependency: IDependency,
): dependency is IExternalDependency {
return dependency.dependencyType === DependencyType.External;
}

View File

@ -16,6 +16,7 @@ import { generateExpression, generateFunction } from './jsExpression';
import { generateJsSlot } from './jsSlot'; import { generateJsSlot } from './jsSlot';
import { executeFunctionStack } from './aopHelper'; import { executeFunctionStack } from './aopHelper';
import { parseExpressionGetKeywords } from './expressionParser'; import { parseExpressionGetKeywords } from './expressionParser';
import { isJSExpressionFn } from './common';
interface ILegaoVariable { interface ILegaoVariable {
type: 'variable'; type: 'variable';
@ -159,7 +160,7 @@ function generateUnknownType(
return generateExpression(value, scope); return generateExpression(value, scope);
} }
if (isJSFunction(value)) { if (isJSFunction(value) || isJSExpressionFn(value)) {
if (options.handlers?.function) { if (options.handlers?.function) {
return executeFunctionStack(value, scope, options.handlers.function, genFunction, options); return executeFunctionStack(value, scope, options.handlers.function, genFunction, options);
} }

View File

@ -2,14 +2,18 @@ import changeCase from 'change-case';
import type { IProjectInfo } from '../types/intermediate'; import type { IProjectInfo } from '../types/intermediate';
export interface DataSourceDependenciesConfig { export interface DataSourceDependenciesConfig {
/** 数据源引擎的版本 */ /** 数据源引擎的版本 */
engineVersion?: string; engineVersion?: string;
/** 数据源引擎的包名 */ /** 数据源引擎的包名 */
enginePackage?: string; enginePackage?: string;
/** 数据源 handlers 的版本 */ /** 数据源 handlers 的版本 */
handlersVersion?: { handlersVersion?: {
[key: string]: string; [key: string]: string;
}; };
/** 数据源 handlers 的包名 */ /** 数据源 handlers 的包名 */
handlersPackages?: { handlersPackages?: {
[key: string]: string; [key: string]: string;

View File

@ -12,6 +12,7 @@ import * as version from './version';
import * as scope from './Scope'; import * as scope from './Scope';
import * as expressionParser from './expressionParser'; import * as expressionParser from './expressionParser';
import * as dataSource from './dataSource'; import * as dataSource from './dataSource';
import * as pathHelper from './pathHelper';
export { export {
common, common,
@ -27,4 +28,5 @@ export {
scope, scope,
expressionParser, expressionParser,
dataSource, dataSource,
pathHelper,
}; };

View File

@ -5,6 +5,7 @@ import * as t from '@babel/types';
import { IPublicTypeJSExpression, IPublicTypeJSFunction, isJSExpression, isJSFunction } from '@alilc/lowcode-types'; import { IPublicTypeJSExpression, IPublicTypeJSFunction, isJSExpression, isJSFunction } from '@alilc/lowcode-types';
import { CodeGeneratorError, IScope } from '../types'; import { CodeGeneratorError, IScope } from '../types';
import { transformExpressionLocalRef, ParseError } from './expressionParser'; import { transformExpressionLocalRef, ParseError } from './expressionParser';
import { isJSExpressionFn } from './common';
function parseFunction(content: string): t.FunctionExpression | null { function parseFunction(content: string): t.FunctionExpression | null {
try { try {
@ -78,8 +79,13 @@ function getBodyStatements(content: string) {
throw new Error('Can not find Function Statement'); throw new Error('Can not find Function Statement');
} }
export function isJsCode(value: unknown): boolean { /**
return isJSExpression(value) || isJSFunction(value); * 广 JSFunction
* @param value
* @returns
*/
export function isBroadJSFunction(value: unknown): boolean {
return isJSExpressionFn(value) || isJSFunction(value);
} }
export function generateExpression(value: any, scope: IScope): string { export function generateExpression(value: any, scope: IScope): string {
@ -96,6 +102,10 @@ export function generateExpression(value: any, scope: IScope): string {
throw new CodeGeneratorError('Not a JSExpression'); throw new CodeGeneratorError('Not a JSExpression');
} }
function getFunctionSource(cfg: IPublicTypeJSFunction): string {
return cfg.source || cfg.value || cfg.compiled;
}
export function generateFunction( export function generateFunction(
value: any, value: any,
config: { config: {
@ -112,21 +122,26 @@ export function generateFunction(
isBindExpr: false, isBindExpr: false,
}, },
) { ) {
if (isJsCode(value)) { if (isBroadJSFunction(value)) {
const functionCfg = value as IPublicTypeJSFunction; const functionCfg = value as IPublicTypeJSFunction;
const functionSource = getFunctionSource(functionCfg);
if (config.isMember) { if (config.isMember) {
return transformFuncExpr2MethodMember(config.name || '', functionCfg.value); return transformFuncExpr2MethodMember(config.name || '', functionSource);
} }
if (config.isBlock) { if (config.isBlock) {
return getBodyStatements(functionCfg.value); return getBodyStatements(functionSource);
} }
if (config.isArrow) { if (config.isArrow) {
return getArrowFunction(functionCfg.value); return getArrowFunction(functionSource);
} }
if (config.isBindExpr) { if (config.isBindExpr) {
return `(${functionCfg.value}).bind(this)`; return `(${functionSource}).bind(this)`;
} }
return functionCfg.value; return functionSource;
}
if (isJSExpression(value)) {
return value.value;
} }
throw new CodeGeneratorError('Not a JSFunction or JSExpression'); throw new CodeGeneratorError('Not a JSFunction or JSExpression');

View File

@ -126,7 +126,7 @@ function generateAttrs(
if (props) { if (props) {
if (!Array.isArray(props)) { if (!Array.isArray(props)) {
Object.keys(props).forEach((propName: string) => { Object.keys(props).forEach((propName: string) => {
pieces = pieces.concat(generateAttr(propName, props[propName], scope, config)); pieces = pieces.concat(generateAttr(propName, props[propName] as IPublicTypeCompositeValue, scope, config));
}); });
} else { } else {
props.forEach((prop) => { props.forEach((prop) => {

View File

@ -0,0 +1,41 @@
import { IContextData } from '../types';
function relativePath(from: string[], to: string[]): string[] {
const length = Math.min(from.length, to.length);
let samePartsLength = length;
for (let i = 0; i < length; i++) {
if (from[i] !== to[i]) {
samePartsLength = i;
break;
}
}
if (samePartsLength === 0) {
return to;
}
let outputParts = [];
for (let i = samePartsLength; i < from.length; i++) {
outputParts.push('..');
}
outputParts = [...outputParts, ...to.slice(samePartsLength)];
if (outputParts[0] !== '..') {
outputParts.unshift('.');
}
return outputParts;
}
export function getSlotRelativePath(options: {
contextData: IContextData;
from: string;
to: string;
}) {
const { contextData, from, to } = options;
const isSingleComponent = contextData?.extraContextData?.projectRemark?.isSingleComponent;
const template = contextData?.extraContextData?.template;
let toPath = template.slots[to].path;
toPath = [...toPath, template.slots[to].fileName!];
let fromPath = template.slots[from].path;
if (!isSingleComponent && ['components', 'pages'].indexOf(from) !== -1) {
fromPath = [...fromPath, 'pageName'];
}
return relativePath(fromPath, toPath).join('/');
}

View File

@ -13,6 +13,7 @@ import {
isJSFunction, isJSFunction,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { CodeGeneratorError } from '../types/error'; import { CodeGeneratorError } from '../types/error';
import { isJSExpressionFn } from './common';
export function isContainerSchema(x: any): x is IPublicTypeContainerSchema { export function isContainerSchema(x: any): x is IPublicTypeContainerSchema {
return ( return (
@ -100,7 +101,7 @@ export function handleSubNodes<T>(
}); });
} else { } else {
Object.values(child.props).forEach((value) => { Object.values(child.props).forEach((value) => {
const childRes = handleCompositeValueInProps(value); const childRes = handleCompositeValueInProps(value as IPublicTypeCompositeValue);
childrenRes.push(...childRes); childrenRes.push(...childRes);
}); });
} }
@ -128,6 +129,7 @@ export function handleSubNodes<T>(
// IPublicTypeCompositeObject // IPublicTypeCompositeObject
if ( if (
!isJSExpression(value) && !isJSExpression(value) &&
!isJSExpressionFn(value) &&
!isJSFunction(value) && !isJSFunction(value) &&
typeof value === 'object' && typeof value === 'object' &&
value !== null value !== null

View File

@ -253,7 +253,6 @@ class Home$$Page extends Component {
if (!response.success) { if (!response.success) {
throw new Error(response.message); throw new Error(response.message);
} }
return response.data; return response.data;
}, },
isInit: true, isInit: true,
@ -280,7 +279,6 @@ class Home$$Page extends Component {
if (!response.success) { if (!response.success) {
throw new Error(response.message); throw new Error(response.message);
} }
return response.data.result; return response.data.result;
}, },
isInit: true, isInit: true,

View File

@ -31,9 +31,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -71,10 +71,10 @@ class Test$$Page extends React.Component {
type: 'urlParams', type: 'urlParams',
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
options: function () { options: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
{ {
id: 'user', id: 'user',
@ -85,17 +85,16 @@ class Test$$Page extends React.Component {
uri: 'https://shs.xxx.com/mock/1458/demo/user', uri: 'https://shs.xxx.com/mock/1458/demo/user',
isSync: true, isSync: true,
}; };
}, }.bind(_this),
dataHandler: function (response) { dataHandler: function (response) {
if (!response.data.success) { if (!response.data.success) {
throw new Error(response.data.message); throw new Error(response.data.message);
} }
return response.data.data; return response.data.data;
}, },
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
{ {
id: 'orders', id: 'orders',
@ -106,17 +105,16 @@ class Test$$Page extends React.Component {
uri: 'https://shs.xxx.com/mock/1458/demo/orders', uri: 'https://shs.xxx.com/mock/1458/demo/orders',
isSync: true, isSync: true,
}; };
}, }.bind(_this),
dataHandler: function (response) { dataHandler: function (response) {
if (!response.data.success) { if (!response.data.success) {
throw new Error(response.data.message); throw new Error(response.data.message);
} }
return response.data.data.result; return response.data.data.result;
}, },
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
], ],
dataHandler: function (dataMap) { dataHandler: function (dataMap) {

View File

@ -71,7 +71,7 @@
}, },
"lifeCycles": { "lifeCycles": {
"componentDidMount": { "componentDidMount": {
"type": "JSExpression", "type": "JSFunction",
"value": "function() { console.log('componentDidMount'); }" "value": "function() { console.log('componentDidMount'); }"
} }
}, },

View File

@ -34,9 +34,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -67,10 +67,10 @@ class Aaaa$$Page extends React.Component {
return { return {
uri: '', uri: '',
}; };
}, }.bind(_this),
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
], ],
}; };

View File

@ -29,9 +29,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -71,7 +71,7 @@
}, },
"lifeCycles": { "lifeCycles": {
"componentDidMount": { "componentDidMount": {
"type": "JSExpression", "type": "JSFunction",
"value": "function() { console.log('componentDidMount'); }" "value": "function() { console.log('componentDidMount'); }"
} }
}, },

View File

@ -29,9 +29,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -31,9 +31,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -76,7 +76,7 @@ class Test$$Page extends React.Component {
type: 'fetch', type: 'fetch',
isInit: function () { isInit: function () {
return true; return true;
}, }.bind(_this),
options: function () { options: function () {
return { return {
params: {}, params: {},
@ -86,7 +86,7 @@ class Test$$Page extends React.Component {
headers: {}, headers: {},
uri: 'https://mocks.xxx.com/mock/jjpin/user/list', uri: 'https://mocks.xxx.com/mock/jjpin/user/list',
}; };
}, }.bind(_this),
id: 'users', id: 'users',
}, },
], ],

View File

@ -32,9 +32,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -31,9 +31,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -71,10 +71,10 @@ class Test$$Page extends React.Component {
type: 'urlParams', type: 'urlParams',
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
options: function () { options: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
{ {
id: 'user', id: 'user',
@ -85,17 +85,16 @@ class Test$$Page extends React.Component {
uri: 'https://shs.xxx.com/mock/1458/demo/user', uri: 'https://shs.xxx.com/mock/1458/demo/user',
isSync: true, isSync: true,
}; };
}, }.bind(_this),
dataHandler: function (response) { dataHandler: function (response) {
if (!response.data.success) { if (!response.data.success) {
throw new Error(response.data.message); throw new Error(response.data.message);
} }
return response.data.data; return response.data.data;
}, },
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
{ {
id: 'orders', id: 'orders',
@ -106,17 +105,16 @@ class Test$$Page extends React.Component {
uri: 'https://shs.xxx.com/mock/1458/demo/orders', uri: 'https://shs.xxx.com/mock/1458/demo/orders',
isSync: true, isSync: true,
}; };
}, }.bind(_this),
dataHandler: function (response) { dataHandler: function (response) {
if (!response.data.success) { if (!response.data.success) {
throw new Error(response.data.message); throw new Error(response.data.message);
} }
return response.data.data.result; return response.data.data.result;
}, },
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
], ],
dataHandler: function (dataMap) { dataHandler: function (dataMap) {

View File

@ -71,7 +71,7 @@
}, },
lifeCycles: { lifeCycles: {
componentDidMount: { componentDidMount: {
type: 'JSExpression', type: 'JSFunction',
value: "function() { console.log('componentDidMount'); }", value: "function() { console.log('componentDidMount'); }",
}, },
}, },
@ -91,7 +91,7 @@
isSync: true, isSync: true,
}, },
dataHandler: { dataHandler: {
type: 'JSExpression', type: 'JSFunction',
value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}',
}, },
}, },
@ -105,13 +105,13 @@
isSync: true, isSync: true,
}, },
dataHandler: { dataHandler: {
type: 'JSExpression', type: 'JSFunction',
value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}',
}, },
}, },
], ],
dataHandler: { dataHandler: {
type: 'JSExpression', type: 'JSFunction',
value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}', value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}',
}, },
}, },

View File

@ -31,9 +31,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -151,6 +151,7 @@ class Test$$Page extends React.Component {
onOkModifyDialogThird() { onOkModifyDialogThird() {
// //
this.setState({ this.setState({
currentStep: 0, currentStep: 0,
isModifyDialogVisible: false, isModifyDialogVisible: false,
@ -159,6 +160,7 @@ class Test$$Page extends React.Component {
onCancelModifyDialogThird() { onCancelModifyDialogThird() {
// //
this.setState({ this.setState({
isModifyDialogVisible: false, isModifyDialogVisible: false,
}); });

View File

@ -30,9 +30,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -63,10 +63,10 @@ class Example$$Page extends React.Component {
return { return {
uri: 'https://api.example.com/user/list', uri: 'https://api.example.com/user/list',
}; };
}, }.bind(_this),
isInit: function () { isInit: function () {
return undefined; return undefined;
}, }.bind(_this),
}, },
], ],
}; };

View File

@ -30,9 +30,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -59,14 +59,14 @@ class $$Page extends React.Component {
id: 'todos', id: 'todos',
isInit: function () { isInit: function () {
return true; return true;
}, }.bind(_this),
type: 'jsonp', type: 'jsonp',
options: function () { options: function () {
return { return {
method: 'GET', method: 'GET',
uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io', uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io',
}; };
}, }.bind(_this),
dataHandler: function dataHandler(data) { dataHandler: function dataHandler(data) {
return data.data; return data.data;
}, },

View File

@ -32,9 +32,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -65,7 +65,6 @@ class Test$$Page extends React.Component {
}; };
this.__jp__init(); this.__jp__init();
this.statusDesc = { this.statusDesc = {
0: '失败', 0: '失败',
1: '成功', 1: '成功',
@ -163,7 +162,6 @@ class Test$$Page extends React.Component {
if (!item) { if (!item) {
return '暂无结果'; return '暂无结果';
} }
const { channel, plat, version, status } = item; const { channel, plat, version, status } = item;
return [channel, plat, version, status].join('-'); return [channel, plat, version, status].join('-');
} }

View File

@ -32,9 +32,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -67,7 +67,6 @@ class Test$$Page extends React.Component {
}; };
this.__jp__init(); this.__jp__init();
this.statusDesc = { this.statusDesc = {
0: '失败', 0: '失败',
1: '成功', 1: '成功',
@ -202,12 +201,10 @@ class Test$$Page extends React.Component {
componentDidMount() { componentDidMount() {
this.$ds.resolve('PROJECTS'); this.$ds.resolve('PROJECTS');
if (this.userTimeout) { if (this.userTimeout) {
clearTimeout(this.userTimeout); clearTimeout(this.userTimeout);
this.userTimeout = null; this.userTimeout = null;
} }
if (this.projectTimeout) { if (this.projectTimeout) {
clearTimeout(this.projectTimeout); clearTimeout(this.projectTimeout);
this.projectTimeout = null; this.projectTimeout = null;

View File

@ -25,9 +25,16 @@
"eslint": "eslint --cache --ext .js,.jsx ./", "eslint": "eslint --cache --ext .js,.jsx ./",
"stylelint": "stylelint ./**/*.scss" "stylelint": "stylelint ./**/*.scss"
}, },
"ideMode": { "name": "ice-react" }, "ideMode": {
"iceworks": { "type": "react", "adapter": "adapter-react-v3" }, "name": "ice-react"
"engines": { "node": ">=8.0.0" }, },
"iceworks": {
"type": "react",
"adapter": "adapter-react-v3"
},
"engines": {
"node": ">=8.0.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"

View File

@ -19,7 +19,12 @@ export function App() {
`; `;
exports[`postprocessor/prettier should works for json file 1`] = ` exports[`postprocessor/prettier should works for json file 1`] = `
"{ \\"components\\": [\\"Button\\", \\"Block\\"] } "{
\\"components\\": [
\\"Button\\",
\\"Block\\"
]
}
" "
`; `;