fix: 🐛 bugs about deps

This commit is contained in:
春希 2020-07-21 13:38:02 +08:00
parent 84da70d9db
commit 1eabd506e3
7 changed files with 70 additions and 36 deletions

View File

@ -6,6 +6,7 @@
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
import { handleChildren } from '../utils/nodeToJSX';
import { uniqueArray } from '../utils/common';
import {
ChildNodeType,
@ -24,6 +25,7 @@ import {
IProjectSchema,
ISchemaParser,
IUtilItem,
INpmPackage,
} from '../types';
const defaultContainer: IContainerInfo = {
@ -36,17 +38,15 @@ const defaultContainer: IContainerInfo = {
};
class SchemaParser implements ISchemaParser {
public validate(schema: IBasicSchema): boolean {
validate(schema: IBasicSchema): boolean {
if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) {
throw new CompatibilityError(
`Not support schema with version [${schema.version}]`,
);
throw new CompatibilityError(`Not support schema with version [${schema.version}]`);
}
return true;
}
public parse(schemaSrc: IProjectSchema | string): IParseResult {
parse(schemaSrc: IProjectSchema | string): IParseResult {
// TODO: collect utils depends in JSExpression
const compDeps: Record<string, IExternalDependency> = {};
const internalDeps: Record<string, IInternalDependency> = {};
@ -64,7 +64,7 @@ class SchemaParser implements ISchemaParser {
}
// 解析三方组件依赖
schema.componentsMap.forEach(info => {
schema.componentsMap.forEach((info) => {
info.dependencyType = DependencyType.External;
info.importName = info.componentName;
compDeps[info.componentName] = info;
@ -73,8 +73,7 @@ class SchemaParser implements ISchemaParser {
let containers: IContainerInfo[];
// Test if this is a lowcode component without container
if (schema.componentsTree.length > 0) {
const firstRoot: IContainerNodeItem = schema
.componentsTree[0] as IContainerNodeItem;
const firstRoot: IContainerNodeItem = schema.componentsTree[0] as IContainerNodeItem;
if (!firstRoot.fileName) {
// 整个 schema 描述一个容器,且无根节点定义
@ -85,7 +84,7 @@ class SchemaParser implements ISchemaParser {
containers = [container];
} else {
// 普通带 1 到多个容器的 schema
containers = schema.componentsTree.map(n => {
containers = schema.componentsTree.map((n) => {
const subRoot = n as IContainerNodeItem;
const container: IContainerInfo = {
...subRoot,
@ -100,7 +99,7 @@ class SchemaParser implements ISchemaParser {
}
// 建立所有容器的内部依赖索引
containers.forEach(container => {
containers.forEach((container) => {
let type;
switch (container.containerType) {
case 'Page':
@ -126,22 +125,20 @@ class SchemaParser implements ISchemaParser {
});
// 分析容器内部组件依赖
containers.forEach(container => {
containers.forEach((container) => {
if (container.children) {
// const depNames = this.getComponentNames(container.children);
// container.deps = uniqueArray<string>(depNames)
// .map(depName => internalDeps[depName] || compDeps[depName])
// .filter(dep => !!dep);
container.deps = Object.keys(compDeps).map(
depName => compDeps[depName],
);
const depNames = this.getComponentNames(container.children);
container.deps = uniqueArray<string>(depNames, (i: string) => i)
.map((depName) => internalDeps[depName] || compDeps[depName])
.filter((dep) => !!dep);
// container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]);
}
});
// 分析路由配置
const routes = containers
.filter(container => container.containerType === 'Page')
.map(page => {
.filter((container) => container.containerType === 'Page')
.map((page) => {
const meta = page.meta as IPageMeta;
if (meta) {
return {
@ -156,20 +153,28 @@ class SchemaParser implements ISchemaParser {
});
const routerDeps = routes
.map(r => internalDeps[r.componentName] || compDeps[r.componentName])
.filter(dep => !!dep);
.map((r) => internalDeps[r.componentName] || compDeps[r.componentName])
.filter((dep) => !!dep);
// 分析 Utils 依赖
let utils: IUtilItem[];
if (schema.utils) {
utils = schema.utils;
utilsDeps = schema.utils
.filter(u => u.type !== 'function')
.map(u => u.content as IExternalDependency);
utilsDeps = schema.utils.filter((u) => u.type !== 'function').map((u) => u.content as IExternalDependency);
} else {
utils = [];
}
// 分析项目 npm 依赖
let npms: INpmPackage[] = [];
containers.forEach((con) => {
const p = (con.deps || [])
.map((dep) => (dep.dependencyType === DependencyType.External ? dep : null))
.filter((dep) => dep !== null);
npms.push(...((p as unknown) as INpmPackage[]));
});
npms = uniqueArray<INpmPackage>(npms, (i) => i.package);
return {
containers,
globalUtils: {
@ -187,13 +192,16 @@ class SchemaParser implements ISchemaParser {
css: schema.css,
constants: schema.constants,
i18n: schema.i18n,
packages: npms,
},
};
}
public getComponentNames(children: ChildNodeType): string[] {
getComponentNames(children: ChildNodeType): string[] {
return handleChildren<string>(children, {
node: (i: IComponentNodeItem) => [i.componentName],
}, {
rerun: true,
});
}
}

View File

@ -28,11 +28,11 @@ function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
deps.forEach(dep => {
if (dep.dependencyType === DependencyType.Internal) {
addDep(
`${(dep as IInternalDependency).moduleName}${dep.main || ''}`,
`${(dep as IInternalDependency).moduleName}${`/${dep.main}` || ''}`,
dep,
);
} else {
addDep(`${(dep as IExternalDependency).package}${dep.main || ''}`, dep);
addDep(`${(dep as IExternalDependency).package}${`/${dep.main}` || ''}`, dep);
}
});

View File

@ -73,6 +73,8 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
originTemplate: '@alifd/scaffold-lite-js',
};
ir.packages.forEach((packageInfo) => (packageJson.dependencies[packageInfo.package] = packageInfo.version));
next.chunks.push({
type: ChunkType.JSON,
fileType: FileType.JSON,

View File

@ -1,13 +1,15 @@
export interface INpmPackage {
package: string; // 组件包的名称
version: string; // 组件包的版本
}
/**
*
*
* @export
* @interface IExternalDependency
*/
export interface IExternalDependency extends IDependency {
package: string; // 组件包的名称
version: string; // 组件包的版本
}
export interface IExternalDependency extends INpmPackage, IDependency {}
export enum InternalDependencyType {
PAGE = 'pages',

View File

@ -5,6 +5,7 @@ import {
IDependency,
II18nMap,
IInternalDependency,
INpmPackage,
IUtilItem,
} from './index';
@ -42,6 +43,7 @@ export interface IProjectInfo {
css?: string;
constants?: Record<string, string>;
i18n?: II18nMap;
packages: INpmPackage[];
}
/**

View File

@ -22,7 +22,10 @@ export function upperCaseFirst(inputValue: string): string {
return changeCase.upperCaseFirst(inputValue);
}
export function uniqueArray<T>(arr: T[]) {
const uniqueItems = [...new Set<T>(arr)];
export function uniqueArray<T>(arr: T[], by: (i: T) => string) {
const map: Record<string, T> = {};
arr.forEach((item) => (map[by(item)] = item));
const uniqueKeys = [...new Set<string>(Object.keys(map))];
const uniqueItems = uniqueKeys.map((key) => map[key]);
return uniqueItems;
}

View File

@ -16,14 +16,26 @@ import { generateExpression } from './jsExpression';
// tslint:disable-next-line: no-empty
const noop = () => [];
const handleChildrenDefaultOptions = {
rerun: false,
};
export function handleChildren<T>(
children: ChildNodeType,
handlers: HandlerSet<T>,
options?: {
rerun?: boolean,
},
): T[] {
const opt = {
...handleChildrenDefaultOptions,
...(options || {}),
};
if (Array.isArray(children)) {
const list: ChildNodeItem[] = children as ChildNodeItem[];
return list
.map(child => handleChildren(child, handlers))
.map(child => handleChildren(child, handlers, opt))
.reduce((p, c) => p.concat(c), []);
} else if (typeof children === 'string') {
const handler = handlers.string || handlers.common || noop;
@ -33,7 +45,12 @@ export function handleChildren<T>(
return handler(children as IJSExpression);
} else {
const handler = handlers.node || handlers.common || noop;
return handler(children as IComponentNodeItem);
let curRes = handler(children as IComponentNodeItem);
if (opt.rerun && children.children) {
const childRes = handleChildren(children.children, handlers, opt);
curRes = curRes.concat(childRes || []);
}
return curRes;
}
}