chore: fix code style conflicts

This commit is contained in:
力皓 2020-09-14 15:21:56 +08:00
commit 9cf809436e
82 changed files with 1407 additions and 14446 deletions

View File

@ -2,6 +2,7 @@
node_modules node_modules
build build
dist dist
demo
es es
lib lib
.* .*

2
.vscode/launch.json vendored
View File

@ -9,7 +9,7 @@
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"runtimeExecutable": "${workspaceFolder}/packages/material-parser/node_modules/.bin/ava", "runtimeExecutable": "${workspaceFolder}/packages/material-parser/node_modules/.bin/ava",
"runtimeArgs": ["debug", "--break", "${file}"] "runtimeArgs": ["debug", "--break", "${workspaceFolder}/packages/material-parser/test/antd.ts"]
} }
] ]
} }

View File

@ -7,6 +7,10 @@ import { GenerateProjectDto } from '../dto/generate-project.dto';
export class ApiController { export class ApiController {
private readonly apiService: ApiService; private readonly apiService: ApiService;
constructor(apiService: ApiService) {
this.apiService = apiService;
}
@Get('generate/test') @Get('generate/test')
generateTest() { generateTest() {
return 'generate test'; return 'generate test';

View File

@ -5,6 +5,10 @@ import { AppService } from './app.service';
export class AppController { export class AppController {
private readonly appService: AppService; private readonly appService: AppService;
constructor(appService: AppService) {
this.appService = appService;
}
@Get() @Get()
getHello(): string { getHello(): string {
return this.appService.getHello(); return this.appService.getHello();

View File

@ -1,7 +1,7 @@
module.exports = { module.exports = {
extends: 'eslint-config-ali/typescript/react', extends: 'eslint-config-ali/typescript/react',
rules: { rules: {
'react/no-multi-comp': 1, 'react/no-multi-comp': 0,
'no-unused-expressions': 1, 'no-unused-expressions': 1,
'implicit-arrow-linebreak': 1, 'implicit-arrow-linebreak': 1,
'no-nested-ternary': 1, 'no-nested-ternary': 1,

View File

@ -38,7 +38,6 @@ export class BorderDetectingInstance extends PureComponent<{
} }
@observer @observer
// eslint-disable-next-line react/no-multi-comp
export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
shouldComponentUpdate() { shouldComponentUpdate() {
return false; return false;

View File

@ -58,7 +58,6 @@ export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost
} }
@observer @observer
// eslint-disable-next-line react/no-multi-comp
export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> { export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {
static contextType = SimulatorContext; static contextType = SimulatorContext;
@ -106,7 +105,6 @@ export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost;
} }
@observer @observer
// eslint-disable-next-line react/no-multi-comp
export class BoxResizingInstance extends Component<{ export class BoxResizingInstance extends Component<{
observed: OffsetObserver; observed: OffsetObserver;
highlight?: boolean; highlight?: boolean;

View File

@ -55,7 +55,6 @@ export class BorderSelectingInstance extends Component<{
} }
@observer @observer
// eslint-disable-next-line react/no-multi-comp
class Toolbar extends Component<{ observed: OffsetObserver }> { class Toolbar extends Component<{ observed: OffsetObserver }> {
shouldComponentUpdate() { shouldComponentUpdate() {
return false; return false;
@ -151,7 +150,6 @@ function createAction(content: ReactNode | ComponentType<any> | ActionContentObj
} }
@observer @observer
// eslint-disable-next-line react/no-multi-comp
export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> { export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {
get host(): BuiltinSimulatorHost { get host(): BuiltinSimulatorHost {
return this.props.host; return this.props.host;
@ -195,7 +193,6 @@ export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHo
} }
@observer @observer
// eslint-disable-next-line react/no-multi-comp
export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> { export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> {
get host(): BuiltinSimulatorHost { get host(): BuiltinSimulatorHost {
return this.props.host; return this.props.host;

View File

@ -49,7 +49,6 @@ export class BuiltinSimulatorHostView extends Component<SimulatorHostProps> {
} }
} }
// eslint-disable-next-line react/no-multi-comp
@observer @observer
class Canvas extends Component<{ host: BuiltinSimulatorHost }> { class Canvas extends Component<{ host: BuiltinSimulatorHost }> {
render() { render() {
@ -72,7 +71,6 @@ class Canvas extends Component<{ host: BuiltinSimulatorHost }> {
} }
} }
// eslint-disable-next-line react/no-multi-comp
@observer @observer
class Content extends Component<{ host: BuiltinSimulatorHost }> { class Content extends Component<{ host: BuiltinSimulatorHost }> {
render() { render() {

View File

@ -10,5 +10,11 @@ module.exports = {
'@typescript-eslint/ban-types': 1, '@typescript-eslint/ban-types': 1,
'no-shadow': 1, 'no-shadow': 1,
'no-prototype-builtins': 1, 'no-prototype-builtins': 1,
'@typescript-eslint/no-unused-vars': 1,
'no-multi-assign': 1,
'no-dupe-class-members': 1,
'react/no-deprecated': 1,
'no-useless-escape': 1,
'brace-style': 1,
} }
} }

View File

@ -68,12 +68,13 @@ export default class ExpressionView extends PureComponent {
return val; return val;
} }
constructor(props: Readonly) { constructor(props: Readonly<{}>) {
super(props); super(props);
this.expression = React.createRef(); this.expression = React.createRef();
this.i18n = generateI18n(props.locale, props.messages); this.i18n = generateI18n(props.locale, props.messages);
this.state = { this.state = {
value: ExpressionView.getInitValue(props.value), value: ExpressionView.getInitValue(props.value),
context: props.context || {},
dataSource: props.dataSource || [], dataSource: props.dataSource || [],
}; };
} }
@ -126,23 +127,32 @@ export default class ExpressionView extends PureComponent {
* @return {Array} * @return {Array}
*/ */
getDataSource(tempStr: string): any[] { getDataSource(tempStr: string): any[] {
// eslint-disable-next-line no-useless-escape const {editor} = this.props.field;
if (/[^\w\.]$/.test(tempStr)) { const schema = editor.get('designer').project.getSchema();
return []; const stateMap = schema.componentsTree[0].state;
} else if (tempStr === null || tempStr === '') { let dataSource = [];
return this.getContextKeys([]);
} else if (/\w\.$/.test(tempStr)) { for (let key in stateMap){
const currentField = this.getCurrentFiled(tempStr); dataSource.push(`this.state.${key}`);
if (!currentField) return null;
let tempKeys = this.getObjectKeys(currentField.str);
tempKeys = this.getContextKeys(tempKeys);
if (!tempKeys) return null;
return tempKeys;
} else if (/\.$/.test(tempStr)) {
return [];
} else {
return null;
} }
// if (/[^\w\.]$/.test(tempStr)) {
// return [];
// } else if (tempStr === null || tempStr === '') {
// return this.getContextKeys([]);
// } else if (/\w\.$/.test(tempStr)) {
// const currentField = this.getCurrentFiled(tempStr);
// if (!currentField) return null;
// let tempKeys = this.getObjectKeys(currentField.str);
// tempKeys = this.getContextKeys(tempKeys);
// if (!tempKeys) return null;
// return tempKeys;
// } else if (/\.$/.test(tempStr)) {
// return [];
// } else {
// return null;
// }
return dataSource;
} }
/** /**

View File

@ -0,0 +1,2 @@
test/fixtures/**
lib/**

View File

@ -0,0 +1,3 @@
module.exports = {
extends: 'eslint-config-ali/typescript/react',
};

View File

@ -12,3 +12,5 @@
cd demo cd demo
node index.js node index.js
``` ```
## API

View File

@ -1,3 +1,4 @@
/* eslint-disable react/forbid-prop-types,react/no-unused-prop-types */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -37,7 +38,11 @@ Demo.propTypes = {
optionalEnum: PropTypes.oneOf(['News', 'Photos']), optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// An object that could be one of many types // An object that could be one of many types
optionalUnion: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Demo)]), optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Demo),
]),
// An array of a certain type // An array of a certain type
optionalArrayOf: PropTypes.arrayOf(PropTypes.number), optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

View File

@ -63,6 +63,7 @@
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react-docgen": "^5.3.0", "react-docgen": "^5.3.0",
"react-docgen-typescript": "^1.16.5", "react-docgen-typescript": "^1.16.5",
"safe-eval": "^0.4.1",
"semver": "^7.1.3", "semver": "^7.1.3",
"short-uuid": "^3.1.1", "short-uuid": "^3.1.1",
"typescript": "^3.9.5", "typescript": "^3.9.5",

View File

@ -5,6 +5,6 @@ export * from './schema/types';
/** /**
* Dev helper * Dev helper
*/ */
export const debug = _debug('lowcode'); export const debug = _debug('lowcode:mat');
export const enableDebug = () => _debug.enable('lowcode:*'); export const enableDebug = () => _debug.enable('lowcode:*');
export const disableDebug = () => _debug.disable(); export const disableDebug = () => _debug.disable();

View File

@ -80,7 +80,7 @@ export interface ObjectOf {
[k: string]: any; [k: string]: any;
} }
export interface Shape { export interface Shape {
type: "shape"; type: 'shape';
value: { value: {
name?: string; name?: string;
propType?: PropType; propType?: PropType;
@ -89,7 +89,7 @@ export interface Shape {
[k: string]: any; [k: string]: any;
} }
export interface Exact { export interface Exact {
type: "exact"; type: 'exact';
value: { value: {
name?: string; name?: string;
propType?: PropType; propType?: PropType;

View File

@ -1,7 +1,7 @@
import { debug, ComponentMeta } from './core'; import { debug, ComponentMeta } from './core';
import { IMaterialParsedModel, IMaterialScanModel } from './types'; import { IMaterialParsedModel, IMaterialScanModel } from './types';
const log = debug.extend('mat'); const log = debug.extend('gen');
export default async function ( export default async function (
matScanModel: IMaterialScanModel, matScanModel: IMaterialScanModel,
@ -41,6 +41,7 @@ export async function genManifest(
title: matScanModel.pkgName, title: matScanModel.pkgName,
docUrl: '', docUrl: '',
screenshot: '', screenshot: '',
devMode: 'proCode', // 需要入料的组件都是源码模式,低代码组件在平台上即可直接生成描述
npm: { npm: {
package: matScanModel.pkgName, package: matScanModel.pkgName,
version: matScanModel.pkgVersion, version: matScanModel.pkgVersion,

View File

@ -1,12 +1,11 @@
import spawn from 'cross-spawn-promise'; import spawn from 'cross-spawn-promise';
import { ensureDir, ensureFile, writeFile } from 'fs-extra'; import { ensureDir, ensureFile, writeFile } from 'fs-extra';
import { join } from 'path'; import { join } from 'path';
import semver from 'semver';
import uuid from 'short-uuid'; import uuid from 'short-uuid';
import { debug } from './core'; import { debug } from './core';
import { IMaterializeOptions } from './types'; import { IMaterializeOptions } from './types';
const log = debug.extend('mat'); const log = debug.extend('localize');
/** /**
* *

View File

@ -3,6 +3,9 @@ import parseJS from './js';
import parseTS from './ts'; import parseTS from './ts';
import { install, installPeerDeps, installTypeModules } from '../utils'; import { install, installPeerDeps, installTypeModules } from '../utils';
import { IMaterialScanModel } from '../types'; import { IMaterialScanModel } from '../types';
import { debug } from '../core';
const log = debug.extend('parse');
export interface IParseArgs extends IMaterialScanModel { export interface IParseArgs extends IMaterialScanModel {
accesser?: 'online' | 'local'; accesser?: 'online' | 'local';
@ -15,7 +18,11 @@ export interface IParseArgs extends IMaterialScanModel {
} }
export default async (args: IParseArgs) => { export default async (args: IParseArgs) => {
const { typingsFileAbsolutePath, mainFileAbsolutePath, moduleFileAbsolutePath = mainFileAbsolutePath } = args; const {
typingsFileAbsolutePath,
mainFileAbsolutePath,
moduleFileAbsolutePath = mainFileAbsolutePath,
} = args;
if (args.accesser === 'local') { if (args.accesser === 'local') {
if (moduleFileAbsolutePath.endsWith('ts') || moduleFileAbsolutePath.endsWith('tsx')) { if (moduleFileAbsolutePath.endsWith('ts') || moduleFileAbsolutePath.endsWith('tsx')) {
await install(args); await install(args);
@ -48,7 +55,7 @@ export default async (args: IParseArgs) => {
} }
return info; return info;
} catch (e) { } catch (e) {
console.error(e); log(e);
// if error, use static js parsing instead // if error, use static js parsing instead
return parseJS(moduleFileAbsolutePath); return parseJS(moduleFileAbsolutePath);
} }

View File

@ -1,5 +1,8 @@
// import { debug } from '../../../core';
const { namedTypes: t, NodePath } = require('ast-types'); const { namedTypes: t, NodePath } = require('ast-types');
// const log = debug.extend('parse:js');
type NodePathType = typeof NodePath; type NodePathType = typeof NodePath;
const { const {
getPropertyName, getPropertyName,
@ -7,7 +10,6 @@ const {
getMemberValuePath, getMemberValuePath,
isReactForwardRefCall, isReactForwardRefCall,
printValue, printValue,
resolveExportDeclaration,
resolveToValue, resolveToValue,
} = require('react-docgen').utils; } = require('react-docgen').utils;
const resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue'); const resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue');
@ -29,16 +31,17 @@ function getDefaultValue(path: NodePathType) {
node = path.node; node = path.node;
try { try {
defaultValue = printValue(path); defaultValue = printValue(path);
} catch (e) {} } catch (e) {
// log(e);
// TODO
}
} }
} }
if (typeof defaultValue !== 'undefined') { if (typeof defaultValue !== 'undefined') {
return { return {
value: defaultValue, value: defaultValue,
computed: computed:
t.CallExpression.check(node) || t.CallExpression.check(node) || t.MemberExpression.check(node) || t.Identifier.check(node),
t.MemberExpression.check(node) ||
t.Identifier.check(node),
}; };
} }
@ -55,10 +58,7 @@ function getStatelessPropsPath(componentDefinition: any) {
} }
function getDefaultPropsPath(componentDefinition: any) { function getDefaultPropsPath(componentDefinition: any) {
let defaultPropsPath = getMemberValuePath( let defaultPropsPath = getMemberValuePath(componentDefinition, 'defaultProps');
componentDefinition,
'defaultProps',
);
if (!defaultPropsPath) { if (!defaultPropsPath) {
return null; return null;
} }
@ -71,9 +71,7 @@ function getDefaultPropsPath(componentDefinition: any) {
if (t.FunctionExpression.check(defaultPropsPath.node)) { if (t.FunctionExpression.check(defaultPropsPath.node)) {
// Find the value that is returned from the function and process it if it is // Find the value that is returned from the function and process it if it is
// an object literal. // an object literal.
const returnValue = resolveFunctionDefinitionToReturnValue( const returnValue = resolveFunctionDefinitionToReturnValue(defaultPropsPath);
defaultPropsPath,
);
if (returnValue && t.ObjectExpression.check(returnValue.node)) { if (returnValue && t.ObjectExpression.check(returnValue.node)) {
defaultPropsPath = returnValue; defaultPropsPath = returnValue;
} }
@ -81,16 +79,11 @@ function getDefaultPropsPath(componentDefinition: any) {
return defaultPropsPath; return defaultPropsPath;
} }
function getDefaultValuesFromProps( function getDefaultValuesFromProps(properties: any[], documentation: any, isStateless: boolean) {
properties: any[],
documentation: any,
isStateless: boolean,
) {
properties properties
// Don't evaluate property if component is functional and the node is not an AssignmentPattern // Don't evaluate property if component is functional and the node is not an AssignmentPattern
.filter( .filter(
propertyPath => !isStateless || propertyPath => !isStateless || t.AssignmentPattern.check(propertyPath.get('value').node),
t.AssignmentPattern.check(propertyPath.get('value').node),
) )
.forEach(propertyPath => { .forEach(propertyPath => {
if (t.Property.check(propertyPath.node)) { if (t.Property.check(propertyPath.node)) {
@ -99,9 +92,7 @@ function getDefaultValuesFromProps(
const propDescriptor = documentation.getPropDescriptor(propName); const propDescriptor = documentation.getPropDescriptor(propName);
const defaultValue = getDefaultValue( const defaultValue = getDefaultValue(
isStateless isStateless ? propertyPath.get('value', 'right') : propertyPath.get('value'),
? propertyPath.get('value', 'right')
: propertyPath.get('value'),
); );
if (defaultValue) { if (defaultValue) {
propDescriptor.defaultValue = defaultValue; propDescriptor.defaultValue = defaultValue;
@ -119,10 +110,7 @@ function getDefaultValuesFromProps(
}); });
} }
export default function defaultPropsHandler( export default function defaultPropsHandler(documentation: any, componentDefinition: any) {
documentation: any,
componentDefinition: any,
) {
let statelessProps = null; let statelessProps = null;
const defaultPropsPath = getDefaultPropsPath(componentDefinition); const defaultPropsPath = getDefaultPropsPath(componentDefinition);
/** /**
@ -134,17 +122,9 @@ export default function defaultPropsHandler(
// Do both statelessProps and defaultProps if both are available so defaultProps can override // Do both statelessProps and defaultProps if both are available so defaultProps can override
if (statelessProps && t.ObjectPattern.check(statelessProps.node)) { if (statelessProps && t.ObjectPattern.check(statelessProps.node)) {
getDefaultValuesFromProps( getDefaultValuesFromProps(statelessProps.get('properties'), documentation, true);
statelessProps.get('properties'),
documentation,
true,
);
} }
if (defaultPropsPath && t.ObjectExpression.check(defaultPropsPath.node)) { if (defaultPropsPath && t.ObjectExpression.check(defaultPropsPath.node)) {
getDefaultValuesFromProps( getDefaultValuesFromProps(defaultPropsPath.get('properties'), documentation, false);
defaultPropsPath.get('properties'),
documentation,
false,
);
} }
} }

View File

@ -7,9 +7,9 @@
import { namedTypes as t } from 'ast-types'; import { namedTypes as t } from 'ast-types';
import getTSType from '../utils/getTSType'; import getTSType from '../utils/getTSType';
import getRoot from '../utils/getRoot'; import getFlowTypeFromReactComponent, {
import parseTS from '../../ts'; applyToFlowTypeProperties,
import getFlowTypeFromReactComponent, { applyToFlowTypeProperties } from '../utils/getFlowTypeFromReactComponent'; } from '../utils/getFlowTypeFromReactComponent';
const { unwrapUtilityType } = require('react-docgen/dist/utils/flowUtilityTypes'); const { unwrapUtilityType } = require('react-docgen/dist/utils/flowUtilityTypes');
const { getFlowType, getPropertyName, resolveToValue } = require('react-docgen').utils; const { getFlowType, getPropertyName, resolveToValue } = require('react-docgen').utils;

View File

@ -26,9 +26,9 @@ export default function parse(filePath: string): IMaterialParsedModel[] {
const item: any = transformItem(name, info.props[name]); const item: any = transformItem(name, info.props[name]);
acc.push(item); acc.push(item);
} catch (e) { } catch (e) {
} finally { // TODO
return acc;
} }
return acc;
}, []); }, []);
res.push({ res.push({
componentName: info.displayName, componentName: info.displayName,

View File

@ -3,7 +3,7 @@ import { uniqBy } from 'lodash';
import checkIsIIFE from './checkIsIIFE'; import checkIsIIFE from './checkIsIIFE';
import resolveHOC from './resolveHOC'; import resolveHOC from './resolveHOC';
import resolveIIFE from './resolveIIFE'; import resolveIIFE from './resolveIIFE';
import resolveImport, { isImportLike } from './resolveImport'; import resolveImport from './resolveImport';
import resolveTranspiledClass from './resolveTranspiledClass'; import resolveTranspiledClass from './resolveTranspiledClass';
import isStaticMethod from './isStaticMethod'; import isStaticMethod from './isStaticMethod';
import findAssignedMethods from './findAssignedMethods'; import findAssignedMethods from './findAssignedMethods';
@ -253,14 +253,16 @@ function getSubComponents(path: any, scope: any, cache: ICache) {
value: def.flatMap((x: any) => x).filter((x: any) => isComponentDefinition(x)), value: def.flatMap((x: any) => x).filter((x: any) => isComponentDefinition(x)),
}; };
}) })
.map(({ subName, localName, value }: IMethodsPath) => value.map((x: any) => ({ .map(({ subName, localName, value }: IMethodsPath) => {
subName, return value.map((x: any) => ({
localName, subName,
value: x, localName,
}))) value: x,
}));
})
// @ts-ignore // @ts-ignore
.flatMap((x: any) => x) .flatMap((x: any) => x)
.map(({ subName, localName, value }: IMethodsPath) => { .map(({ subName, value }: IMethodsPath) => {
const __meta = { const __meta = {
subName, subName,
exportName: path.__meta && path.__meta.exportName, exportName: path.__meta && path.__meta.exportName,

View File

@ -1,10 +1,6 @@
import { namedTypes as t, visit } from 'ast-types'; import { namedTypes as t } from 'ast-types';
const { const { isReactCreateClassCall, isReactForwardRefCall } = require('react-docgen').utils;
isReactCreateClassCall,
isReactForwardRefCall,
resolveToValue,
} = require('react-docgen').utils;
/** /**
* If the path is a call expression, it recursively resolves to the * If the path is a call expression, it recursively resolves to the

View File

@ -1,4 +1,4 @@
import { builders, namedTypes as t, NodePath, visit } from 'ast-types'; import { builders, NodePath, visit } from 'ast-types';
/** /**
* If the path is a call expression, it recursively resolves to the * If the path is a call expression, it recursively resolves to the
* rightmost argument, stopping if it finds a React.createClass call expression * rightmost argument, stopping if it finds a React.createClass call expression
@ -17,11 +17,7 @@ export default function resolveTranspiledClass(path: any) {
builders.blockStatement([ builders.blockStatement([
builders.returnStatement( builders.returnStatement(
builders.jsxElement( builders.jsxElement(
builders.jsxOpeningElement( builders.jsxOpeningElement(builders.jsxIdentifier('div'), [], true),
builders.jsxIdentifier('div'),
[],
true,
),
), ),
), ),
]), ]),

View File

@ -14,5 +14,5 @@ export function get(scope: string, name: string) {
} }
export function has(scope: string, name: string) { export function has(scope: string, name: string) {
return cache[scope] && cache[scope].hasOwnProperty(name); return cache[scope] && Object.prototype.hasOwnProperty.call(cache[scope], name);
} }

View File

@ -9,10 +9,15 @@ function makeProxy(target: { [name: string]: any }, meta: any = {}): any {
if (prop === '__isProxy') return true; if (prop === '__isProxy') return true;
if (prop === '__getRaw') return () => target; if (prop === '__getRaw') return () => target;
if (prop === '__getMeta') return () => meta; if (prop === '__getMeta') return () => meta;
return meta.hasOwnProperty(prop) ? meta[prop] : obj[prop]; return Object.prototype.hasOwnProperty.call(meta, prop) ? meta[prop] : obj[prop];
// return obj[prop]; // return obj[prop];
}, },
has: (obj, prop) => obj.hasOwnProperty(prop) || meta.hasOwnProperty(prop), has: (obj, prop) => {
return (
Object.prototype.hasOwnProperty.call(obj, prop) ||
Object.prototype.hasOwnProperty.call(meta, prop)
);
},
}); });
} }

View File

@ -4,7 +4,6 @@ import { isEmpty } from 'lodash';
import parsePropTypes from 'parse-prop-types'; import parsePropTypes from 'parse-prop-types';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { transformItem } from '../transform'; import { transformItem } from '../transform';
import { IParseArgs } from '../index';
import requireInSandbox from './requireInSandbox'; import requireInSandbox from './requireInSandbox';
export interface IComponentInfo { export interface IComponentInfo {
@ -29,7 +28,7 @@ const reservedKeys = [
]; ];
function getKeys(com: any) { function getKeys(com: any) {
const keys = Object.keys(com).filter((x) => { const keys = Object.keys(com).filter(x => {
return !reservedKeys.includes(x) && !x.startsWith('_'); return !reservedKeys.includes(x) && !x.startsWith('_');
}); });
@ -37,7 +36,11 @@ function getKeys(com: any) {
} }
function isComponent(obj: any) { function isComponent(obj: any) {
return typeof obj === 'function' && (obj.hasOwnProperty('propTypes') || obj.hasOwnProperty('defaultProps')); return (
typeof obj === 'function' &&
(Object.prototype.hasOwnProperty.call(obj, 'propTypes') ||
Object.prototype.hasOwnProperty.call(obj, 'defaultProps'))
);
} }
export default function (filePath: string) { export default function (filePath: string) {
@ -50,7 +53,7 @@ export default function (filePath: string) {
if (Com.__esModule) { if (Com.__esModule) {
const keys = getKeys(Com); const keys = getKeys(Com);
keys.forEach((k) => { keys.forEach(k => {
if (isComponent(Com[k])) { if (isComponent(Com[k])) {
components.push({ components.push({
component: Com[k], component: Com[k],
@ -75,8 +78,8 @@ export default function (filePath: string) {
const keys = getKeys(item.component); const keys = getKeys(item.component);
const subs = keys const subs = keys
.filter((k) => isComponent(item.component[k])) .filter(k => isComponent(item.component[k]))
.map((k) => ({ .map(k => ({
component: item.component[k], component: item.component[k],
meta: { meta: {
...item.meta, ...item.meta,
@ -91,14 +94,14 @@ export default function (filePath: string) {
const result = components.reduce((acc: any, { meta, component }) => { const result = components.reduce((acc: any, { meta, component }) => {
const componentInfo = parsePropTypes(component); const componentInfo = parsePropTypes(component);
if (!isEmpty(componentInfo)) { if (!isEmpty(componentInfo)) {
const props = Object.keys(componentInfo).reduce((acc: any[], name) => { const props = Object.keys(componentInfo).reduce((acc2: any[], name) => {
try { try {
const item: any = transformItem(name, componentInfo[name]); const item: any = transformItem(name, componentInfo[name]);
acc.push(item); acc2.push(item);
} catch (e) { } catch (e) {
} finally { // TODO
return acc;
} }
return acc2;
}, []); }, []);
return [ return [

View File

@ -1,4 +1,8 @@
import { omit, pick } from 'lodash'; import { omit, pick, isNil } from 'lodash';
import { safeEval, isEvaluable } from '../utils';
import { debug } from '../core';
const log = debug.extend('parse:transform');
export function transformType(itemType: any) { export function transformType(itemType: any) {
if (typeof itemType === 'string') return itemType; if (typeof itemType === 'string') return itemType;
@ -7,7 +11,7 @@ export function transformType(itemType: any) {
// return name; // return name;
// } // }
if (computed !== undefined && value) { if (computed !== undefined && value) {
return eval(value); return safeEval(value);
} }
const result: any = { const result: any = {
type: name, type: name,
@ -24,16 +28,31 @@ export function transformType(itemType: any) {
case 'symbol': case 'symbol':
case 'object': case 'object':
case 'null': case 'null':
case 'array':
case 'element':
case 'node':
break; break;
case 'literal': case 'literal':
return eval(value); return safeEval(value);
case 'enum': case 'enum':
case 'tuple': case 'tuple':
case 'oneOf': case 'oneOf':
result.type = 'oneOf'; result.type = 'oneOf';
result.value = value.map(transformType); result.value = value.map(transformType);
break; break;
case 'union': case 'union': {
const { raw } = itemType;
if (raw) {
if (raw.match(/ReactNode$/)) {
result.type = 'node';
break;
} else if (raw.match(/Element$/)) {
result.type = 'element';
break;
}
}
}
// eslint-disable-next-line no-fallthrough
case 'oneOfType': case 'oneOfType':
result.type = 'oneOfType'; result.type = 'oneOfType';
result.value = value.map(transformType); result.value = value.map(transformType);
@ -77,12 +96,9 @@ export function transformType(itemType: any) {
result.value = properties result.value = properties
.filter((item: any) => typeof item.key !== 'object') .filter((item: any) => typeof item.key !== 'object')
.map((prop: any) => { .map((prop: any) => {
const { const { key } = prop;
key,
value: { name, ...others },
} = prop;
return transformItem(key, { return transformItem(key, {
...others, ...omit(prop.value, 'name'),
type: pick(prop.value, ['name', 'value']), type: pick(prop.value, ['name', 'value']),
}); });
}); });
@ -90,7 +106,6 @@ export function transformType(itemType: any) {
break; break;
} }
case 'objectOf': case 'objectOf':
case 'arrayOf':
case 'instanceOf': case 'instanceOf':
result.value = transformType(value); result.value = transformType(value);
break; break;
@ -107,18 +122,19 @@ export function transformType(itemType: any) {
}); });
}); });
break; break;
case (name.match('ReactNode$') || {}).input: case (name.match(/ReactNode$/) || {}).input:
result.type = 'node'; result.type = 'node';
break; break;
case (name.match('Element$') || {}).input: case (name.match(/Element$/) || {}).input:
result.type = 'element'; result.type = 'element';
break; break;
case (name.match('ElementType$') || {}).input: // case (name.match(/ElementType$/) || {}).input:
result.type = 'elementType'; // result.type = 'elementType';
break; // break;
default: default:
result.type = 'instanceOf'; // result.type = 'instanceOf';
result.value = name; // result.value = name;
result.type = 'any';
break; break;
} }
if (Object.keys(result).length === 1) { if (Object.keys(result).length === 1) {
@ -128,7 +144,15 @@ export function transformType(itemType: any) {
} }
export function transformItem(name: string, item: any) { export function transformItem(name: string, item: any) {
const { description, flowType, tsType, type = tsType || flowType, required, defaultValue, ...others } = item; const {
description,
flowType,
tsType,
type = tsType || flowType,
required,
defaultValue,
...others
} = item;
const result: any = { const result: any = {
name, name,
}; };
@ -147,11 +171,19 @@ export function transformItem(name: string, item: any) {
result.description = description; result.description = description;
} }
} }
if (defaultValue !== undefined) { if (!isNil(defaultValue) && typeof defaultValue === 'object' && isEvaluable(defaultValue)) {
try { if (defaultValue === null) {
const value = eval(defaultValue.value); result.defaultValue = defaultValue;
result.defaultValue = value; } else {
} catch (e) {} try {
const value = safeEval(defaultValue.value);
if (isEvaluable(value)) {
result.defaultValue = value;
}
} catch (e) {
log(e);
}
}
} }
if (result.propType === undefined) { if (result.propType === undefined) {
delete result.propType; delete result.propType;

View File

@ -1,8 +1,17 @@
import { Parser, ComponentDoc } from 'react-docgen-typescript'; import { Parser, ComponentDoc } from 'react-docgen-typescript';
import ts, { SymbolFlags, TypeFlags } from 'typescript'; import ts, { SymbolFlags, TypeFlags } from 'typescript';
import { isEmpty, isEqual } from 'lodash'; import { isEmpty, isEqual } from 'lodash';
import { debug } from '../../core';
import { Json } from '../../types';
import { transformItem } from '../transform'; import { transformItem } from '../transform';
const log = debug.extend('parse:ts');
type ExtendedType = ts.Type & {
id: string;
typeArguments: any[];
};
function getSymbolName(symbol: ts.Symbol) { function getSymbolName(symbol: ts.Symbol) {
// @ts-ignore // @ts-ignore
const prefix: string = symbol.parent && getSymbolName(symbol.parent); const prefix: string = symbol.parent && getSymbolName(symbol.parent);
@ -32,13 +41,10 @@ function getDocgenTypeHelper(
parentIds: number[] = [], parentIds: number[] = [],
isRequired = false, isRequired = false,
): any { ): any {
function isTuple(type: ts.Type) { function isTuple(_type: ts.Type) {
// @ts-ignore use internal methods // @ts-ignore use internal methods
return checker.isArrayLikeType(type) && !checker.isArrayType(type); return checker.isArrayLikeType(_type) && !checker.isArrayType(_type);
} }
// if (type.aliasSymbol && type.aliasSymbol.getName() === 'ReactNode') {
// return 'children';
// }
let required: boolean; let required: boolean;
if (isRequired !== undefined) { if (isRequired !== undefined) {
required = isRequired; required = isRequired;
@ -46,7 +52,7 @@ function getDocgenTypeHelper(
required = !(type.flags & SymbolFlags.Optional) || isRequired; required = !(type.flags & SymbolFlags.Optional) || isRequired;
} }
function makeResult(typeInfo: object) { function makeResult(typeInfo: Json) {
if (skipRequired) { if (skipRequired) {
return { return {
raw: checker.typeToString(type), raw: checker.typeToString(type),
@ -61,7 +67,7 @@ function getDocgenTypeHelper(
} }
} }
function getShapeFromArray(symbolArr: ts.Symbol[], type: ts.Type) { function getShapeFromArray(symbolArr: ts.Symbol[], _type: ts.Type) {
const shape: Array<{ const shape: Array<{
key: key:
| { | {
@ -69,7 +75,7 @@ function getDocgenTypeHelper(
} }
| string; | string;
value: any; value: any;
}> = symbolArr.map((prop) => { }> = symbolArr.map(prop => {
const propType = checker.getTypeOfSymbolAtLocation( const propType = checker.getTypeOfSymbolAtLocation(
prop, prop,
// @ts-ignore // @ts-ignore
@ -83,19 +89,19 @@ function getDocgenTypeHelper(
propType, propType,
false, false,
// @ts-ignore // @ts-ignore
[...parentIds, type.id], [...parentIds, _type.id],
// @ts-ignore // @ts-ignore
prop?.valueDeclaration?.questionToken ? false : undefined, prop?.valueDeclaration?.questionToken ? false : undefined,
), ),
}; };
}); });
// @ts-ignore use internal methods // @ts-ignore use internal methods
if (checker.isArrayLikeType(type)) { if (checker.isArrayLikeType(_type)) {
return shape; return shape;
} }
if (type.getStringIndexType()) { if (_type.getStringIndexType()) {
// @ts-ignore use internal methods // @ts-ignore use internal methods
if (!type.stringIndexInfo) { if (!_type.stringIndexInfo) {
return shape; return shape;
} }
shape.push({ shape.push({
@ -103,11 +109,14 @@ function getDocgenTypeHelper(
name: 'string', name: 'string',
}, },
// @ts-ignore use internal methods // @ts-ignore use internal methods
value: getDocgenTypeHelper(checker, type.stringIndexInfo.type, false, [...parentIds, type.id]), value: getDocgenTypeHelper(checker, _type.stringIndexInfo.type, false, [
...parentIds,
(_type as ExtendedType).id,
]),
}); });
} else if (type.getNumberIndexType()) { } else if (_type.getNumberIndexType()) {
// @ts-ignore use internal methods // @ts-ignore use internal methods
if (!type.numberIndexInfo) { if (!_type.numberIndexInfo) {
return shape; return shape;
} }
shape.push({ shape.push({
@ -116,32 +125,34 @@ function getDocgenTypeHelper(
}, },
// @ts-ignore use internal methods // @ts-ignore use internal methods
value: getDocgenTypeHelper(checker, type.numberIndexInfo.type, false, [...parentIds, type.id]), value: getDocgenTypeHelper(checker, _type.numberIndexInfo.type, false, [
...parentIds,
(_type as ExtendedType).id,
]),
}); });
} }
return shape; return shape;
} }
function getShape(type: ts.Type) { function getShape(_type: ts.Type) {
const { symbol } = type; const { symbol } = _type;
if (symbol && symbol.members) { if (symbol && symbol.members) {
// @ts-ignore // @ts-ignore
const props: ts.Symbol[] = Array.from(symbol.members.values()); const props: ts.Symbol[] = Array.from(symbol.members.values());
return getShapeFromArray( return getShapeFromArray(
props.filter((prop) => prop.getName() !== '__index'), props.filter(prop => prop.getName() !== '__index'),
type, _type,
); );
} else { } else {
// @ts-ignore // @ts-ignore
const args = type.resolvedTypeArguments || []; const args = _type.resolvedTypeArguments || [];
const props = checker.getPropertiesOfType(type); const props = checker.getPropertiesOfType(_type);
const shape = getShapeFromArray(props.slice(0, args.length), type); const shape = getShapeFromArray(props.slice(0, args.length), _type);
return shape; return shape;
} }
} }
const pattern = /^__global\.(.+)$/; const pattern = /^__global\.(.+)$/;
// @ts-ignore // @ts-ignore
if (parentIds.includes(type.id)) { if (parentIds.includes(type.id)) {
return makeResult({ return makeResult({
@ -191,21 +202,26 @@ function getDocgenTypeHelper(
return makeResult({ return makeResult({
name: 'union', name: 'union',
// @ts-ignore // @ts-ignore
value: type.types.map((t) => getDocgenTypeHelper(checker, t, true, [...parentIds, type.id])), value: type.types.map(t => getDocgenTypeHelper(checker, t, true, [...parentIds, type.id])),
}); });
} else if (type.flags & (TypeFlags.Object | TypeFlags.Intersection)) { } else if (type.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
if (isTuple(type)) { if (isTuple(type)) {
const props = getShape(type); const props = getShape(type);
return makeResult({ return makeResult({
name: 'union', name: 'union',
value: props.map((p) => p.value), value: props.map(p => p.value),
}); });
// @ts-ignore // @ts-ignore
} else if (checker.isArrayType(type)) { } else if (checker.isArrayType(type)) {
return makeResult({ return makeResult({
name: 'Array', name: 'Array',
// @ts-ignore // @ts-ignore
elements: [getDocgenTypeHelper(checker, type.typeArguments[0], false, [...parentIds, type.id])], elements: [
getDocgenTypeHelper(checker, (type as ExtendedType).typeArguments[0], false, [
...parentIds,
(type as any).id,
]),
],
}); });
} else if (type.aliasSymbol) { } else if (type.aliasSymbol) {
return makeResult({ return makeResult({
@ -254,7 +270,10 @@ interface SymbolWithMeta extends ts.Symbol {
}; };
} }
export default function parseTS(filePathOrPaths: string | string[], parserOpts: any = {}): ComponentDoc[] { export default function parseTS(
filePathOrPaths: string | string[],
parserOpts: any = {},
): ComponentDoc[] {
const filePaths = Array.isArray(filePathOrPaths) ? filePathOrPaths : [filePathOrPaths]; const filePaths = Array.isArray(filePathOrPaths) ? filePathOrPaths : [filePathOrPaths];
const program = ts.createProgram(filePaths, compilerOptions); const program = ts.createProgram(filePaths, compilerOptions);
@ -264,8 +283,8 @@ export default function parseTS(filePathOrPaths: string | string[], parserOpts:
const checker = program.getTypeChecker(); const checker = program.getTypeChecker();
const result = filePaths const result = filePaths
.map((filePath) => program.getSourceFile(filePath)) .map(filePath => program.getSourceFile(filePath))
.filter((sourceFile) => typeof sourceFile !== 'undefined') .filter(sourceFile => typeof sourceFile !== 'undefined')
.reduce((docs: any[], sourceFile) => { .reduce((docs: any[], sourceFile) => {
const moduleSymbol = checker.getSymbolAtLocation(sourceFile as ts.Node); const moduleSymbol = checker.getSymbolAtLocation(sourceFile as ts.Node);
@ -291,7 +310,7 @@ export default function parseTS(filePathOrPaths: string | string[], parserOpts:
subName: exportName ? name : '', subName: exportName ? name : '',
exportName: exportName || name, exportName: exportName || name,
}; };
if (docs.find((x) => isEqual(x.meta, meta))) { if (docs.find(x => isEqual(x.meta, meta))) {
continue; continue;
} }
docs.push({ docs.push({
@ -303,7 +322,10 @@ export default function parseTS(filePathOrPaths: string | string[], parserOpts:
continue; continue;
} }
const type = checker.getTypeOfSymbolAtLocation(sym, sym.valueDeclaration || sym.declarations[0]); const type = checker.getTypeOfSymbolAtLocation(
sym,
sym.valueDeclaration || sym.declarations[0],
);
Array.prototype.push.apply( Array.prototype.push.apply(
exportSymbols, exportSymbols,
@ -323,10 +345,9 @@ export default function parseTS(filePathOrPaths: string | string[], parserOpts:
const item: any = transformItem(name, info.props[name]); const item: any = transformItem(name, info.props[name]);
acc.push(item); acc.push(item);
} catch (e) { } catch (e) {
console.log('error', e); log(e);
} finally {
return acc;
} }
return acc;
}, []); }, []);
res.push({ res.push({
componentName: info?.meta?.exportName || info.displayName, componentName: info?.meta?.exportName || info.displayName,

View File

@ -0,0 +1,4 @@
export interface Json {
[x: string]: string | number | boolean | Date | Json | JsonArray;
}
export type JsonArray = Array<string | number | boolean | Date | Json | JsonArray>;

View File

@ -1,11 +1,9 @@
/** /**
* *
*/ */
enum ChannelType { export enum ChannelType {
/** 本地 */ /** 本地 */
LOCAL = 'local', LOCAL = 'local',
/** 在线 */ /** 在线 */
ONLINE = 'online', ONLINE = 'online',
} }
export default ChannelType;

View File

@ -1,7 +1,7 @@
/** /**
* *
*/ */
enum EcologyType { export enum EcologyType {
/** react 生态 */ /** react 生态 */
REACT = 'react', REACT = 'react',
/** vue 生态 */ /** vue 生态 */
@ -11,5 +11,3 @@ enum EcologyType {
/** angular 生态 */ /** angular 生态 */
ANGULAR = 'angular', ANGULAR = 'angular',
} }
export default EcologyType;

View File

@ -1,9 +0,0 @@
/**
*
*/
enum ExtensionName {
/** 配置 manifest */
CONFIGMANIFEST = 'mat:config:manifest',
}
export default ExtensionName;

View File

@ -4,7 +4,7 @@ import { ComponentMeta } from '../core';
* *
* @interface IAccesser * @interface IAccesser
*/ */
interface IAccesser { export interface IAccesser {
/** /**
* *
* @returns {Promise<IMaterialinSchema>} * @returns {Promise<IMaterialinSchema>}
@ -12,5 +12,3 @@ interface IAccesser {
*/ */
access(): Promise<ComponentMeta[]>; access(): Promise<ComponentMeta[]>;
} }
export default IAccesser;

View File

@ -1,15 +0,0 @@
/**
* - bundle.js
* @interface ICompiler
*/
interface ICompiler {
/**
*
* @param {{ [key: string]: any }} config webpack
* @returns {Promise<void>}
* @memberof ICompiler
*/
compile(config: { [key: string]: any }): Promise<void>;
}
export default ICompiler;

View File

@ -3,7 +3,7 @@ import { ComponentMeta } from '../core';
* manifest * manifest
* *
*/ */
type IExtensionConfigManifest = (params: { export type IExtensionConfigManifest = (params: {
manifestObj: ComponentMeta; // manifest 配置对象 manifestObj: ComponentMeta; // manifest 配置对象
manifestFilePath: string; // manifest 文件默认路径 manifestFilePath: string; // manifest 文件默认路径
}) => Promise<{ }) => Promise<{
@ -11,5 +11,3 @@ type IExtensionConfigManifest = (params: {
manifestFilePath: string; // manifest 文件路径 manifestFilePath: string; // manifest 文件路径
manifestObj: ComponentMeta; // manifest 文件对象 manifestObj: ComponentMeta; // manifest 文件对象
}>; }>;
export default IExtensionConfigManifest;

View File

@ -1,7 +1,7 @@
/** /**
* *
*/ */
interface IMaterialScanModel { export interface IMaterialScanModel {
/** 当前包名 */ /** 当前包名 */
pkgName: string; pkgName: string;
/** 当前包版本 */ /** 当前包版本 */
@ -19,5 +19,3 @@ interface IMaterialScanModel {
/** typings文件绝对路径 */ /** typings文件绝对路径 */
typingsFileAbsolutePath?: string; typingsFileAbsolutePath?: string;
} }
export default IMaterialScanModel;

View File

@ -1,11 +1,8 @@
import ExtensionName from './ExtensionName';
import IExtensionConfigManifest from './IExtensionConfigManifest';
/** /**
* *
* @interface IMaterializeOptions * @interface IMaterializeOptions
*/ */
interface IMaterializeOptions { export interface IMaterializeOptions {
/** /**
* () * ()
* *
@ -35,5 +32,3 @@ interface IMaterializeOptions {
*/ */
npmClient?: string; npmClient?: string;
} }
export default IMaterializeOptions;

View File

@ -1,4 +1,4 @@
import { NodePath, Path } from 'ast-types'; import { Path } from 'ast-types';
export interface IFileMeta { export interface IFileMeta {
src: string; src: string;

View File

@ -1,21 +1,8 @@
import ChannelType from './ChannelType'; export * from './ChannelType';
import EcologyType from './EcologyType'; export * from './EcologyType';
import ExtensionName from './ExtensionName'; export * from './IAccesser';
import IAccesser from './IAccesser'; export * from './IExtensionConfigManifest';
import ICompiler from './ICompiler'; export * from './IMaterializeOptions';
import IExtensionConfigManifest from './IExtensionConfigManifest'; export * from './IMaterialScanModel';
import IMaterializeOptions from './IMaterializeOptions'; export * from './IMaterialParsedModel';
import IMaterialScanModel from './IMaterialScanModel'; export * from './Basic';
import { IMaterialParsedModel } from './IMaterialParsedModel';
export {
ExtensionName,
IExtensionConfigManifest,
IMaterialParsedModel,
IMaterializeOptions,
IMaterialScanModel,
ChannelType,
EcologyType,
IAccesser,
ICompiler,
};

View File

@ -1,27 +1,42 @@
import { pathExists, readFileSync, writeFile } from 'fs-extra'; import { pathExists, readFileSync, writeFile } from 'fs-extra';
import { isPlainObject } from 'lodash';
import safeEval from 'safe-eval';
import * as path from 'path'; import * as path from 'path';
import spawn from 'cross-spawn-promise'; import spawn from 'cross-spawn-promise';
export async function isNPMInstalled(args: { workDir: string; moduleDir: string; npmClient?: string }) { export async function isNPMInstalled(args: {
return await pathExists(path.join(args.workDir, 'node_modules')); workDir: string;
moduleDir: string;
npmClient?: string;
}) {
return pathExists(path.join(args.workDir, 'node_modules'));
} }
export async function install(args: { workDir: string; moduleDir: string; npmClient?: string }) { export async function install(args: { workDir: string; moduleDir: string; npmClient?: string }) {
if (await isNPMInstalled(args)) return; if (await isNPMInstalled(args)) return;
const { workDir, moduleDir, npmClient = 'tnpm' } = args; const { workDir, npmClient = 'tnpm' } = args;
try { try {
await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any); await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
} catch (e) {} } catch (e) {
// TODO
}
} }
export async function installTypeScript(args: { workDir: string; moduleDir: string; npmClient?: string }) { export async function installTypeScript(args: {
workDir: string;
moduleDir: string;
npmClient?: string;
}) {
if (await isNPMInstalled(args)) return; if (await isNPMInstalled(args)) return;
const { workDir, moduleDir, npmClient = 'tnpm' } = args; const { workDir, npmClient = 'tnpm' } = args;
await spawn(npmClient, ['i', 'typescript'], { stdio: 'inherit', cwd: workDir } as any); await spawn(npmClient, ['i', 'typescript'], { stdio: 'inherit', cwd: workDir } as any);
} }
export async function installPeerDeps(args: { workDir: string; moduleDir: string; npmClient?: string }) { export async function installPeerDeps(args: {
workDir: string;
moduleDir: string;
npmClient?: string;
}) {
const { workDir, moduleDir, npmClient = 'tnpm' } = args; const { workDir, moduleDir, npmClient = 'tnpm' } = args;
const modulePkgJsonPath = path.resolve(moduleDir, 'package.json'); const modulePkgJsonPath = path.resolve(moduleDir, 'package.json');
if (!(await pathExists(modulePkgJsonPath))) { if (!(await pathExists(modulePkgJsonPath))) {
@ -43,7 +58,11 @@ export async function installPeerDeps(args: { workDir: string; moduleDir: string
await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any); await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
} }
export async function installTypeModules(args: { workDir: string; moduleDir: string; npmClient?: string }) { export async function installTypeModules(args: {
workDir: string;
moduleDir: string;
npmClient?: string;
}) {
const { workDir, moduleDir, npmClient = 'tnpm' } = args; const { workDir, moduleDir, npmClient = 'tnpm' } = args;
const pkgJsonPath = path.resolve(moduleDir, 'package.json'); const pkgJsonPath = path.resolve(moduleDir, 'package.json');
if (!(await pathExists(pkgJsonPath))) { if (!(await pathExists(pkgJsonPath))) {
@ -65,3 +84,19 @@ export function loadFile(filePath: string): string {
} }
return content.toString(); return content.toString();
} }
export function isPrimitive(val) {
return !['object', 'function'].includes(typeof val) || val === null;
}
export function isEvaluable(value) {
if (isPrimitive(value)) return true;
if (Array.isArray(value)) {
return value.every(isEvaluable);
} else if (isPlainObject(value)) {
return Object.keys(value).every(key => isEvaluable(value[key]));
}
return false;
}
export { safeEval };

View File

@ -1,10 +1,11 @@
import Ajv from 'ajv'; import Ajv from 'ajv';
import { Json } from '../types/Basic';
import schema from './schema.json'; import schema from './schema.json';
const ajv = new Ajv({ jsonPointers: true }); const ajv = new Ajv({ jsonPointers: true });
const validate = ajv.compile(schema); const validate = ajv.compile(schema);
export default function validateSchema(json: object) { export default function validateSchema(json: Json) {
if (validate(json) === false) { if (validate(json) === false) {
throw new Error(JSON.stringify(validate.errors, null, 2)); throw new Error(JSON.stringify(validate.errors, null, 2));
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ Generated by [AVA](https://avajs.dev).
[ [
{ {
componentName: 'AIMakeBlank', componentName: 'AIMakeBlank',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -63,6 +64,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'AIMakeIcon', componentName: 'AIMakeIcon',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -112,6 +114,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'AIMakeImage', componentName: 'AIMakeImage',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -139,6 +142,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'AIMakeLink', componentName: 'AIMakeLink',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -187,6 +191,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'AIMakePlaceholder', componentName: 'AIMakePlaceholder',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -221,6 +226,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'AIMakeText', componentName: 'AIMakeText',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -273,6 +279,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'Root', componentName: 'Root',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -300,6 +307,7 @@ Generated by [AVA](https://avajs.dev).
[ [
{ {
componentName: 'Demo', componentName: 'Demo',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: false, destructuring: false,
@ -312,10 +320,7 @@ Generated by [AVA](https://avajs.dev).
props: [ props: [
{ {
name: 'optionalArray', name: 'optionalArray',
propType: { propType: 'array',
type: 'instanceOf',
value: 'array',
},
}, },
{ {
name: 'optionalBool', name: 'optionalBool',
@ -344,24 +349,15 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
name: 'optionalNode', name: 'optionalNode',
propType: { propType: 'node',
type: 'instanceOf',
value: 'node',
},
}, },
{ {
name: 'optionalElement', name: 'optionalElement',
propType: { propType: 'element',
type: 'instanceOf',
value: 'element',
},
}, },
{ {
name: 'optionalElementType', name: 'optionalElementType',
propType: { propType: 'any',
type: 'instanceOf',
value: 'elementType',
},
}, },
{ {
name: 'optionalMessage', name: 'optionalMessage',
@ -486,6 +482,7 @@ Generated by [AVA](https://avajs.dev).
[ [
{ {
componentName: 'default', componentName: 'default',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: false, destructuring: false,
@ -498,70 +495,7 @@ Generated by [AVA](https://avajs.dev).
props: [ props: [
{ {
name: 'node', name: 'node',
propType: { propType: 'node',
type: 'oneOfType',
value: [
'string',
'number',
false,
true,
'object',
{
type: 'shape',
value: [
{
name: 'P',
propType: 'any',
},
{
name: 'T',
propType: 'any',
},
{
name: 'type',
propType: 'any',
},
{
name: 'props',
propType: 'any',
},
{
name: 'key',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
],
},
{
type: 'oneOfType',
value: [],
},
{
type: 'shape',
value: [
{
name: 'key',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
name: 'children',
propType: 'node',
},
],
},
],
},
}, },
], ],
screenshot: '', screenshot: '',
@ -569,6 +503,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'default', componentName: 'default',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: false, destructuring: false,

View File

@ -4,199 +4,54 @@ The actual snapshot is saved in `online.ts.snap`.
Generated by [AVA](https://avajs.dev). Generated by [AVA](https://avajs.dev).
## materialize custom breadcrumb by online ## materialize mc-hello by online
> Snapshot 1 > Snapshot 1
[ [
{ {
componentName: 'default', componentName: 'default',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: false, destructuring: false,
exportName: 'default', exportName: 'default',
main: 'lib/index.js', main: 'lib/index.js',
package: 'mc-breadcrumb', package: 'mc-hello',
subName: '', subName: '',
version: '1.0.1', version: '1.0.1',
}, },
props: [ props: [
{ {
name: 'prefix', name: 'color',
propType: 'string', propType: 'string',
}, },
{ {
name: 'rtl', name: 'background',
propType: 'string',
},
{
defaultValue: false,
name: 'round',
propType: 'bool', propType: 'bool',
}, },
{
defaultValue: 200,
name: 'width',
propType: 'number',
},
{
defaultValue: 40,
name: 'height',
propType: 'number',
},
{ {
name: 'children', name: 'children',
propType: { propType: 'node',
type: 'instanceOf',
value: 'custom',
},
},
{
name: 'maxNode',
propType: {
type: 'oneOfType',
value: [
'number',
{
type: 'oneOf',
value: [
'auto',
],
},
],
},
},
{
name: 'separator',
propType: {
type: 'oneOfType',
value: [
{
type: 'instanceOf',
value: 'node',
},
'string',
],
},
},
{
name: 'component',
propType: {
type: 'oneOfType',
value: [
'string',
'func',
],
},
},
{
name: 'className',
propType: 'any',
},
{
name: 'locale',
propType: 'object',
},
{
name: 'pure',
propType: 'bool',
},
{
name: 'device',
propType: {
type: 'oneOf',
value: [
'tablet',
'desktop',
'phone',
],
},
},
{
name: 'popupContainer',
propType: 'any',
},
{
name: 'errorBoundary',
propType: {
type: 'oneOfType',
value: [
'bool',
'object',
],
},
}, },
], ],
screenshot: '', screenshot: '',
title: 'mc-breadcrumb', title: 'mc-hello',
},
{
componentName: 'Item',
docUrl: '',
npm: {
destructuring: false,
exportName: 'default',
main: 'lib/index.js',
package: 'mc-breadcrumb',
subName: 'Item',
version: '1.0.1',
},
props: [
{
name: 'prefix',
propType: 'string',
},
{
name: 'rtl',
propType: 'bool',
},
{
name: 'link',
propType: 'string',
},
{
name: 'activated',
propType: 'bool',
},
{
name: 'separator',
propType: {
type: 'instanceOf',
value: 'node',
},
},
{
name: 'className',
propType: 'any',
},
{
name: 'children',
propType: {
type: 'instanceOf',
value: 'node',
},
},
{
name: 'locale',
propType: 'object',
},
{
name: 'pure',
propType: 'bool',
},
{
name: 'device',
propType: {
type: 'oneOf',
value: [
'tablet',
'desktop',
'phone',
],
},
},
{
name: 'popupContainer',
propType: 'any',
},
{
name: 'errorBoundary',
propType: {
type: 'oneOfType',
value: [
'bool',
'object',
],
},
},
],
screenshot: '',
title: 'mc-breadcrumb',
}, },
] ]
@ -207,6 +62,7 @@ Generated by [AVA](https://avajs.dev).
[ [
{ {
componentName: 'BlockPicker', componentName: 'BlockPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -239,7 +95,6 @@ Generated by [AVA](https://avajs.dev).
}, },
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -249,6 +104,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'CirclePicker', componentName: 'CirclePicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -281,7 +137,6 @@ Generated by [AVA](https://avajs.dev).
propType: 'number', propType: 'number',
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -291,6 +146,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'default', componentName: 'default',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: false, destructuring: false,
@ -318,7 +174,6 @@ Generated by [AVA](https://avajs.dev).
propType: 'bool', propType: 'bool',
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -339,6 +194,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'ChromePicker', componentName: 'ChromePicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -366,7 +222,6 @@ Generated by [AVA](https://avajs.dev).
propType: 'bool', propType: 'bool',
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -387,6 +242,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'CompactPicker', componentName: 'CompactPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -398,7 +254,6 @@ Generated by [AVA](https://avajs.dev).
}, },
props: [ props: [
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -408,6 +263,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'GithubPicker', componentName: 'GithubPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -443,7 +299,6 @@ Generated by [AVA](https://avajs.dev).
}, },
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -453,6 +308,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'HuePicker', componentName: 'HuePicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -464,7 +320,6 @@ Generated by [AVA](https://avajs.dev).
}, },
props: [ props: [
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -474,6 +329,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'PhotoshopPicker', componentName: 'PhotoshopPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -489,7 +345,6 @@ Generated by [AVA](https://avajs.dev).
propType: 'string', propType: 'string',
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -499,6 +354,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'SketchPicker', componentName: 'SketchPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -526,7 +382,6 @@ Generated by [AVA](https://avajs.dev).
}, },
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -536,6 +391,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'SliderPicker', componentName: 'SliderPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -547,7 +403,6 @@ Generated by [AVA](https://avajs.dev).
}, },
props: [ props: [
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -557,6 +412,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'SwatchesPicker', componentName: 'SwatchesPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -590,7 +446,6 @@ Generated by [AVA](https://avajs.dev).
}, },
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },
@ -600,6 +455,7 @@ Generated by [AVA](https://avajs.dev).
}, },
{ {
componentName: 'TwitterPicker', componentName: 'TwitterPicker',
devMode: 'proCode',
docUrl: '', docUrl: '',
npm: { npm: {
destructuring: true, destructuring: true,
@ -633,7 +489,6 @@ Generated by [AVA](https://avajs.dev).
}, },
}, },
{ {
defaultValue: {},
name: 'styles', name: 'styles',
propType: 'object', propType: 'object',
}, },

View File

@ -29,7 +29,6 @@ interface Props {
node?: React.ReactNode; node?: React.ReactNode;
// element?: JSX.Element; // element?: JSX.Element;
// elementType?: React.ElementType; // elementType?: React.ElementType;
// instance: Props;
} }
const App = (props: Props) => { const App = (props: Props) => {

View File

@ -39,4 +39,3 @@ test('ts component by local', async t => {
t.snapshot(actual); t.snapshot(actual);
}); });

View File

@ -3,7 +3,7 @@ import parse from '../src';
import { IMaterializeOptions } from '../src/types'; import { IMaterializeOptions } from '../src/types';
const reactColorComponent = 'react-color'; const reactColorComponent = 'react-color';
const customComponent = 'mc-breadcrumb'; const customComponent = 'mc-hello@1.0.1';
test('materialize react-color by online', async t => { test('materialize react-color by online', async t => {
const options: IMaterializeOptions = { const options: IMaterializeOptions = {
@ -15,7 +15,7 @@ test('materialize react-color by online', async t => {
t.snapshot(actual); t.snapshot(actual);
}); });
test('materialize custom breadcrumb by online', async t => { test('materialize mc-hello by online', async t => {
const options: IMaterializeOptions = { const options: IMaterializeOptions = {
entry: customComponent, entry: customComponent,
accesser: 'online', accesser: 'online',

View File

@ -0,0 +1,7 @@
module.exports = {
extends: 'eslint-config-ali/typescript/react',
rules: {
'no-unused-expressions': 1,
'react/no-multi-comp': 1,
}
}

View File

@ -10,7 +10,14 @@ export default class DwellTimer {
private event?: LocateEvent; private event?: LocateEvent;
constructor(private decide: (node: ParentalNode, event: LocateEvent) => void, private timeout: number = 500) {} private decide: (node: ParentalNode, event: LocateEvent) => void;
private timeout: number = 500;
constructor(decide: (node: ParentalNode, event: LocateEvent) => void, timeout: number = 500) {
this.decide = decide;
this.timeout = timeout;
}
focus(node: ParentalNode, event: LocateEvent) { focus(node: ParentalNode, event: LocateEvent) {
this.event = event; this.event = event;

View File

@ -1,4 +1,4 @@
import { DropLocation, ParentalNode, isLocationChildrenDetail, Node } from '@ali/lowcode-designer'; import { DropLocation, ParentalNode, isLocationChildrenDetail } from '@ali/lowcode-designer';
const IndentSensitive = 15; const IndentSensitive = 15;
export class IndentTrack { export class IndentTrack {

View File

@ -46,7 +46,13 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
return this._visible; return this._visible;
} }
constructor(readonly editor: IEditor, readonly at: string | symbol) { readonly editor: IEditor;
readonly at: string | symbol;
constructor(editor: IEditor, at: string | symbol) {
this.editor = editor;
this.at = at;
let inited = false; let inited = false;
const setup = async () => { const setup = async () => {
if (inited) { if (inited) {
@ -195,12 +201,10 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
} else { } else {
this.dwell.reset(); this.dwell.reset();
} }
} else { // FIXME: recreate new location
// FIXME: recreate new location } else if ((originLoc.detail as LocationChildrenDetail).near) {
if ((originLoc.detail as LocationChildrenDetail).near) { (originLoc.detail as LocationChildrenDetail).near = undefined;
(originLoc.detail as LocationChildrenDetail).near = undefined; this.dwell.reset();
this.dwell.reset();
}
} }
return; return;
} }
@ -213,12 +217,12 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
let { focusSlots } = pos; let { focusSlots } = pos;
let { node } = treeNode; let { node } = treeNode;
if (isDragNodeObject(dragObject)) { if (isDragNodeObject(dragObject)) {
const nodes = operationalNodes; const newNodes = operationalNodes;
let i = nodes.length; let i = newNodes.length;
let p: any = node; let p: any = node;
while (i-- > 0) { while (i-- > 0) {
if (contains(nodes[i], p)) { if (contains(newNodes[i], p)) {
p = nodes[i].parent; p = newNodes[i].parent;
} }
} }
if (p !== node) { if (p !== node) {

View File

@ -11,7 +11,10 @@ export interface ITreeBoard {
} }
export class TreeMaster { export class TreeMaster {
constructor(readonly designer: Designer) { readonly designer: Designer;
constructor(designer: Designer) {
this.designer = designer;
let startTime: any; let startTime: any;
designer.dragon.onDragstart(() => { designer.dragon.onDragstart(() => {
startTime = Date.now() / 1000; startTime = Date.now() / 1000;

View File

@ -218,7 +218,10 @@ export default class TreeNode {
return this._node; return this._node;
} }
constructor(readonly tree: Tree, node: Node) { readonly tree: Tree;
constructor(tree: Tree, node: Node) {
this.tree = tree;
this.document = node.document; this.document = node.document;
this.designer = this.document.designer; this.designer = this.document.designer;
this._node = node; this._node = node;

View File

@ -8,7 +8,10 @@ export class Tree {
readonly id: string; readonly id: string;
constructor(readonly document: DocumentModel) { readonly document: DocumentModel;
constructor(document: DocumentModel) {
this.document = document;
this.root = this.getTreeNode(document.rootNode); this.root = this.getTreeNode(document.rootNode);
this.id = document.id; this.id = document.id;
} }

View File

@ -3,8 +3,6 @@ import classNames from 'classnames';
import { observer, Title, Tip, globalContext, Editor } from '@ali/lowcode-editor-core'; import { observer, Title, Tip, globalContext, Editor } from '@ali/lowcode-editor-core';
import { IconArrowRight } from '../icons/arrow-right'; import { IconArrowRight } from '../icons/arrow-right';
import { IconEyeClose } from '../icons/eye-close'; import { IconEyeClose } from '../icons/eye-close';
import { IconLock } from '../icons/lock';
import { IconUnlock } from '../icons/unlock';
import { intl, intlNode } from '../locale'; import { intl, intlNode } from '../locale';
import TreeNode from '../tree-node'; import TreeNode from '../tree-node';
import { IconEye } from '../icons/eye'; import { IconEye } from '../icons/eye';
@ -14,7 +12,7 @@ import { IconRadioActive } from '../icons/radio-active';
import { IconRadio } from '../icons/radio'; import { IconRadio } from '../icons/radio';
import { createIcon } from '@ali/lowcode-utils'; import { createIcon } from '@ali/lowcode-utils';
function emitOutlineEvent(type: string, treeNode: TreeNode, rest?: object) { function emitOutlineEvent(type: string, treeNode: TreeNode, rest?: Record<string, unknown>) {
const editor = globalContext.get(Editor); const editor = globalContext.get(Editor);
const node = treeNode?.node; const node = treeNode?.node;
const npm = node?.componentMeta?.npm; const npm = node?.componentMeta?.npm;
@ -172,28 +170,28 @@ export default class TreeTitle extends Component<{
} }
} }
@observer // @observer
class LockBtn extends Component<{ treeNode: TreeNode }> { // class LockBtn extends Component<{ treeNode: TreeNode }> {
shouldComponentUpdate() { // shouldComponentUpdate() {
return false; // return false;
} // }
render() { // render() {
const { treeNode } = this.props; // const { treeNode } = this.props;
return ( // return (
<div // <div
className="tree-node-lock-btn" // className="tree-node-lock-btn"
onClick={(e) => { // onClick={(e) => {
e.stopPropagation(); // e.stopPropagation();
treeNode.setLocked(!treeNode.locked); // treeNode.setLocked(!treeNode.locked);
}} // }}
> // >
{treeNode.locked ? <IconLock /> : <IconUnlock />} // {treeNode.locked ? <IconLock /> : <IconUnlock />}
<Tip>{treeNode.locked ? intl('Unlock') : intl('Lock')}</Tip> // <Tip>{treeNode.locked ? intl('Unlock') : intl('Lock')}</Tip>
</div> // </div>
); // );
} // }
} // }
@observer @observer
class HideBtn extends Component<{ treeNode: TreeNode }> { class HideBtn extends Component<{ treeNode: TreeNode }> {

View File

@ -152,7 +152,7 @@ export default class TreeView extends Component<{ tree: Tree }> {
return ( return (
<div <div
className="lc-outline-tree" className="lc-outline-tree"
ref={(shell) => (this.shell = shell)} ref={(shell) => { this.shell = shell; }}
onMouseDownCapture={this.onMouseDown} onMouseDownCapture={this.onMouseDown}
onMouseOver={this.onMouseOver} onMouseOver={this.onMouseOver}
onClick={this.onClick} onClick={this.onClick}

View File

@ -13,6 +13,12 @@
height: 100%; height: 100%;
} }
.button-container{
position: absolute;
top: 0px;
right: 10px;
}
.editor-context-container{ .editor-context-container{
height: 100%; height: 100%;
width: 100%; width: 100%;

View File

@ -14,7 +14,7 @@ const TAB_KEY = {
const defaultEditorOption = { const defaultEditorOption = {
width: '100%', width: '100%',
height: '100%', height: '95%',
options: { options: {
readOnly: false, readOnly: false,
automaticLayout: true, automaticLayout: true,
@ -46,8 +46,6 @@ export default class SourceEditor extends Component<{
}> { }> {
private monocoEditor; private monocoEditor;
private monocoEditorCss;
private editorCmd; private editorCmd;
private editorJsRef = React.createRef(); private editorJsRef = React.createRef();
@ -56,12 +54,17 @@ export default class SourceEditor extends Component<{
private editorNode; private editorNode;
private editorParentNode; state = {
isFullScreen:false,
tabKey: TAB_KEY.JS_TAB,
isShowSaveBtn:true
};
// eslint-disable-next-line react/no-deprecated // eslint-disable-next-line react/no-deprecated
componentWillMount() { componentWillMount() {
const { editor } = this.props; const { editor } = this.props;
// 添加函数 // 添加函数
editor.on('sourceEditor.addFunction', (params: FunctionEventParam) => { editor.on('sourceEditor.addFunction', (params: FunctionEventParam) => {
this.callEditorEvent('sourceEditor.addFunction', params); this.callEditorEvent('sourceEditor.addFunction', params);
@ -72,7 +75,6 @@ export default class SourceEditor extends Component<{
this.callEditorEvent('sourceEditor.focusByFunction', params); this.callEditorEvent('sourceEditor.focusByFunction', params);
}); });
// 插件面板关闭事件,监听规则同上 // 插件面板关闭事件,监听规则同上
editor.on('skeleton.panel-dock.unactive', (pluginName) => { editor.on('skeleton.panel-dock.unactive', (pluginName) => {
if (pluginName == 'sourceEditor') { if (pluginName == 'sourceEditor') {
@ -93,7 +95,6 @@ export default class SourceEditor extends Component<{
componentDidMount() { componentDidMount() {
this.editorNode = this.editorJsRef.current; // 记录当前dom节点 this.editorNode = this.editorJsRef.current; // 记录当前dom节点
this.editorParentNode = this.editorNode.parentNode; // 记录父节点;
} }
/** /**
@ -268,11 +269,12 @@ export default class SourceEditor extends Component<{
if (newSchema != '' && JSON.stringify(newSchema) != oldSchemaStr) { if (newSchema != '' && JSON.stringify(newSchema) != oldSchemaStr) {
editor.get('designer').project.setSchema(newSchema); editor.get('designer').project.setSchema(newSchema);
successFlag && Message.success('保存成功')
} }
}; };
render() { render() {
const { selectTab, jsCode, css } = this.state; const { selectTab, jsCode, css ,isShowSaveBtn} = this.state;
const tabs = [ const tabs = [
{ tab: 'index.js', key: TAB_KEY.JS_TAB }, { tab: 'index.js', key: TAB_KEY.JS_TAB },
{ tab: 'style.css', key: TAB_KEY.CSS_TAB }, { tab: 'style.css', key: TAB_KEY.CSS_TAB },
@ -280,12 +282,13 @@ export default class SourceEditor extends Component<{
return ( return (
<div className="source-editor-container"> <div className="source-editor-container">
<Tab size="small" shape="wrapped" onChange={this.onTabChange} activeKey={selectTab}> <Tab size="small" shape="wrapped" onChange={this.onTabChange} activeKey={selectTab}>
{tabs.map((item) => ( {tabs.map((item) => (
<Tab.Item key={item.key} title={item.tab} /> <Tab.Item key={item.key} title={item.tab} />
))} ))}
</Tab> </Tab>
{ isShowSaveBtn && <div className="button-container"><Button type="primary" onClick={()=>this.saveSchema(successFlag)}></Button></div>}
<div style={{ height: '100%' }} className="editor-context-container"> <div style={{ height: '100%' }} className="editor-context-container">
<div id="jsEditorDom" className="editor-context" ref={this.editorJsRef}> <div id="jsEditorDom" className="editor-context" ref={this.editorJsRef}>

View File

@ -54,8 +54,12 @@ const transfrom = {
return `\n\t${functionName}(){\n\t}\n`; return `\n\t${functionName}(){\n\t}\n`;
}, },
setFunction2Schema(functionMap, schema) { setFunction2Schema(functionMap, schema){
const pageNode = schema.componentsTree[0]; let pageNode = schema.componentsTree[0];
// 先清除原有的schema的值
delete pageNode.state;
pageNode.lifeCycles = {};
pageNode.methods = {};
if (!pageNode) return ''; if (!pageNode) return '';
for (const key in functionMap) { for (const key in functionMap) {
if (key == 'state') { if (key == 'state') {

View File

@ -12,7 +12,9 @@ export default class RaxProvider extends Provider {
let App; let App;
const layoutConfig = this.getLayoutConfig(); const layoutConfig = this.getLayoutConfig();
if (!layoutConfig || !layoutConfig.componentName) { if (!layoutConfig || !layoutConfig.componentName) {
App = (props) => (RouterView ? createElement(RouterView, { ...props }) : null); App = (props) => {
return RouterView ? createElement(RouterView, { ...props }) : null;
};
return App; return App;
} }
const { componentName: layoutName, props: layoutProps } = layoutConfig; const { componentName: layoutName, props: layoutProps } = layoutConfig;
@ -25,7 +27,9 @@ export default class RaxProvider extends Provider {
RouterView ? createElement(RouterView, props) : null, RouterView ? createElement(RouterView, props) : null,
); );
} else { } else {
App = (props) => (RouterView ? createElement(RouterView, props) : null); App = (props) => {
return RouterView ? createElement(RouterView, props) : null;
};
} }
return App; return App;
} }

View File

@ -0,0 +1,9 @@
module.exports = {
extends: 'eslint-config-ali/typescript/react',
rules: {
'no-proto': 1,
'no-new-func': 1,
'no-shadow': 1,
'@typescript-eslint/no-unused-vars': 1,
}
}

View File

@ -43,6 +43,7 @@ export default class BaseEngine extends Component {
messages: PropTypes.object, messages: PropTypes.object,
__appHelper: PropTypes.object, __appHelper: PropTypes.object,
__components: PropTypes.object, __components: PropTypes.object,
// eslint-disable-next-line react/no-unused-prop-types
__componentsMap: PropTypes.object, __componentsMap: PropTypes.object,
__ctx: PropTypes.object, __ctx: PropTypes.object,
__schema: PropTypes.object, __schema: PropTypes.object,
@ -294,7 +295,6 @@ export default class BaseEngine extends Component {
__schema: schema, __schema: schema,
__appHelper: appHelper, __appHelper: appHelper,
__components: components, __components: components,
// __componentsMap: componentsMap,
} }
: {}; : {};
if (engine && engine.props.designMode) { if (engine && engine.props.designMode) {
@ -336,9 +336,8 @@ export default class BaseEngine extends Component {
} }
props.__id = schema.id; props.__id = schema.id;
let Child = null;
if (!isFileSchema(schema) && schema.children) { if (!isFileSchema(schema) && schema.children) {
Child = this.__createVirtualDom( this.__createVirtualDom(
isJSExpression(schema.children) ? parseExpression(schema.children, self) : schema.children, isJSExpression(schema.children) ? parseExpression(schema.children, self) : schema.children,
self, self,
{ {
@ -462,7 +461,7 @@ export default class BaseEngine extends Component {
return checkProps(function () { return checkProps(function () {
const args = {}; const args = {};
if (Array.isArray(params) && params.length) { if (Array.isArray(params) && params.length) {
params.map((item, idx) => { params.forEach((item, idx) => {
if (typeof item === 'string') { if (typeof item === 'string') {
args[item] = arguments[idx]; args[item] = arguments[idx];
} else if (item && typeof item === 'object') { } else if (item && typeof item === 'object') {

View File

@ -61,7 +61,7 @@ export default class CompEngine extends BaseEngine {
debug(`comp.componentWillUnmount - ${this.props.__schema.fileName}`); debug(`comp.componentWillUnmount - ${this.props.__schema.fileName}`);
} }
async componentDidCatch(e) { async componentDidCatch() {
super.componentDidCatch(...arguments); super.componentDidCatch(...arguments);
debug(`comp.componentDidCatch - ${this.props.__schema.fileName}`); debug(`comp.componentDidCatch - ${this.props.__schema.fileName}`);
} }

View File

@ -78,7 +78,7 @@ export default class PageEngine extends BaseEngine {
debug(`page.render - ${__schema.fileName}`); debug(`page.render - ${__schema.fileName}`);
const { const {
id, className, style, autoLoading, defaultHeight = 300, loading, id, className, style,
} = this.__parseData(__schema.props); } = this.__parseData(__schema.props);
const { Page } = __components; const { Page } = __components;
@ -88,9 +88,6 @@ export default class PageEngine extends BaseEngine {
<AppContext.Consumer> <AppContext.Consumer>
{(context) => { {(context) => {
this.context = context; this.context = context;
{
/* this.__generateCtx(currCtx); */
}
this.__render(); this.__render();
return ( return (
<AppContext.Provider <AppContext.Provider

View File

@ -40,7 +40,7 @@ export default class TempEngine extends BaseEngine {
debug(`temp.componentDidMount - ${this.props.__schema.fileName}`); debug(`temp.componentDidMount - ${this.props.__schema.fileName}`);
} }
componentDidUpdate(prevProps, prevState, snapshot) { componentDidUpdate() {
debug(`temp.componentDidUpdate - ${this.props.__schema.fileName}`); debug(`temp.componentDidUpdate - ${this.props.__schema.fileName}`);
} }

View File

@ -3,6 +3,7 @@ import { createElement, Component, forwardRef } from 'rax';
export default function (Comp) { export default function (Comp) {
class compWrapper extends Component { class compWrapper extends Component {
// eslint-disable-next-line no-useless-constructor
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
} }

View File

@ -157,7 +157,7 @@ export default class DataHelper {
const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest; const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest;
const csrfInput = document.getElementById('_csrf_token'); const csrfInput = document.getElementById('_csrf_token');
const _tb_token_ = csrfInput && csrfInput.value; const _tb_token_ = csrfInput && csrfInput.value;
asyncDataList.map(req => { asyncDataList.forEach(req => {
const { id, type, options } = req; const { id, type, options } = req;
if (!id || !type) return; if (!id || !type) return;
if (type === 'doServer') { if (type === 'doServer') {
@ -271,6 +271,7 @@ export default class DataHelper {
fetchOne(type, req) { fetchOne(type, req) {
const { options } = req; const { options } = req;
// eslint-disable-next-line prefer-const
let { uri, method = 'GET', headers, params, ...otherProps } = options; let { uri, method = 'GET', headers, params, ...otherProps } = options;
otherProps = otherProps || {}; otherProps = otherProps || {};
switch (type) { switch (type) {

View File

@ -50,8 +50,6 @@ const EXPRESSION_TYPE = {
JSSLOT: 'JSSlot', JSSLOT: 'JSSlot',
}; };
const EXPRESSION_REG = /^\{\{(\{.*\}|.*?)\}\}$/; const EXPRESSION_REG = /^\{\{(\{.*\}|.*?)\}\}$/;
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
const debug = Debug('utils:index'); const debug = Debug('utils:index');
const ENV = { const ENV = {
@ -180,6 +178,7 @@ export function fillObj(receiver = {}, ...suppliers) {
// 中划线转驼峰 // 中划线转驼峰
export function toHump(name) { export function toHump(name) {
// eslint-disable-next-line no-useless-escape
return name.replace(/\-(\w)/g, (all, letter) => letter.toUpperCase()); return name.replace(/\-(\w)/g, (all, letter) => letter.toUpperCase());
} }
// 驼峰转中划线 // 驼峰转中划线
@ -525,7 +524,7 @@ export function addCssTag(id, content) {
// 注册快捷 // 注册快捷
export function registShortCuts(config, appHelper) { export function registShortCuts(config, appHelper) {
const keyboardFilter = (keymaster.filter = (event) => { keymaster.filter = (event) => {
const eTarget = event.target || event.srcElement; const eTarget = event.target || event.srcElement;
const { tagName } = eTarget; const { tagName } = eTarget;
const isInput = !!(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA'); const isInput = !!(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
@ -541,7 +540,8 @@ export function registShortCuts(config, appHelper) {
return false; return false;
} }
return true; return true;
}); };
const keyboardFilter = keymaster.filter;
const ideMessage = appHelper.utils && appHelper.utils.ideMessage; const ideMessage = appHelper.utils && appHelper.utils.ideMessage;

View File

@ -8,7 +8,7 @@ interface IProps {
} }
interface IState { interface IState {
schema: object | null; schema: Record<string, unknown> | null;
hasError: boolean; hasError: boolean;
} }
@ -76,6 +76,6 @@ export default class LazyComponent extends Component<IProps, IState> {
loading={Loading ? <Loading /> : null} loading={Loading ? <Loading /> : null}
{...restProps} {...restProps}
/> />
) );
} }
} }

View File

@ -8,11 +8,13 @@ import LazyComponent from './components/LazyComponent';
export default class ReactProvider extends Provider { export default class ReactProvider extends Provider {
// 定制构造根组件的逻辑,如切换路由机制 // 定制构造根组件的逻辑,如切换路由机制
createApp() { createApp() {
let RouterView = this.getRouterView(); const RouterView = this.getRouterView();
let App: any; let App: any;
const layoutConfig = this.getLayoutConfig(); const layoutConfig = this.getLayoutConfig();
if (!layoutConfig || !layoutConfig.componentName) { if (!layoutConfig || !layoutConfig.componentName) {
App = (props: any) => (RouterView ? createElement(RouterView, { ...props }) : null); App = (props: any) => {
return (RouterView ? createElement(RouterView, { ...props }) : null);
};
return App; return App;
} }
const { componentName: layoutName, props: layoutProps } = layoutConfig; const { componentName: layoutName, props: layoutProps } = layoutConfig;
@ -25,7 +27,9 @@ export default class ReactProvider extends Provider {
RouterView ? createElement(RouterView, props) : null, RouterView ? createElement(RouterView, props) : null,
); );
} else { } else {
App = (props: any) => (RouterView ? createElement(RouterView, props) : null); App = (props: any) => {
return (RouterView ? createElement(RouterView, props) : null);
};
} }
return App; return App;
} }
@ -83,13 +87,14 @@ export default class ReactProvider extends Provider {
const appHelper = new AppHelper(); const appHelper = new AppHelper();
appHelper.set('utils', this.getUtils()); appHelper.set('utils', this.getUtils());
appHelper.set('constants', this.getConstants()); appHelper.set('constants', this.getConstants());
const self = this;
const RouterView = (props: any) => { const RouterView = (props: any) => {
return createElement(Router as any, { return createElement(Router as any, {
routes, routes,
components: this.getComponents(), components: self.getComponents(),
utils: this.getUtils(), utils: self.getUtils(),
appHelper, appHelper,
componentsMap: this.getComponentsMapObj(), componentsMap: self.getComponentsMapObj(),
...props, ...props,
}); });
}; };
@ -104,7 +109,10 @@ export default class ReactProvider extends Provider {
return this.getLazyElement(pageId); return this.getLazyElement(pageId);
} else { } else {
const lazyElement = createElement(LazyComponent as any, { const lazyElement = createElement(LazyComponent as any, {
getPageData: async () => await this.getPageData(pageId), getPageData: async () => {
const pageData = await this.getPageData(pageId);
return pageData;
},
key: pageId, key: pageId,
context: this, context: this,
...props, ...props,

View File

@ -56,7 +56,7 @@ export interface DataSourceItem {
type: string; type: string;
options: { options: {
uri: string; uri: string;
params: object; params: Record<string, unknown>;
method: string; method: string;
shouldFetch?: string; shouldFetch?: string;
willFetch?: string; willFetch?: string;
@ -121,6 +121,7 @@ export default class Provider {
} }
async(): Promise<IAppConfig> { async(): Promise<IAppConfig> {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
const appData: IAppData = await this.getAppData(); const appData: IAppData = await this.getAppData();
@ -216,11 +217,11 @@ export default class Provider {
throw new Error('Method called "getAppData" not implemented.'); throw new Error('Method called "getAppData" not implemented.');
} }
getPageData(pageId?: string): any { getPageData(): any {
throw new Error('Method called "getPageData" not implemented.'); throw new Error('Method called "getPageData" not implemented.');
} }
getLazyComponent(pageId: string, props: any): any { getLazyComponent(): any {
throw new Error('Method called "getLazyComponent" not implemented.'); throw new Error('Method called "getLazyComponent" not implemented.');
} }
@ -229,7 +230,7 @@ export default class Provider {
throw new Error('Method called "createApp" not implemented.'); throw new Error('Method called "createApp" not implemented.');
} }
runApp(App: any, config: IAppConfig) { runApp() {
throw new Error('Method called "runApp" not implemented.'); throw new Error('Method called "runApp" not implemented.');
} }

View File

@ -37,15 +37,15 @@ export default function runApp() {
const App = provider.createApp(); const App = provider.createApp();
provider.runApp(App, config); provider.runApp(App, config);
}).catch((err: Error) => { }).catch((err: Error) => {
console.error(err.message); console.error(err.message);
const { fallbackUI, afterCatch } = app.getErrorBoundary() || {}; const { fallbackUI, afterCatch } = app.getErrorBoundary() || {};
if (typeof afterCatch === 'function') { if (typeof afterCatch === 'function') {
afterCatch(err.message, err.stack); afterCatch(err.message, err.stack);
} }
if (!fallbackUI) { if (!fallbackUI) {
return; return;
} }
provider.runApp(fallbackUI, {}); provider.runApp(fallbackUI, {});
}); });
}); });
} }

View File

@ -105,6 +105,10 @@ export class StylePoint {
readonly id: string; readonly id: string;
constructor(level: number, id?: string) { constructor(level: number, id?: string) {
this.level = level;
if (id) {
this.id = id;
}
let placeholder: any; let placeholder: any;
if (id) { if (id) {
placeholder = document.head.querySelector(`style[data-id="${id}"]`); placeholder = document.head.querySelector(`style[data-id="${id}"]`);