diff --git a/packages/demo/public/preview.html b/packages/demo/public/preview.html index 34c8cf86c..c8f2cfdcb 100644 --- a/packages/demo/public/preview.html +++ b/packages/demo/public/preview.html @@ -16,5 +16,6 @@ +
diff --git a/packages/demo/src/app/config/app.js b/packages/demo/src/app/config/app.ts similarity index 55% rename from packages/demo/src/app/config/app.js rename to packages/demo/src/app/config/app.ts index c1ad5b57c..6562cebbf 100644 --- a/packages/demo/src/app/config/app.js +++ b/packages/demo/src/app/config/app.ts @@ -1,15 +1,15 @@ export default { sdkVersion: '1.0.3', - historyMode: 'hash', // 浏览器路由:brower 哈希路由:hash - constainerId: 'app', + history: 'hash', // 浏览器路由:brower 哈希路由:hash + containerId: 'lce-container', layout: { componentName: 'BasicLayout', props: { name: '低代码引擎预览 demo', logo: { - src: 'https://img.alicdn.com/tfs/TB1kAfWyrY1gK0jSZTEXXXDQVXa-75-33.png', - width: 40, - height: 20, + src: 'https://img.alicdn.com/tfs/TB1L.1QAeL2gK0jSZFmXXc7iXXa-90-90.png', + width: 25, + height: 25, }, }, }, diff --git a/packages/demo/src/app/config/components.js b/packages/demo/src/app/config/components.js deleted file mode 100644 index 91aef7993..000000000 --- a/packages/demo/src/app/config/components.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * 内置组件 - */ -import Engine from '@ali/iceluna-sdk/lib/engine'; -import Page from '@ali/iceluna-sdk/lib/engine/pageEngine' -import Div from '@ali/iceluna-comp-div'; - -export default { - Engine, - Page, - Div, -} diff --git a/packages/demo/src/app/config/components.ts b/packages/demo/src/app/config/components.ts new file mode 100644 index 000000000..3c4d25558 --- /dev/null +++ b/packages/demo/src/app/config/components.ts @@ -0,0 +1,5 @@ +/** + * 内置组件 + */ + +export default {}; diff --git a/packages/demo/src/app/config/componentsMap.js b/packages/demo/src/app/config/componentsMap.ts similarity index 100% rename from packages/demo/src/app/config/componentsMap.js rename to packages/demo/src/app/config/componentsMap.ts diff --git a/packages/demo/src/app/config/utils.js b/packages/demo/src/app/config/constants.ts similarity index 100% rename from packages/demo/src/app/config/utils.js rename to packages/demo/src/app/config/constants.ts diff --git a/packages/demo/src/app/config/utils.ts b/packages/demo/src/app/config/utils.ts new file mode 100644 index 000000000..ff8b4c563 --- /dev/null +++ b/packages/demo/src/app/config/utils.ts @@ -0,0 +1 @@ +export default {}; diff --git a/packages/demo/src/app/index.ts b/packages/demo/src/app/index.ts index 2cfc99a6b..f4df24866 100644 --- a/packages/demo/src/app/index.ts +++ b/packages/demo/src/app/index.ts @@ -1,22 +1,20 @@ -import { boot, run } from '@ali/lowcode-runtime'; +import { app } from '@ali/lowcode-runtime'; import Renderer from '@ali/lowcode-react-renderer'; import FusionLoading from './plugins/loading/fusion'; import BasicLayout from './layouts/BasicLayout'; -import provider from './plugins/provider'; +import Preview from './plugins/provider'; // 注册渲染模块 -boot.registerRenderer(Renderer); +app.registerRenderer(Renderer); // 注册布局组件,可注册多个 -boot.registerLayout('BasicLayout', BasicLayout); +app.registerLayout('BasicLayout', BasicLayout); // 注册页面 Loading -boot.registerLoading(FusionLoading); +app.registerLoading(FusionLoading); -const appProvider = provider.create('lowcode_demo'); // 入参为应用唯一标识 +// appKey:应用唯一标识 +app.registerProvider(Preview); -// 异步加载应用配置 -appProvider.then(({ App, config }) => { - // 启动应用 - run(App, config); -}); +// 启动应用 +app.run(); diff --git a/packages/demo/src/app/layouts/BasicLayout/index.less b/packages/demo/src/app/layouts/BasicLayout/index.scss similarity index 75% rename from packages/demo/src/app/layouts/BasicLayout/index.less rename to packages/demo/src/app/layouts/BasicLayout/index.scss index 000abd1c8..a8fe9848a 100644 --- a/packages/demo/src/app/layouts/BasicLayout/index.less +++ b/packages/demo/src/app/layouts/BasicLayout/index.scss @@ -1,4 +1,4 @@ -@header-height: 52px; +$header-height: 52px; .avatar { width: 24px; @@ -10,13 +10,13 @@ .basic-shell { min-height: 100vh; .next-shell-header { - height: @header-height; + height: $header-height; } .next-shell-main { flex: 1; display: flex; flex-flow: column; - min-height: calc(100% - @header-height); + min-height: calc(100% - $header-height); .next-shell-sub-main { flex: 1; } diff --git a/packages/demo/src/app/layouts/BasicLayout/index.js b/packages/demo/src/app/layouts/BasicLayout/index.tsx similarity index 70% rename from packages/demo/src/app/layouts/BasicLayout/index.js rename to packages/demo/src/app/layouts/BasicLayout/index.tsx index 6a51fdc75..3785e8339 100644 --- a/packages/demo/src/app/layouts/BasicLayout/index.js +++ b/packages/demo/src/app/layouts/BasicLayout/index.tsx @@ -1,15 +1,22 @@ import { Search, Icon, Shell } from '@alifd/next'; -import './index.less'; +import './index.scss'; -// eslint-disable-next-line react/prop-types -export default ({ name, children, logo }) => ( - +export default ({ + name, + children, + logo, +}: { + name: string; + children: any; + logo: { src: string; width: number; height: number }; +}) => ( + logo {name} - + diff --git a/packages/demo/src/app/plugins/loading/deep/index.less b/packages/demo/src/app/plugins/loading/deep/index.less deleted file mode 100644 index 2b59ea5ef..000000000 --- a/packages/demo/src/app/plugins/loading/deep/index.less +++ /dev/null @@ -1,11 +0,0 @@ -.recore-loading { - width: 48px; - height: 48px; - background: url(https://g.alicdn.com/uxcore/pic/loading.svg) center no-repeat; - background-size: contain; - position: fixed; - top: 50%; - left: 50%; - margin-top: -24px; - margin-left: -24px; -} diff --git a/packages/demo/src/app/plugins/loading/deep/index.tsx b/packages/demo/src/app/plugins/loading/deep/index.tsx deleted file mode 100644 index 02b2fc692..000000000 --- a/packages/demo/src/app/plugins/loading/deep/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import './index.less'; - -export default () =>
; diff --git a/packages/demo/src/app/plugins/loading/fusion/index.less b/packages/demo/src/app/plugins/loading/fusion/index.scss similarity index 100% rename from packages/demo/src/app/plugins/loading/fusion/index.less rename to packages/demo/src/app/plugins/loading/fusion/index.scss diff --git a/packages/demo/src/app/plugins/loading/fusion/index.tsx b/packages/demo/src/app/plugins/loading/fusion/index.tsx index e61bfd9f0..73de48418 100644 --- a/packages/demo/src/app/plugins/loading/fusion/index.tsx +++ b/packages/demo/src/app/plugins/loading/fusion/index.tsx @@ -1,4 +1,4 @@ import { Loading } from '@alifd/next'; -import './index.less'; +import './index.scss'; export default () => ; diff --git a/packages/demo/src/app/plugins/provider.ts b/packages/demo/src/app/plugins/provider.ts index fc56ece03..3e5458bd7 100644 --- a/packages/demo/src/app/plugins/provider.ts +++ b/packages/demo/src/app/plugins/provider.ts @@ -1,45 +1,45 @@ -import { createElement } from 'react'; -import { Provider, boot, Router } from '@ali/lowcode-runtime'; +import { ReactProvider, Utils } from '@ali/lowcode-runtime'; import appConfig from '../config/app'; import builtInComps from '../config/components'; import componentsMap from '../config/componentsMap'; -import util from '../config/utils'; -import { buildComponents } from './utils'; +import constants from '../config/constants'; +import utils from '../config/utils'; // 定制加载应用配置的逻辑 -class PreviewProvider extends Provider { +export default class Preview extends ReactProvider { // 定制获取、处理应用配置(组件、插件、路由模式、布局等)的逻辑 - async getAppData(appkey: string, restOptions?: any): Promise { - const { historyMode, layout, constainerId } = appConfig; + async getAppData(): Promise { + const { history, layout, containerId } = appConfig; const appSchemaStr: any = localStorage.getItem('lce-dev-store'); - const appSchema = JSON.parse(appSchemaStr || ''); - const history = { - mode: historyMode || 'hash', - basement: '/', - }; - this.layout = layout; + if (!appSchemaStr) { + return; + } + const appSchema = JSON.parse(appSchemaStr); + if (!appSchema) { + return; + } const routes: any = {}; - appSchema.componentsTree.forEach((page: any, idx: number) => { + appSchema.componentsTree.forEach((page: any) => { if (!page.fileName) { return; } const pageId = page.fileName; routes[pageId] = `/${pageId}`; }); - this.routerConfig = routes; - this.componentsMap = componentsMap; - this.globalComponents = { ...builtInComps, ...buildComponents({ '@alifd/next': 'Next' }, componentsMap) }; - this.globalUtils = util; return { history, - globalComponents: this.globalComponents, - globalUtils: this.globalUtils, - constainerId, + layout, + routes, + containerId, + components: { ...builtInComps, ...Utils.buildComponents({ '@alifd/next': 'Next' }, componentsMap) }, + componentsMap, + utils: utils, + constants, }; } // 定制获取、处理页面 schema 的逻辑 - async getPageData(pageId: string, restOptions?: any) { + async getPageData(pageId: string) { const appSchemaStr = localStorage.getItem('lce-dev-store'); const appSchema = JSON.parse(appSchemaStr || ''); const idx = appSchema.componentsTree.findIndex( @@ -48,67 +48,4 @@ class PreviewProvider extends Provider { const schema = appSchema.componentsTree[idx]; return schema; } - - // 定制构造根组件的逻辑,如切换路由机制 - createApp() { - if (!this.routerConfig) { - return; - } - const routes: Array<{ path: string; children: any; exact: boolean; keepAlive: boolean }> = []; - let homePageId = ''; - Object.keys(this.routerConfig).forEach((pageId: string, idx: number) => { - if (!pageId) { - return; - } - const path = this.routerConfig[pageId]; - if (idx === 0 || path === '/') { - homePageId = pageId; - } - routes.push({ - path, - children: (props: any) => this.getLazyComponent(pageId, props), - exact: true, - keepAlive: true, - }); - }); - if (homePageId) { - routes.push({ - path: '**', - children: (props: any) => this.getLazyComponent(homePageId, { ...props }), - exact: true, - keepAlive: true, - }); - } - const RouterView = (props: any) => { - return createElement(Router as any, { - routes, - components: this.globalComponents, - utils: this.globalUtils, - componentsMap: this.componentsMap, - ...props, - }); - }; - let App; - if (!this.layout || !(this.layout as any).componentName) { - App = (props: any) => createElement(RouterView, { ...props }); - return App; - } - const { componentName: layoutName, props: layoutProps } = this.layout as any; - const Layout = boot.getLayout(layoutName); - if (Layout) { - App = (props: any) => - createElement( - Layout, - { - ...layoutProps, - }, - RouterView({ props }), - ); - } else { - App = (props: any) => createElement(RouterView, props); - } - return App; - } } - -export default new PreviewProvider(); diff --git a/packages/demo/src/index.ts b/packages/demo/src/index.ts index 27a6639b2..eae3b122e 100644 --- a/packages/demo/src/index.ts +++ b/packages/demo/src/index.ts @@ -1 +1 @@ -import "./editor" +import './editor'; diff --git a/packages/demo/src/preview.ts b/packages/demo/src/preview.ts index 168ff510c..36c3352e9 100644 --- a/packages/demo/src/preview.ts +++ b/packages/demo/src/preview.ts @@ -1 +1 @@ -import "./app"; +import './app'; diff --git a/packages/material-parser/package.json b/packages/material-parser/package.json index bd0c6f7a8..f061f4525 100644 --- a/packages/material-parser/package.json +++ b/packages/material-parser/package.json @@ -20,6 +20,7 @@ "jest-watch-typeahead": "^0.3.1", "js-yaml": "^3.13.1", "json-schema-to-typescript": "^8.2.0", + "tslib": "^1.11.1", "typescript": "^3.8.3" }, "scripts": { @@ -47,6 +48,7 @@ "@babel/parser": "^7.8.4", "@babel/traverse": "^7.8.4", "@babel/types": "^7.8.3", + "ast-types": "^0.13.3", "cross-spawn-promise": "^0.10.2", "debug": "^4.1.1", "fs-extra": "^8.1.0", diff --git a/packages/material-parser/scripts/transform.js b/packages/material-parser/scripts/transform.js index b07f55aa1..2f9416675 100644 --- a/packages/material-parser/scripts/transform.js +++ b/packages/material-parser/scripts/transform.js @@ -17,7 +17,7 @@ const tsPath = path.resolve(__dirname, '../src/otter-core/schema/types.ts'); ajv.compile(schema); fs.writeFileSync(JsonPath, JSON.stringify(schema, null, 2), 'utf-8'); console.log('yaml file is successfully transformed into json'); - const ts = await compile(schema, 'IComponentMaterial'); + const ts = await compile(schema, 'ComponentMeta'); fs.writeFileSync(tsPath, ts); console.log('schema.d.ts is successfully generated'); } catch (e) { diff --git a/packages/material-parser/src/Materialize.ts b/packages/material-parser/src/Materialize.ts deleted file mode 100644 index 06928f804..000000000 --- a/packages/material-parser/src/Materialize.ts +++ /dev/null @@ -1,48 +0,0 @@ -import LocalAccesser from './accesser/LocalAccesser'; -import OnlineAccesser from './accesser/OnlineAccesser'; -import { IComponentMaterial } from './otter-core'; -import { IAccesser, IMaterializeOptions } from './types'; - -/** - * 物料化(将普通组件包装为可接入和可流通的物料组件的过程,称为物料化)运行于 node 端 - * @class Materialize - */ -class Materialize { - /** - * 物料化配置项 - * @private - * @type {IMaterializeOptions} - * @memberof Materialize - */ - private options: IMaterializeOptions; - - /** - * 接入器 - * @private - * @type {IAccesser} - * @memberof Materialize - */ - private accesser?: IAccesser; - - constructor(options: IMaterializeOptions) { - this.options = options; - } - - /** - * 开始物料化 - * - * @returns {Promise} - * @memberof Materialize - */ - public async start(): Promise { - // 分发请求到对应接入器 - if (this.options.accesser === 'local') { - this.accesser = new LocalAccesser(this.options); - } else { - this.accesser = new OnlineAccesser(this.options); - } - return this.accesser.access(); - } -} - -export default Materialize; diff --git a/packages/material-parser/src/accesser/BaseAccesser.ts b/packages/material-parser/src/accesser/BaseAccesser.ts deleted file mode 100644 index 40269a88d..000000000 --- a/packages/material-parser/src/accesser/BaseAccesser.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { IComponentMaterial } from '../otter-core'; -import { IAccesser, IMaterializeOptions } from '../types'; - -/** - * 接入器模板基类 - * @abstract - * @class BaseAccesser - * @implements {IAccesser} - */ -abstract class BaseAccesser implements IAccesser { - /** - * 物料化配置项 - * @protected - * @type {IMaterializeOptions} - * @memberof BaseAccesser - */ - protected options: IMaterializeOptions; - - constructor(options: IMaterializeOptions) { - this.options = options; - } - - public abstract access(): Promise; -} - -export default BaseAccesser; diff --git a/packages/material-parser/src/accesser/LocalAccesser.ts b/packages/material-parser/src/accesser/LocalAccesser.ts deleted file mode 100644 index e3bc885ce..000000000 --- a/packages/material-parser/src/accesser/LocalAccesser.ts +++ /dev/null @@ -1,78 +0,0 @@ -import Generator from '../generator/Generator'; -import { debug, IComponentMaterial } from '../otter-core'; -import BaseParser from '../parser/BaseParser'; -import ReactParser from '../parser/ReactParser'; -import Scanner from '../scanner/Scanner'; -import { IMaterialParsedModel, IMaterialScanModel, IParser } from '../types'; -import BaseAccesser from './BaseAccesser'; - -const log = debug.extend('mat'); - -/** - * 本地接入器 - * @class LocalAccesser - * @extends {BaseAccesser} - */ -class LocalAccesser extends BaseAccesser { - /** - * 扫描器实例 - * @private - * @type {Scanner} - * @memberof LocalAccesser - */ - private scanner!: Scanner; - - /** - * 解析器实例 - * @private - * @type {IParser} - * @memberof LocalAccesser - */ - private parser!: IParser; - - /** - * 生成器实例 - * @private - * @type {Generator} - * @memberof LocalAccesser - */ - private generator!: Generator; - - public async access(): Promise { - await this.init(); - // 开始扫描 - const matScanModel: IMaterialScanModel = await this.scanner.scan(); - log('matScanModel', matScanModel); - // 开始解析 - const matParsedModels: IMaterialParsedModel[] = await this.parser.parse( - matScanModel, - ); - log('matParsedModels', matParsedModels); - // 开始生产 - const material: IComponentMaterial = await this.generator.generate( - matScanModel, - matParsedModels, - ); - log('material', material); - return material; - } - - /** - * 初始化 - * @private - * @returns {Promise} - * @memberof LocalAccesser - */ - private async init(): Promise { - const options = this.options; - this.scanner = new Scanner(options); - const ecology = await BaseParser.recognizeEcology(options); - if (ecology === 'react') { - // debugger; - this.parser = new ReactParser(options); - this.generator = new Generator(options); - } - } -} - -export default LocalAccesser; diff --git a/packages/material-parser/src/accesser/OnlineAccesser.ts b/packages/material-parser/src/accesser/OnlineAccesser.ts deleted file mode 100644 index 160f4d20b..000000000 --- a/packages/material-parser/src/accesser/OnlineAccesser.ts +++ /dev/null @@ -1,121 +0,0 @@ -import spawn from 'cross-spawn-promise'; -import { ensureDir, ensureFile, writeFile } from 'fs-extra'; -import { join } from 'path'; -import semver from 'semver'; -import uuid from 'short-uuid'; -import { debug, IComponentMaterial, OtterError } from '../otter-core'; -import { IMaterializeOptions } from '../types'; -import BaseAccesser from './BaseAccesser'; -import LocalAccesser from './LocalAccesser'; - -const log = debug.extend('mat'); - -/** - * 在线接入 - * @class OnlineAccesser - * @extends {BaseAccesser} - */ -class OnlineAccesser extends BaseAccesser { - /** - * 临时目录 - * - * @private - * @type {string} - * @memberof OnlineAccesser - */ - private tempDir: string = ''; - - public async access(): Promise { - // 创建临时目录 - this.tempDir = await this.createTempDir(); - // 创建组件包 - const { name, version } = this.getPkgNameAndVersion(this.options.entry); - await this.createFakePackage({ - pkgName: name, - pkgVersion: version, - }); - // 将问题转化为本地物料化场景 - const options: IMaterializeOptions = { - cwd: this.tempDir, - entry: join(this.tempDir, 'node_modules', name), - accesser: 'local', - isExportedAsMultiple: this.options.isExportedAsMultiple, - }; - const localAccesser = new LocalAccesser(options); - return localAccesser.access(); - } - - /** - * 创建组件包 - * - * @private - * @param {{ - * pkgName: string; - * pkgVersion: string; - * }} params - * @returns {Promise} - * @memberof OnlineAccesser - */ - private async createFakePackage(params: { - pkgName: string; - pkgVersion: string; - }): Promise { - // 创建临时组件包 - const tempDir = this.tempDir; - const pkgJsonFilePath = join(tempDir, 'package.json'); - await ensureFile(pkgJsonFilePath); - await writeFile( - pkgJsonFilePath, - JSON.stringify({ - name: params.pkgName, - version: params.pkgVersion, - dependencies: { - [params.pkgName]: params.pkgVersion, - }, - }), - ); - // 安装依赖 - const npmClient = this.options.npmClient || 'tnpm'; - await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: tempDir } as any); - } - - /** - * 创建临时目录 - * - * @private - * @returns {Promise} 返回临时文件夹路径 - * @memberof LocalGenerator - */ - private async createTempDir(): Promise { - const tempDirName = uuid.generate(); - const tempDir = join(__dirname, '../../node_modules/.temp/', tempDirName); - await ensureDir(tempDir); - log('create temp dir successfully', tempDir); - return tempDir; - } - - /** - * 分离物料组件名称和版本号 - * - * @private - * @param {string} pkgNameWithVersion - * @returns {{ [key: string]: any }} - * @memberof OnlineAccesser - */ - private getPkgNameAndVersion( - pkgNameWithVersion: string, - ): { [key: string]: any } { - const matches = pkgNameWithVersion.match(/(@\d+\.\d+\.\d+)$/); - if (!matches) { - throw new OtterError(`Illegal semver version: ${pkgNameWithVersion}`); - } - const semverObj = semver.coerce(matches[0]); - const name = pkgNameWithVersion.replace(matches[0], ''); - return { - version: semverObj && semverObj.version, - name, - }; - } -} - -export default OnlineAccesser; diff --git a/packages/material-parser/src/extensions/MatConfigManifest.ts b/packages/material-parser/src/extensions/MatConfigManifest.ts deleted file mode 100644 index 491fdce8f..000000000 --- a/packages/material-parser/src/extensions/MatConfigManifest.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { writeFile } from 'fs-extra'; -import { IComponentMaterial } from '../otter-core'; - -/** - * 配置 manifest(物料化场景下可以使用此扩展点) - * - 扩展点名称:mat:config:manifest - * - 对应 Studio 所处状态:进入 就绪态 前 - * - * @export - * @param {{ - * manifestObj: IComponentMaterial, - * manifestFilePath: string, - * }} params - * @returns {Promise<{ - * manifestJS: string, - * manifestFilePath: string, - * manifestObj: IComponentMaterial, - * }>} - */ -export default async function matConfigManifest(params: { - manifestObj: IComponentMaterial; - manifestFilePath: string; -}): Promise<{ - manifestJSON: string; - manifestFilePath: string; - manifestObj: IComponentMaterial; -}> { - const manifestJSON = JSON.stringify(params.manifestObj); - - await writeFile(params.manifestFilePath, manifestJSON); - - return Promise.resolve({ - manifestJSON, - manifestObj: params.manifestObj, - manifestFilePath: params.manifestFilePath, - }); -} diff --git a/packages/material-parser/src/extensions/index.ts b/packages/material-parser/src/extensions/index.ts deleted file mode 100644 index d35c1b720..000000000 --- a/packages/material-parser/src/extensions/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ExtensionName } from '../types'; -import MatConfigManifest from './MatConfigManifest'; - -export default { - [ExtensionName.CONFIGMANIFEST]: MatConfigManifest, -}; diff --git a/packages/material-parser/src/generate.ts b/packages/material-parser/src/generate.ts new file mode 100644 index 000000000..6c4f0b140 --- /dev/null +++ b/packages/material-parser/src/generate.ts @@ -0,0 +1,59 @@ +import { debug, ComponentMeta } from './otter-core'; +import { IMaterialParsedModel, IMaterialScanModel } from './types'; + +const log = debug.extend('mat'); + +export default async function( + matScanModel: IMaterialScanModel, + matParsedModels: IMaterialParsedModel[], +): Promise { + const containerList = []; + for (const matParsedModel of matParsedModels) { + // TODO 可以开放扩展点让上层使用者指定导出哪些组件或者不导出哪些组件 + // 默认排除掉 defaultExportName 为空的组件 + if (!matParsedModel.componentName) { + log('skip'); + continue; + } + // 组装 manifest + const manifest: any = await genManifest(matScanModel, matParsedModel); + + containerList.push(manifest); + } + + return containerList; +} + +/** + * 生成 manifest + * + * @param {IMaterialParsedModel} matParsedModel + * @returns {Promise< + * manifestObj: ComponentMeta, // 组件描述 + * >} + * @memberof LocalGenerator + */ +export async function genManifest( + matScanModel: IMaterialScanModel, + matParsedModel: IMaterialParsedModel, +): Promise { + const manifestObj: Partial = { + componentName: matParsedModel.componentName, + title: matScanModel.pkgName, + docUrl: '', + screenshot: '', + npm: { + package: matScanModel.pkgName, + version: matScanModel.pkgVersion, + exportName: matParsedModel.componentName, + main: matScanModel.mainFilePath, + destructuring: false, + subName: '', + }, + }; + + // 填充 props + manifestObj.props = matParsedModel.props; + // 执行扩展点 + return manifestObj as ComponentMeta; +} diff --git a/packages/material-parser/src/generator/Generator.ts b/packages/material-parser/src/generator/Generator.ts deleted file mode 100644 index bec97c827..000000000 --- a/packages/material-parser/src/generator/Generator.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { dirname, join } from 'path'; -import defaultExtension from '../extensions'; -import { debug, IComponentMaterial, PropsSection } from '../otter-core'; -import { - IGenerator, - IMaterializeOptions, - IMaterialParsedModel, - IMaterialScanModel, -} from '../types'; - -const log = debug.extend('mat'); - -/** - * 用于物料工作台 - */ -class Generator implements IGenerator { - /** - * 物料化配置项 - * @protected - * @type {IMaterializeOptions} - * @memberof BaseGenerator - */ - /** - * 物料化配置项 - * @protected - * @type {IMaterializeOptions} - * @memberof BaseGenerator - */ - protected options!: IMaterializeOptions; - - constructor(options: IMaterializeOptions) { - this.options = options; - } - - public async generate( - matScanModel: IMaterialScanModel, - matParsedModels: IMaterialParsedModel[], - ): Promise { - // const model: IMaterialinSchema = {} as any; - // 标记协议版本号 - // model.version = '1.0.0'; - // 组装 pkgInfo - // model.pkgInfo = pkgInfo; - const containerList = []; - for (const matParsedModel of matParsedModels) { - // TODO 可以开放扩展点让上层使用者指定导出哪些组件或者不导出哪些组件 - // 默认排除掉 defaultExportName 为空的组件 - if ( - !matParsedModel.defaultExportName || - !matParsedModel.defaultExportName.length - ) { - log('skip', matParsedModel.filePath); - continue; - } - // 组装 manifest - const manifest: any = await this.genManifest( - matScanModel, - matParsedModel, - ); - - containerList.push(manifest); - } - - // const components: IMaterialinComponent[] = bundle.bundleObj.components; - // Object.keys(bundle.bundleObj.Modules).forEach(key => { - // const { origin, manifest } = bundle.bundleObj.Modules[key]; - // const component: IMaterialinComponent = { - // componentName: key, - // origin, - // manifest, - // }; - // components.push(component); - // }); - // model.components = components; - // log('materialsModel', JSON.stringify(bundle.bundleObj)); - - return containerList; - } - - /** - * 生成 manifest - * - * @param {IMaterialParsedModel} matParsedModel - * @returns {Promise<{ - * manifestFilePath: string, // manifest 文件路径 - * manifestJS: string, // manifest 文件内容 - * manifestObj: IMaterialinManifest, // manifest 文件对象 - * }>} - * @memberof LocalGenerator - */ - public async genManifest( - matScanModel: IMaterialScanModel, - matParsedModel: IMaterialParsedModel, - ): Promise<{ - manifestFilePath: string; // manifest 文件路径 - manifestObj: IComponentMaterial; // manifest 文件对象 - }> { - const manifestObj: Partial = { - // componentName: matParsedModel.defaultExportName, - title: matScanModel.pkgName, - docUrl: '', - screenshot: '', - npm: { - package: matScanModel.pkgName, - version: matScanModel.pkgVersion, - exportName: '', // matParsedModel.defaultExportName, - main: matScanModel.mainEntry, - destructuring: false, - subName: '', - }, - }; - - const defaultManifestFilePath = join( - dirname(matParsedModel.filePath), - './manifest.json', - ); - - // 填充 props - manifestObj.props = matParsedModel.props; - // 执行扩展点 - const manifest: any = await this.executeExtensionPoint( - 'mat:config:manifest', - { - manifestObj, - manifestFilePath: defaultManifestFilePath, - }, - ); - return { - manifestObj: manifest.manifestObj, - manifestFilePath: manifest.manifestFilePath, - }; - } - - /** - * 填充 props - * - * @public - * @param {IMaterialParsedModel} matParsedModel - * @returns {IMaterialinProp[]} - * @memberof BaseGenerator - */ - public populateProps( - matParsedModel: IMaterialParsedModel, - ): PropsSection['props'] { - // @ts-ignore - return matParsedModel.props; - } - - /** - * 执行扩展点 - * @param {string} extName 扩展点名称 - * @param {...any[]} args 参数 - * @returns {Promise} - * @memberof BaseGenerator - */ - public async executeExtensionPoint( - extName: string, - ...args: any[] - ): Promise { - const options = this.options; - const optionsExtensions: any = options.extensions; - const defaultExtensions: any = defaultExtension; - - const ext: any = - optionsExtensions && optionsExtensions[extName] - ? optionsExtensions[extName] - : defaultExtensions[extName]; - if (!ext) { - throw new Error(`Unsupported extension point: ${extName}`); - } - return ext(...args); - } -} - -export default Generator; diff --git a/packages/material-parser/src/index.ts b/packages/material-parser/src/index.ts index d38da4098..267a83629 100644 --- a/packages/material-parser/src/index.ts +++ b/packages/material-parser/src/index.ts @@ -1,8 +1,26 @@ -import Materialize from './Materialize'; - export { default as validate } from './validate'; export { default as schema } from './validate/schema.json'; export * from './types'; -export default Materialize; +import { IMaterializeOptions } from './types'; +import { ComponentMeta } from './otter-core'; +import scan from './scan'; +import generate from './generate'; +import parse from './parse'; +import localize from './localize'; + +export default async function(options: IMaterializeOptions): Promise { + const { accesser = 'local' } = options; + if (accesser === 'online') { + const entry = await localize(options); + options.entry = entry; + } + const scanedModel = await scan(options); + const parsedModel = await parse({ + filePath: scanedModel.entryFilePath, + fileContent: scanedModel.entryFileContent, + }); + const result = await generate(scanedModel, parsedModel); + return result; +} diff --git a/packages/material-parser/src/localize.ts b/packages/material-parser/src/localize.ts new file mode 100644 index 000000000..fb59a795d --- /dev/null +++ b/packages/material-parser/src/localize.ts @@ -0,0 +1,100 @@ +import spawn from 'cross-spawn-promise'; +import { ensureDir, ensureFile, writeFile } from 'fs-extra'; +import { join } from 'path'; +import semver from 'semver'; +import uuid from 'short-uuid'; +import { debug, OtterError } from './otter-core'; +import { IMaterializeOptions } from './types'; + +const log = debug.extend('mat'); + +/** + * 创建组件包 + * + * @private + * @param {{ + * pkgName: string; + * pkgVersion: string; + * }} params + * @returns {Promise} + * @memberof OnlineAccesser + */ +export async function createFakePackage(params: { + tempDir: string; + pkgName: string; + pkgVersion: string; + npmClient?: string; +}): Promise { + // 创建临时组件包 + const tempDir = params.tempDir; + const pkgJsonFilePath = join(tempDir, 'package.json'); + await ensureFile(pkgJsonFilePath); + await writeFile( + pkgJsonFilePath, + JSON.stringify({ + name: params.pkgName, + version: params.pkgVersion || '0.0.0', + dependencies: { + [params.pkgName]: params.pkgVersion || 'latest', + }, + }), + ); + + // 安装依赖 + const npmClient = params.npmClient || 'tnpm'; + await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: tempDir } as any); +} + +/** + * 创建临时目录 + * + * @private + * @returns {Promise} 返回临时文件夹路径 + * @memberof LocalGenerator + */ +export async function createTempDir(): Promise { + const tempDirName = uuid.generate(); + const tempDir = join(__dirname, '../../node_modules/.temp/', tempDirName); + await ensureDir(tempDir); + log('create temp dir successfully', tempDir); + return tempDir; +} + +/** + * 分离物料组件名称和版本号 + * + * @private + * @param {string} pkgNameWithVersion + * @returns {{ [key: string]: any }} + * @memberof OnlineAccesser + */ +export function getPkgNameAndVersion(pkgNameWithVersion: string): { [key: string]: any } { + const matches = pkgNameWithVersion.match(/(@\d+\.\d+\.\d+)$/); + if (!matches) { + return { + name: pkgNameWithVersion, + }; + } + const semverObj = semver.coerce(matches[0]); + const name = pkgNameWithVersion.replace(matches[0], ''); + return { + version: semverObj && semverObj.version, + name, + }; +} + +// 将问题转化为本地物料化场景 +export default async function localize(options: IMaterializeOptions): Promise { + // 创建临时目录 + const tempDir = await createTempDir(); + // 创建组件包 + const { name, version } = getPkgNameAndVersion(options.entry); + await createFakePackage({ + pkgName: name, + pkgVersion: version, + tempDir, + npmClient: options.npmClient, + }); + + return join(tempDir, 'node_modules', name); +} diff --git a/packages/material-parser/src/otter-core/schema/types.ts b/packages/material-parser/src/otter-core/schema/types.ts index 5fe064355..97a6d5f52 100644 --- a/packages/material-parser/src/otter-core/schema/types.ts +++ b/packages/material-parser/src/otter-core/schema/types.ts @@ -8,7 +8,7 @@ /** * json schema for low code component protocol */ -export type IComponentMaterial = BasicSection & PropsSection & ConfigureSection; +export type ComponentMeta = BasicSection & PropsSection & ConfigureSection; export type PropType = BasicType | RequiredType | ComplexType; export type BasicType = "array" | "bool" | "func" | "number" | "object" | "string" | "node" | "element" | "any"; export type ComplexType = OneOf | OneOfType | ArrayOf | ObjectOf | Shape | Exact; diff --git a/packages/material-parser/src/parse/handlers/defaultPropsHandler.ts b/packages/material-parser/src/parse/handlers/defaultPropsHandler.ts new file mode 100644 index 000000000..74782c162 --- /dev/null +++ b/packages/material-parser/src/parse/handlers/defaultPropsHandler.ts @@ -0,0 +1,150 @@ +const { namedTypes: t, NodePath } = require('ast-types'); +type NodePathType = typeof NodePath; +const { + getPropertyName, + isReactComponentClass, + getMemberValuePath, + isReactForwardRefCall, + printValue, + resolveExportDeclaration, + resolveToValue, +} = require('react-docgen').utils; +const resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue'); + +function getDefaultValue(path: NodePathType) { + let node = path.node; + let defaultValue; + if (t.Literal.check(node)) { + defaultValue = node.raw; + } else { + if (t.AssignmentPattern.check(path.node)) { + path = resolveToValue(path.get('right')); + } else { + path = resolveToValue(path); + } + if (t.ImportDeclaration.check(path.node)) { + defaultValue = node.name; + } else { + node = path.node; + try { + defaultValue = printValue(path); + } catch (e) {} + } + } + if (typeof defaultValue !== 'undefined') { + return { + value: defaultValue, + computed: + t.CallExpression.check(node) || + t.MemberExpression.check(node) || + t.Identifier.check(node), + }; + } + + return null; +} + +function getStatelessPropsPath(componentDefinition: any) { + const value = resolveToValue(componentDefinition); + if (isReactForwardRefCall(value)) { + const inner = resolveToValue(value.get('arguments', 0)); + return inner.get('params', 0); + } + return value.get('params', 0); +} + +function getDefaultPropsPath(componentDefinition: any) { + let defaultPropsPath = getMemberValuePath( + componentDefinition, + 'defaultProps', + ); + if (!defaultPropsPath) { + return null; + } + + defaultPropsPath = resolveToValue(defaultPropsPath); + if (!defaultPropsPath) { + return null; + } + + if (t.FunctionExpression.check(defaultPropsPath.node)) { + // Find the value that is returned from the function and process it if it is + // an object literal. + const returnValue = resolveFunctionDefinitionToReturnValue( + defaultPropsPath, + ); + if (returnValue && t.ObjectExpression.check(returnValue.node)) { + defaultPropsPath = returnValue; + } + } + return defaultPropsPath; +} + +function getDefaultValuesFromProps( + properties: any[], + documentation: any, + isStateless: boolean, +) { + properties + // Don't evaluate property if component is functional and the node is not an AssignmentPattern + .filter( + propertyPath => + !isStateless || + t.AssignmentPattern.check(propertyPath.get('value').node), + ) + .forEach(propertyPath => { + if (t.Property.check(propertyPath.node)) { + const propName = getPropertyName(propertyPath); + if (!propName) return; + + const propDescriptor = documentation.getPropDescriptor(propName); + const defaultValue = getDefaultValue( + isStateless + ? propertyPath.get('value', 'right') + : propertyPath.get('value'), + ); + if (defaultValue) { + propDescriptor.defaultValue = defaultValue; + } + } else if (t.SpreadElement.check(propertyPath.node)) { + const resolvedValuePath = resolveToValue(propertyPath.get('argument')); + if (t.ObjectExpression.check(resolvedValuePath.node)) { + getDefaultValuesFromProps( + resolvedValuePath.get('properties'), + documentation, + isStateless, + ); + } + } + }); +} + +export default function defaultPropsHandler( + documentation: any, + componentDefinition: any, +) { + let statelessProps = null; + const defaultPropsPath = getDefaultPropsPath(componentDefinition); + /** + * function, lazy, memo, forwardRef etc components can resolve default props as well + */ + if (!isReactComponentClass(componentDefinition)) { + statelessProps = getStatelessPropsPath(componentDefinition); + } + + // Do both statelessProps and defaultProps if both are available so defaultProps can override + if (statelessProps && t.ObjectPattern.check(statelessProps.node)) { + getDefaultValuesFromProps( + statelessProps.get('properties'), + documentation, + true, + ); + } + if (defaultPropsPath && t.ObjectExpression.check(defaultPropsPath.node)) { + getDefaultValuesFromProps( + defaultPropsPath.get('properties'), + documentation, + false, + ); + } +} diff --git a/packages/material-parser/src/parser/handlers/index.ts b/packages/material-parser/src/parse/handlers/index.ts similarity index 86% rename from packages/material-parser/src/parser/handlers/index.ts rename to packages/material-parser/src/parse/handlers/index.ts index a4ff85a6c..d7fae8bdd 100644 --- a/packages/material-parser/src/parser/handlers/index.ts +++ b/packages/material-parser/src/parse/handlers/index.ts @@ -1,9 +1,11 @@ -const { handlers } = require('react-docgen'); import { propTypeHandler, contextTypeHandler, childContextTypeHandler, } from './propTypeHandler'; +import defaultPropsHandler from './defaultPropsHandler'; + +const { handlers } = require('react-docgen'); const defaultHandlers = [ propTypeHandler, @@ -12,7 +14,7 @@ const defaultHandlers = [ handlers.propTypeCompositionHandler, handlers.propDocBlockHandler, handlers.flowTypeHandler, - handlers.defaultPropsHandler, + defaultPropsHandler, handlers.componentDocblockHandler, handlers.displayNameHandler, handlers.componentMethodsHandler, diff --git a/packages/material-parser/src/parser/handlers/propTypeHandler.ts b/packages/material-parser/src/parse/handlers/propTypeHandler.ts similarity index 96% rename from packages/material-parser/src/parser/handlers/propTypeHandler.ts rename to packages/material-parser/src/parse/handlers/propTypeHandler.ts index 619a88eb4..74fb883b2 100644 --- a/packages/material-parser/src/parser/handlers/propTypeHandler.ts +++ b/packages/material-parser/src/parse/handlers/propTypeHandler.ts @@ -8,7 +8,7 @@ */ import { namedTypes as t, visit } from 'ast-types'; -import { throwStatement } from '@babel/types'; + const { resolveToValue, getPropType, @@ -29,7 +29,6 @@ function getRoot(node: any) { } return root; } -// import type Documentation from '../Documentation'; function isPropTypesExpression(path: any) { const moduleName = resolveToModule(path); @@ -81,11 +80,12 @@ function amendPropTypes(getDescriptor: any, path: any) { function getDefinePropertyValuePath(nodePath: any, propName: string) { const program = getRoot(nodePath); - const componentName = nodePath.node.id.name; let resultPath = nodePath; + if (!nodePath.node.id) return; + const componentName = nodePath.node.id.name; visit(program, { - visitCallExpression: function(path) { + visitCallExpression(path) { const args = path.get('arguments'); const argsNodeList = args.value; if ( diff --git a/packages/material-parser/src/parse/index.ts b/packages/material-parser/src/parse/index.ts new file mode 100644 index 000000000..028200af2 --- /dev/null +++ b/packages/material-parser/src/parse/index.ts @@ -0,0 +1,36 @@ +const reactDocs = require('react-docgen'); +import { transformItem } from './transform'; +import { debug } from '../otter-core'; +import { IMaterialParsedModel, IMaterialScanModel } from '../types'; +import resolver from './resolver'; +import handlers from './handlers'; + +export default function parse(params: { fileContent: string; filePath: string }): Promise { + const { fileContent, filePath } = params; + const result = reactDocs.parse( + fileContent, + (ast: any) => { + ast.__path = filePath; + return resolver(ast); + }, + handlers, + ); + const coms = result.reduce((res: any[], info: any) => { + if (!info || !info.props) return res; + const props = Object.keys(info.props).reduce((acc: any[], name) => { + try { + const item: any = transformItem(name, info.props[name]); + acc.push(item); + } catch (e) { + } finally { + return acc; + } + }, []); + res.push({ + componentName: info.displayName, + props, + }); + return res; + }, []); + return coms; +} diff --git a/packages/material-parser/src/parser/resolver/checkIsIIFE.ts b/packages/material-parser/src/parse/resolver/checkIsIIFE.ts similarity index 100% rename from packages/material-parser/src/parser/resolver/checkIsIIFE.ts rename to packages/material-parser/src/parse/resolver/checkIsIIFE.ts diff --git a/packages/material-parser/src/parser/resolver/index.ts b/packages/material-parser/src/parse/resolver/index.ts similarity index 73% rename from packages/material-parser/src/parser/resolver/index.ts rename to packages/material-parser/src/parse/resolver/index.ts index b16a99fd4..f0d67adbb 100644 --- a/packages/material-parser/src/parser/resolver/index.ts +++ b/packages/material-parser/src/parse/resolver/index.ts @@ -7,6 +7,12 @@ */ import { namedTypes as t, visit } from 'ast-types'; +import checkIsIIFE from './checkIsIIFE'; +import resolveHOC from './resolveHOC'; +import resolveIIFE from './resolveIIFE'; +import resolveImport from './resolveImport'; +import resolveTranspiledClass from './resolveTranspiledClass'; + const { isExportsOrModuleAssignment, isReactComponentClass, @@ -17,13 +23,6 @@ const { resolveExportDeclaration, resolveToValue, } = require('react-docgen').utils; -import checkIsIIFE from './checkIsIIFE'; -import resolveHOC from './resolveHOC'; -import resolveIIFE from './resolveIIFE'; -import resolveTranspiledClass from './resolveTranspiledClass'; - -const ERROR_MULTIPLE_DEFINITIONS = - 'Multiple exported component definitions found.'; function ignore() { return false; @@ -57,7 +56,7 @@ function resolveDefinition(definition: any) { return null; } -function getDefinition(definition: any) { +function getDefinition(definition: any): any { if (checkIsIIFE(definition)) { definition = resolveToValue(resolveIIFE(definition)); if (!isComponentDefinition(definition)) { @@ -70,14 +69,17 @@ function getDefinition(definition: any) { if (!isComponentDefinition(definition)) { definition = resolveTranspiledClass(definition); } + } else if (t.SequenceExpression.check(definition.node)) { + return getDefinition( + resolveToValue(definition.get('expressions').get(0)), + ); + } else { + definition = resolveImport( + definition, + findAllExportedComponentDefinition, + ); } } - // definition = resolveToValue(resolveIIFE(definition)); - // if (!isComponentDefinition(definition)) { - // definition = resolveTranspiledClass(definition); - // } - // definition = resolveToValue(resolveHOC(definition)); - return definition; } /** @@ -95,33 +97,37 @@ function getDefinition(definition: any) { * export default Definition; * export var Definition = ...; */ -export default function findExportedComponentDefinition(ast: any) { - let foundDefinition: any; +export default function findAllExportedComponentDefinition(ast: any) { + const components: any[] = []; function exportDeclaration(path: any) { - const definitions = resolveExportDeclaration(path).reduce( - (acc: any, definition: any) => { + const definitions = resolveExportDeclaration(path) + .reduce((acc: any[], definition: any) => { if (isComponentDefinition(definition)) { acc.push(definition); } else { definition = getDefinition(definition); - if (isComponentDefinition(definition)) { - acc.push(definition); + if (!Array.isArray(definition)) { + definition = [definition]; } + definition.forEach((def: any) => { + if (isComponentDefinition(def)) { + acc.push(def); + } + }); } return acc; - }, - [], - ); + }, []) + .map((definition: any) => resolveDefinition(definition)); if (definitions.length === 0) { return false; } - if (definitions.length > 1 || foundDefinition) { - // If a file exports multiple components, ... complain! - throw new Error(ERROR_MULTIPLE_DEFINITIONS); - } - foundDefinition = resolveDefinition(definitions[0]); + definitions.forEach((definition: any) => { + if (definition && components.indexOf(definition) === -1) { + components.push(definition); + } + }); return false; } @@ -142,6 +148,12 @@ export default function findExportedComponentDefinition(ast: any) { visitExportNamedDeclaration: exportDeclaration, visitExportDefaultDeclaration: exportDeclaration, + visitExportAllDeclaration: function(path) { + components.push( + ...resolveImport(path, findAllExportedComponentDefinition), + ); + return false; + }, visitAssignmentExpression(path: any) { // Ignore anything that is not `exports.X = ...;` or @@ -155,14 +167,14 @@ export default function findExportedComponentDefinition(ast: any) { if (!isComponentDefinition(path)) { path = getDefinition(path); } - if (foundDefinition) { - // If a file exports multiple components, ... complain! - throw new Error(ERROR_MULTIPLE_DEFINITIONS); + + const definition = resolveDefinition(path); + if (definition && components.indexOf(definition) === -1) { + components.push(definition); } - foundDefinition = resolveDefinition(path); return false; }, }); - return foundDefinition; + return components; } diff --git a/packages/material-parser/src/parser/resolver/resolveHOC.ts b/packages/material-parser/src/parse/resolver/resolveHOC.ts similarity index 99% rename from packages/material-parser/src/parser/resolver/resolveHOC.ts rename to packages/material-parser/src/parse/resolver/resolveHOC.ts index a5538a91f..426dc1e84 100644 --- a/packages/material-parser/src/parser/resolver/resolveHOC.ts +++ b/packages/material-parser/src/parse/resolver/resolveHOC.ts @@ -6,6 +6,7 @@ */ import { namedTypes as t, visit } from 'ast-types'; + const { isReactCreateClassCall, isReactForwardRefCall, diff --git a/packages/material-parser/src/parser/resolver/resolveIIFE.ts b/packages/material-parser/src/parse/resolver/resolveIIFE.ts similarity index 62% rename from packages/material-parser/src/parser/resolver/resolveIIFE.ts rename to packages/material-parser/src/parse/resolver/resolveIIFE.ts index 011328600..371cde5fb 100644 --- a/packages/material-parser/src/parser/resolver/resolveIIFE.ts +++ b/packages/material-parser/src/parse/resolver/resolveIIFE.ts @@ -1,20 +1,7 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ +import checkIsIIFE from './checkIsIIFE'; -// const { namedTypes: t, visit } = require("ast-types"); const resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue') .default; -// isReactCreateClassCall, -// isReactForwardRefCall, -// resolveToValue, -// resolveHOC - -import checkIsIIFE from './checkIsIIFE'; /** * If the path is a call expression, it recursively resolves to the * rightmost argument, stopping if it finds a React.createClass call expression diff --git a/packages/material-parser/src/parse/resolver/resolveImport.ts b/packages/material-parser/src/parse/resolver/resolveImport.ts new file mode 100644 index 000000000..86c87f279 --- /dev/null +++ b/packages/material-parser/src/parse/resolver/resolveImport.ts @@ -0,0 +1,60 @@ +import { namedTypes as t } from 'ast-types'; +import fs from 'fs'; +import p from 'path'; + +function getRoot(node: any) { + let root = node.parent; + while (root.parent) { + root = root.parent; + } + return root.node; +} + +function isImportLike(node: any) { + return ( + t.ImportDeclaration.check(node) || + t.ExportAllDeclaration.check(node) || + t.ExportNamedDeclaration.check(node) + ); +} + +function getPath(path: any, name: any) { + const root = getRoot(path); + if (!root) return; + let { __path } = root; + __path = p.dirname(__path); + // is directory + if (fs.existsSync(p.resolve(__path, name))) { + name = name + '/index'; + } + const suffix = suffixes.find(suf => { + return fs.existsSync(p.resolve(__path, name + suf)); + }); + if (!suffix) return; + return p.resolve(__path, name + suffix); +} + +const buildParser = require('react-docgen/dist/babelParser').default; +const parser = buildParser(); +const suffixes = ['.js', '.jsx', '.ts', '.tsx']; + +export default function resolveImport(path: any, callback: any) { + let name; + if (path.name === 'local') { + name = path.parentPath.parentPath.parentPath.node.source.value; + } else if (!isImportLike(path.node)) { + return path; + } else { + name = path.node.source.value; + } + if (name) { + const __path = getPath(path, name); + if (!__path) return path; + const fileContent = fs.readFileSync(__path, 'utf8'); + const ast = parser.parse(fileContent); + ast.__src = fileContent; + ast.__path = __path; + return callback(ast); + } + return path; +} diff --git a/packages/material-parser/src/parser/resolver/resolveTranspiledClass.ts b/packages/material-parser/src/parse/resolver/resolveTranspiledClass.ts similarity index 80% rename from packages/material-parser/src/parser/resolver/resolveTranspiledClass.ts rename to packages/material-parser/src/parse/resolver/resolveTranspiledClass.ts index c4bfc6e72..0357966ab 100644 --- a/packages/material-parser/src/parser/resolver/resolveTranspiledClass.ts +++ b/packages/material-parser/src/parse/resolver/resolveTranspiledClass.ts @@ -1,11 +1,3 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - import { builders, namedTypes as t, NodePath, visit } from 'ast-types'; /** * If the path is a call expression, it recursively resolves to the @@ -19,7 +11,7 @@ export default function resolveTranspiledClass(path: any) { visitFunctionDeclaration(arg) { classPath = new NodePath( builders.functionDeclaration( - arg.node.id, + arg.node.id || 'Default', [], builders.blockStatement([ builders.returnStatement( diff --git a/packages/material-parser/src/parse/transform.ts b/packages/material-parser/src/parse/transform.ts new file mode 100644 index 000000000..11de2aa22 --- /dev/null +++ b/packages/material-parser/src/parse/transform.ts @@ -0,0 +1,132 @@ +export function transformType(type: any) { + if (typeof type === 'string') return type; + const { name, elements, value = elements, computed, required } = type; + if (!value && !required) { + return name; + } + if (computed !== undefined && value) { + return eval(value); + } + const result: any = { + type: name, + }; + if (required) { + result.isRequired = required; + } + switch (name) { + case 'number': + case 'string': + case 'bool': + case 'any': + case 'func': + case 'symbol': + case 'object': + break; + case 'literal': + return eval(value); + case 'enum': + case 'tuple': + result.type = 'oneOf'; + result.value = value.map(transformType); + break; + case 'union': + result.type = 'oneOfType'; + result.value = value.map(transformType); + break; + case 'boolean': + result.type = 'bool'; + break; + case 'Array': { + result.type = 'arrayOf'; + const v = transformType(value[0]); + if (typeof v.type === 'string') result.value = v.type; + break; + } + case 'signature': { + result.type = 'shape'; + const { + signature: { properties }, + } = type; + if (properties.length === 0) { + result.type = 'object'; + } else if (properties.length === 1 && typeof properties[0].key === 'object') { + result.type = 'objectOf'; + const v = transformType(properties[0].value); + if (typeof v.type === 'string') result.value = v.type; + } else { + result.value = properties + .filter((item: any) => typeof item.key !== 'object') + .map((prop: any) => { + const { + key, + value: { name, ...others }, + } = prop; + return transformItem(key, { + ...others, + type: { + name, + }, + }); + }); + } + break; + } + case 'objectOf': + case 'arrayOf': + case 'instanceOf': + result.value = transformType(value); + break; + case 'exact': + case 'shape': + result.value = Object.keys(value).map((n) => { + // tslint:disable-next-line:variable-name + const { name: _name, ...others } = value[n]; + return transformItem(n, { + ...others, + type: { + name: _name, + }, + }); + }); + break; + case (name.match('ReactNode$') || {}).input: + result.type = 'node'; + break; + case (name.match('Element$') || {}).input: + result.type = 'element'; + break; + case (name.match('ElementType$') || {}).input: + result.type = 'elementType'; + break; + default: + result.type = 'instanceOf'; + result.value = name; + break; + } + return result; +} + +export function transformItem(name: string, item: any) { + const { description, flowType, type = flowType, required, defaultValue } = item; + const result: any = { + name, + propType: transformType({ + ...type, + required: !!required, + }), + }; + if (description) { + result.description = description; + } + if (defaultValue) { + try { + const value = eval(defaultValue.value); + result.defaultValue = value; + } catch (e) {} + } + if (result.propType === undefined) { + delete result.propType; + } + + return result; +} diff --git a/packages/material-parser/src/parser/BaseParser.ts b/packages/material-parser/src/parser/BaseParser.ts deleted file mode 100644 index baf292875..000000000 --- a/packages/material-parser/src/parser/BaseParser.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { OtterError } from '../otter-core'; -import { - EcologyType, - IMaterializeOptions, - IMaterialParsedModel, - IMaterialScanModel, - IParser, - SourceType, -} from '../types'; - -/** - * 解析器基类 - * @abstract - * @class BaseParser - * @implements {IParser} - */ -abstract class BaseParser implements IParser { - /** - * 识别语法生态,判断是 react、vue、rax - * @static - * @param {IMaterializeOptions} options - * @returns {Promise} - * @memberof BaseParser - */ - public static recognizeEcology( - options: IMaterializeOptions, - ): Promise { - // TODO 识别物料组件生态 - return Promise.resolve(EcologyType.REACT); - } - - private options: IMaterializeOptions; - - constructor(options: IMaterializeOptions) { - this.options = options; - } - - public async parse( - model: IMaterialScanModel, - ): Promise { - const results: IMaterialParsedModel[] = []; - switch (model.sourceType) { - case SourceType.MODULE: { - for (const item of model.modules) { - const parsedModel: IMaterialParsedModel = await this.parseES6({ - model, - filePath: item.filePath, - fileContent: item.fileContent, - }); - results.push(parsedModel); - } - break; - } - case SourceType.MAIN: { - this.parseES5(model); - break; - } - default: { - throw new OtterError(`Unsupported SourceType [${model.sourceType}]`); - } - } - return results; - } - - public abstract parseES5( - model: IMaterialScanModel, - ): Promise; - - public abstract parseES6(params: { - model: IMaterialScanModel; - filePath: string; - fileContent: string; - }): Promise; -} - -export default BaseParser; diff --git a/packages/material-parser/src/parser/ReactParser.ts b/packages/material-parser/src/parser/ReactParser.ts deleted file mode 100644 index 5ececea15..000000000 --- a/packages/material-parser/src/parser/ReactParser.ts +++ /dev/null @@ -1,704 +0,0 @@ -import { CodeGenerator } from '@babel/generator'; -// import { parse } from '@babel/parser'; -const buildParser = require('react-docgen/dist/babelParser').default; -const reactDocs = require('react-docgen'); -import traverse from '@babel/traverse'; -import * as t from '@babel/types'; -const { utils: ReactDocUtils } = require('react-docgen'); -import { debug } from '../otter-core'; -import { - IMaterialParsedModel, - IMaterialScanModel, - IPropType, - IPropTypes, - SourceType, -} from '../types'; -import BaseParser from './BaseParser'; -import resolver from './resolver'; -import handlers from './handlers'; - -const log = debug.extend('mat'); -const parser = buildParser(); - -function transformType(type: any): any { - const { name, value, computed, required } = type; - if (!value && !required) { - return name; - } - if (computed !== undefined && value) { - // tslint:disable-next-line:no-eval - return eval(value); - } - const result: any = { - type: name, - }; - if (required) { - result.isRequired = required; - } - if (Array.isArray(value)) { - if (name === 'enum') { - result.type = 'oneOf'; - } else if (name === 'union') { - result.type = 'oneOfType'; - } - result.value = value.map(transformType); - } else if (typeof value === 'object') { - if (name === 'objectOf' || name === 'arrayOf' || name === 'instanceOf') { - result.value = transformType(value); - } else { - result.value = Object.keys(value).map((n: string) => { - // tslint:disable-next-line:variable-name - const { name: _name, ...others } = value[n]; - return transformItem(n, { - ...others, - type: { - name: _name, - }, - }); - }); - } - } else if (value !== undefined) { - result.value = value; - } - return result; -} - -function transformItem(name: string, item: any): any { - const { description, type, required, defaultValue } = item; - const result: any = { - name, - propType: transformType({ - ...type, - required: !!required, - }), - }; - if (description) { - result.description = description; - } - if (defaultValue) { - try { - const value = eval(defaultValue.value); - result.defaultValue = value; - } catch (e) {} - } - - return result; -} -/** - * 解析 react 生态下的组件 - * - * @class ReactParser - * @extends {BaseParser} - */ -class ReactParser extends BaseParser { - /** - * 解析 ExportStatement - * @static - * @returns {Promise} - * @memberof ReactParser - */ - public static async parseExportedStatement( - fileContent: string, - sourceType: string, - ): Promise< - Array<{ - localName: string; - exportedName: string; - source: string; - }> - > { - const ast = parser.parse(fileContent); - - // @ts-ignore - ast.__src = fileContent; - - const specifiers: any = []; - - // 组装 localName 和 exportedName - traverse(ast, { - enter(path) { - if (t.isExportNamedDeclaration(path.node)) { - path.node.specifiers.forEach(spec => { - if (t.isExportSpecifier(spec)) { - const source = (path.node as t.ExportNamedDeclaration).source; - specifiers.push({ - localName: spec.local.name, - exportedName: spec.exported.name, - source: t.isLiteral(source) ? (source as any).value : '', - }); - } - }); - } - }, - }); - // 组装 source - traverse(ast, { - enter(path) { - if (t.isImportDeclaration(path.node)) { - const source = path.node.source; - path.node.specifiers.forEach(spec => { - if (t.isImportDefaultSpecifier(spec)) { - const target = specifiers.find( - (inner: any) => inner.localName === spec.local.name, - ); - if (target) { - target.source = source.value; - } - } - }); - } - }, - }); - debug('specifiers', specifiers); - return specifiers; - } - public static parseProperties(objectPath: any): IPropTypes { - const results: IPropTypes = objectPath - .get('properties') - .map((p: any) => - transformItem( - p.get('key').node.name, - ReactDocUtils.getPropType(p.get('value')), - ), - ); - - return results; - } - - public async parseES5( - model: IMaterialScanModel, - ): Promise { - const parsedModel: IMaterialParsedModel = { - filePath: '', - defaultExportName: '', - componentNames: [], - importModules: [], - exportModules: [], - subModules: [], - propsTypes: [], - propsDefaults: [], - }; - - const mainEntryItem: any = model.modules.find( - item => item.filePath === model.mainEntry, - ); - - const result = reactDocs.parse( - mainEntryItem.fileContent, - resolver, - handlers, - ); - const props = Object.keys(result.props || {}).map(name => { - return transformItem(name, result.props[name]); - }); - - return { - filePath: mainEntryItem.filePath, - // defaultExportName, - // subModules, - // propsTypes, - props, - } as any; - - // log('mainEntryItem', mainEntryItem); - // const ast = parser.parse(mainEntryItem.file); - - // @ts-ignore - // ast.__src = mainEntryItem.file; - - // // 获取 defaultExportName - // traverse(ast, { - // enter(path) { - // if (t.isExpressionStatement(path.node)) { - // if ( - // t.isAssignmentExpression(path.node.expression) && - // t.isMemberExpression(path.node.expression.left) && - // t.isIdentifier(path.node.expression.left.object) && - // t.isIdentifier(path.node.expression.right) && - // path.node.expression.left.object.name === 'exports' && - // (path.node.expression.left.property.name === 'default' || - // path.node.expression.left.property.value === 'default') - // ) { - // // 支持 export default Demo 写法 - // const tempVarName = path.node.expression.right.name; - // let defaultExportName = ''; - // traverse(ast, { - // enter(innerPath) { - // if ( - // t.isVariableDeclaration(innerPath.node) && - // Array.isArray(innerPath.node.declarations) && - // innerPath.node.declarations.length && - // t.isVariableDeclarator(innerPath.node.declarations[0]) && - // t.isIdentifier(innerPath.node.declarations[0].id) && - // innerPath.node.declarations[0].id.name === tempVarName && - // t.isIdentifier(innerPath.node.declarations[0].init) - // ) { - // defaultExportName = innerPath.node.declarations[0].init.name; - // } - // }, - // }); - // parsedModel.defaultExportName = defaultExportName; - // log('isIdentifier defaultExportName', defaultExportName); - // } - // } - // }, - // }); - - // traverse(ast, { - // enter(path) { - // // 获取 componentNames - // if (t.isVariableDeclaration(path.node)) { - // if ( - // t.isVariableDeclarator(path.node.declarations) && - // t.isIdentifier(path.node.declarations.init) && - // t.isIdentifier(path.node.declarations.id) - // ) { - // const exportedName = path.node.declarations.init.name; - // const localName = path.node.declarations.id.name; - // log('isIdentifier componentNames', exportedName); - // parsedModel.componentNames.push({ - // exportedName, - // localName, - // }); - // } - // } - // // 获取 exportModules - // if (t.isExpressionStatement(path.node)) { - // // 对应 export function DemoFunc() {} 或 export { DemoFunc } 写法 - // if ( - // t.isAssignmentExpression(path.node.expression) && - // t.isMemberExpression(path.node.expression.left) && - // t.isIdentifier(path.node.expression.left.object) && - // t.isIdentifier(path.node.expression.left.property) && - // t.isIdentifier(path.node.expression.right) && - // path.node.expression.left.object.name === 'exports' - // ) { - // const exportedName = path.node.expression.left.property.name; - // const localName = path.node.expression.right.name; - // parsedModel.exportModules.push({ - // exportedName: - // exportedName === 'default' - // ? parsedModel.defaultExportName - // : exportedName, - // localName: - // exportedName === 'default' - // ? parsedModel.defaultExportName - // : localName, - // }); - // } - // // 支持 export { default as DemoFunc } from './DemoFunc' 写法 - // if ( - // t.isCallExpression(path.node.expression) && - // t.isMemberExpression(path.node.expression.callee) && - // t.isIdentifier(path.node.expression.callee.object) && - // t.isIdentifier(path.node.expression.callee.property) && - // path.node.expression.callee.object.name === 'Object' && - // path.node.expression.callee.property.name === 'defineProperty' && - // Array.isArray(path.node.expression.arguments) && - // t.isIdentifier(path.node.expression.arguments[0]) && - // (path.node.expression.arguments[0] as t.Identifier).name === - // 'exports' && - // t.isLiteral(path.node.expression.arguments[1]) - // ) { - // // 对应 export function DemoFunc() {} 或 export { DemoFunc } 写法 - // const args = path.node.expression.arguments as any; - // const funcName = args[1].value; - // if (funcName !== '__esModule') { - // parsedModel.exportModules.push({ - // exportedName: funcName, - // localName: funcName, - // }); - // } - // } - // } - // // 获取 importModules - // if ( - // t.isVariableDeclaration(path.node) && - // Array.isArray(path.node.declarations) && - // path.node.declarations.length - // ) { - // path.node.declarations.forEach(dec => { - // // 支持 import Demo from './demo' 写法 - // if ( - // t.isVariableDeclarator(dec) && - // t.isIdentifier(dec.id) && - // t.isCallExpression(dec.init) && - // t.isIdentifier(dec.init.callee) && - // ['_interopRequireWildcard', '_interopRequireDefault'].includes( - // dec.init.callee.name, - // ) && - // // dec.init.callee.name === '_interopRequireWildcard' && - // Array.isArray(dec.init.arguments) && - // t.isCallExpression(dec.init.arguments[0]) && - // t.isIdentifier( - // (dec.init.arguments[0] as t.CallExpression).callee, - // ) && - // ((dec.init.arguments[0] as t.CallExpression) - // .callee as t.Identifier).name === 'require' - // ) { - // const localName = dec.id.name; - // const args = (dec.init.arguments[0] as t.CallExpression) - // .arguments as any; - // const source = args[0].value; - // parsedModel.importModules.push({ - // importDefaultName: localName, - // localName, - // source, - // }); - // } - - // // 支持 import { Demo as Demo2 } from './demo' 写法 - // if ( - // t.isVariableDeclarator(dec) && - // t.isIdentifier(dec.id) && - // t.isCallExpression(dec.init) && - // t.isIdentifier(dec.init.callee) && - // dec.init.callee.name === 'require' && - // Array.isArray(dec.init.arguments) && - // t.isLiteral(dec.init.arguments[0]) - // ) { - // const args = dec.init.arguments as any; - // const source = args[0].value; - // const importName = dec.id.name; - // const localName = dec.id.name; - // // 遍历查找出 importName 和 localName - // // ES5 本身并不支持按需加载,故 import 都是全量导入 - // // 但如果使用了诸如:babel-plugin-import 等插件,会自动更改编译之后的 ES5 代码 - // parsedModel.importModules.push({ - // importName, - // localName, - // source, - // }); - // } - // }); - // } - - // // 获取 subModules - // if ( - // t.isExpressionStatement(path.node) && - // t.isAssignmentExpression(path.node.expression) && - // t.isMemberExpression(path.node.expression.left) - // ) { - // if ( - // t.isIdentifier(path.node.expression.left.object) && - // path.node.expression.left.object.name === - // parsedModel.defaultExportName - // ) { - // // 支持 SFC.SubDemo1 = SubDemo1; 写法 - // if (t.isIdentifier(path.node.expression.right)) { - // parsedModel.subModules.push({ - // objectName: [path.node.expression.left.object.name], - // propertyName: path.node.expression.left.property.name, - // isValueAnonymousFunc: false, - // value: path.node.expression.right.name, - // }); - // } - - // // 支持 SFC.SubDemo2 = function() {}; 写法 - // if (t.isFunctionExpression(path.node.expression.right)) { - // const rightID = path.node.expression.right.id as any; - // parsedModel.subModules.push({ - // objectName: [path.node.expression.left.object.name], - // propertyName: path.node.expression.left.property.name, - // isValueAnonymousFunc: !rightID, - // value: rightID ? rightID.name : undefined, - // }); - // } - // } - - // if (t.isMemberExpression(path.node.expression.left.object)) { - // if (t.isIdentifier(path.node.expression.right)) { - // // 支持 DemoFunc4.Test.Obj2 = Obj3; 写法 - // const tempLeftObject = path.node.expression.left.object as any; - // parsedModel.subModules.push({ - // objectName: [ - // tempLeftObject.object.name, - // tempLeftObject.property.name, - // ], - // propertyName: path.node.expression.left.property.name, - // isValueAnonymousFunc: false, - // value: path.node.expression.right.name, - // }); - // } - // if (t.isFunctionExpression(path.node.expression.right)) { - // // 支持 DemoFunc4.Test.Obj2 = function() {}; 写法 - // const rightID = path.node.expression.right.id as any; - // const tempLeftObject = path.node.expression.left.object as any; - // parsedModel.subModules.push({ - // objectName: [ - // tempLeftObject.object.name, - // tempLeftObject.property.name, - // ], - // propertyName: path.node.expression.left.property.name, - // isValueAnonymousFunc: !rightID, - // value: rightID ? rightID.name : undefined, - // }); - // } - // } - // } - - // // 获取 propsTypes 和 defaultProps - // if ( - // t.isExpressionStatement(path.node) && - // t.isAssignmentExpression(path.node.expression) && - // t.isMemberExpression(path.node.expression.left) && - // t.isObjectExpression(path.node.expression.right) && - // t.isIdentifier(path.node.expression.left.object) && - // t.isIdentifier(path.node.expression.left.property) && - // path.node.expression.left.object.name === - // parsedModel.defaultExportName && - // ['propTypes', 'defaultProps'].includes( - // path.node.expression.left.property.name, - // ) - // ) { - // // 处理 propTypes - // if (path.node.expression.left.property.name === 'propTypes') { - // path.node.expression.right.properties.forEach(prop => { - // if (t.isProperty(prop)) { - // if (t.isMemberExpression(prop.value)) { - // if (t.isIdentifier(prop.value.object)) { - // // 支持 optionalArray: PropTypes.array 写法 - // parsedModel.propsTypes.push({ - // name: prop.key.name, - // type: prop.value.property.name, - // required: false, - // }); - // } - // if (t.isMemberExpression(prop.value.object)) { - // // 支持 optionalArray: PropTypes.array.isRequired 写法 - // parsedModel.propsTypes.push({ - // name: prop.key.name, - // type: prop.value.object.property.name, - // required: - // prop.value.object.property.name === 'isRequired', - // }); - // } - // if ( - // t.isCallExpression(prop.value.object) && - // t.isMemberExpression(prop.value.object.callee) - // ) { - // // 支持 optionalArray: PropTypes.shape().isRequired 写法 - // parsedModel.propsTypes.push({ - // name: prop.key.name, - // type: prop.value.object.callee.property.name, - // required: prop.value.property.name === 'isRequired', - // }); - // } - // } - // if ( - // t.isCallExpression(prop.value) && - // t.isMemberExpression(prop.value.callee) - // ) { - // // 支持 optionalArray: PropTypes.shape() 写法 - // parsedModel.propsTypes.push({ - // name: prop.key.name, - // type: prop.value.callee.property.name, - // required: false, - // }); - // } - // } - // }); - // } - // // 处理 defaultProps - // if (path.node.expression.left.property.name === 'defaultProps') { - // path.node.expression.right.properties.forEach(prop => { - // if (t.isProperty(prop)) { - // if (t.isObjectExpression(prop.value)) { - // const defaultValue = new CodeGenerator( - // t.objectExpression(prop.value.properties), - // ).generate().code; - // parsedModel.propsDefaults.push({ - // name: prop.key.name, - // defaultValue, - // }); - // } - // } - // }); - // } - // } - // }, - // }); - - // log('traverse done.'); - // log('parsedModel.defaultExportName', parsedModel.defaultExportName); - // log('parsedModel.componentNames', parsedModel.componentNames); - // log('parsedModel.importModules', parsedModel.importModules); - // log('parsedModel.exportModules', parsedModel.exportModules); - // log('parsedModel.subModules', parsedModel.subModules); - // log('parsedModel.propsTypes', parsedModel.propsTypes); - // log('parsedModel.propsDefaults', parsedModel.propsDefaults); - // log('parsedModel', parsedModel); - // return parsedModel; - } - - public async parseES6(params: { - model: IMaterialScanModel; - filePath: string; - fileContent: string; - }): Promise { - const ast = parser.parse(params.fileContent); - const result = reactDocs.parse(params.fileContent, resolver, handlers); - const props = Object.keys(result.props || {}).map(name => { - return transformItem(name, result.props[name]); - }); - const defaultExportName = await this.parseDefaultExportNameES6(ast); - // const subModules = await this.parseSubModulesES6(ast); - - return { - filePath: params.filePath, - defaultExportName, - // subModules, - props, - } as any; - } - - /** - * 解析 AST 获取 defaultExportName - * 支持的写法: - * - export default Demo - * - export default function Demo() {} - * - export default class Demo {} - * - * @private - * @param {*} ast - * @memberof ReactParser - */ - private async parseDefaultExportNameES6(ast: any): Promise { - let defaultExportName = ''; - traverse(ast, { - enter(path) { - // 获取 defaultExportName - if (t.isExportDefaultDeclaration(path.node)) { - if (t.isIdentifier(path.node.declaration)) { - // 支持 export default Demo 写法 - defaultExportName = path.node.declaration.name; - log('isIdentifier defaultExportName', defaultExportName); - } - if (t.isFunctionDeclaration(path.node.declaration)) { - if (t.isIdentifier(path.node.declaration.id)) { - // 支持 export default function Demo() {} 写法 - defaultExportName = path.node.declaration.id.name; - log('isFunctionDeclaration defaultExportName', defaultExportName); - } - } - if (t.isClassDeclaration(path.node.declaration)) { - if (t.isIdentifier(path.node.declaration.id)) { - // 支持 export default class Demo {} 写法 - defaultExportName = path.node.declaration.id.name; - log('isClassDeclaration defaultExportName', defaultExportName); - } - } - if (t.isCallExpression(path.node.declaration)) { - const traverseCallExp: any = (args: any[]) => { - const arg = args[0]; - if (t.isIdentifier(arg)) { - return arg.name; - } - return traverseCallExp(arg.arguments); - }; - defaultExportName = traverseCallExp( - path.node.declaration.arguments, - ); - } - } - }, - }); - return defaultExportName; - } - - /** - * 解析 AST 获取 subModules - * 支持的写法: - * - DemoFunc4.Test = Test; - * - DemoFunc4.Test = function() {}; - * - DemoFunc4.Test.Obj2 = Obj3; - * - DemoFunc4.Test.Obj2 = function() {}; - * - * @private - * @param {*} ast - * @returns {Promise>} - * @memberof ReactParser - */ - private async parseSubModulesES6( - ast: any, - ): Promise< - Array<{ - objectName: string[]; - propertyName: string; - value?: string; - isValueAnonymousFunc: boolean; - }> - > { - const results: any[] = []; - traverse(ast, { - enter(path) { - if (t.isExpressionStatement(path.node)) { - if (t.isAssignmentExpression(path.node.expression)) { - if (t.isMemberExpression(path.node.expression.left)) { - if (t.isIdentifier(path.node.expression.left.object)) { - if (t.isIdentifier(path.node.expression.right)) { - // 支持 DemoFunc4.Test = Test; 写法 - results.push({ - objectName: [path.node.expression.left.object.name], - propertyName: path.node.expression.left.property.name, - isValueAnonymousFunc: false, - value: path.node.expression.right.name, - }); - } - if (t.isFunctionExpression(path.node.expression.right)) { - // 支持 DemoFunc4.Test = function() {}; 写法 - const rightID = !path.node.expression.right.id as any; - results.push({ - objectName: [path.node.expression.left.object.name], - propertyName: path.node.expression.left.property.name, - isValueAnonymousFunc: !!rightID, - value: rightID ? rightID.name : undefined, - }); - } - } - if (t.isMemberExpression(path.node.expression.left.object)) { - if (t.isIdentifier(path.node.expression.right)) { - // 支持 DemoFunc4.Test.Obj2 = Obj3; 写法 - const tempLeftObject = path.node.expression.left - .object as any; - results.push({ - objectName: [ - tempLeftObject.object.name, - tempLeftObject.property.name, - ], - propertyName: path.node.expression.left.property.name, - isValueAnonymousFunc: false, - value: path.node.expression.right.name, - }); - } - if (t.isFunctionExpression(path.node.expression.right)) { - // 支持 DemoFunc4.Test.Obj2 = function() {}; 写法 - const rightID = !path.node.expression.right.id as any; - const tempLeftObject = path.node.expression.left - .object as any; - results.push({ - objectName: [ - tempLeftObject.object.name, - tempLeftObject.property.name, - ], - propertyName: path.node.expression.left.property.name, - isValueAnonymousFunc: !!rightID, - value: rightID ? rightID.name : undefined, - }); - } - } - } - } - } - }, - }); - return results; - } -} - -export default ReactParser; diff --git a/packages/material-parser/src/scan.ts b/packages/material-parser/src/scan.ts new file mode 100644 index 000000000..05d661d75 --- /dev/null +++ b/packages/material-parser/src/scan.ts @@ -0,0 +1,68 @@ +import { IMaterializeOptions, IMaterialScanModel, SourceType } from './types'; +import { pathExists, readFile, lstatSync } from 'fs-extra'; +import { join } from 'path'; +import { debug } from './otter-core'; +const log = debug.extend('mat'); + +export default async function scan(options: IMaterializeOptions): Promise { + const model: IMaterialScanModel = { + pkgName: '', + pkgVersion: '', + sourceType: SourceType.MODULE, + entryFilePath: '', + entryFileContent: '', + mainFilePath: '', + }; + log('options', options); + // 入口文件路径 + let entryFilePath = options.entry; + const stats = lstatSync(entryFilePath); + if (!stats.isFile()) { + let mainFilePath = ''; + const pkgJsonPath = join(entryFilePath, 'package.json'); + // 判断是否存在 package.json + if (!(await pathExists(pkgJsonPath))) { + throw new Error(`Cannot find package.json. ${pkgJsonPath}`); + } + // 读取 package.json + let pkgJson = await resolvePkgJson(pkgJsonPath); + model.pkgName = pkgJson.name; + model.pkgVersion = pkgJson.version; + if (pkgJson.module) { + // 支持 es module + model.sourceType = SourceType.MODULE; + mainFilePath = pkgJson.module; + } else if (pkgJson.main) { + // 支持 commonjs + model.sourceType = SourceType.MAIN; + mainFilePath = pkgJson.main; + } else { + mainFilePath = './index.js'; + } + model.mainFilePath = mainFilePath; + entryFilePath = join(entryFilePath, mainFilePath); + } + + log('entryFilePath', entryFilePath); + const entryFileContent = await loadFile(entryFilePath); + log('entryFile', entryFileContent); + model.entryFilePath = entryFilePath; + model.entryFileContent = entryFileContent; + // 记录入口文件 + log('model', model); + return model; +} + +export async function loadFile(filePath: string): Promise { + const content: string | Buffer = await readFile(filePath); + if (typeof content === 'string') { + return content; + } + return content.toString(); +} + +export async function resolvePkgJson(pkgJsonPath: string): Promise<{ [k: string]: any }> { + const content = await loadFile(pkgJsonPath); + const json = JSON.parse(content); + return json; +} diff --git a/packages/material-parser/src/scanner/Scanner.ts b/packages/material-parser/src/scanner/Scanner.ts deleted file mode 100644 index 880678e13..000000000 --- a/packages/material-parser/src/scanner/Scanner.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { pathExists, readFile, statSync } from 'fs-extra'; -import { dirname, join } from 'path'; -import { debug } from '../otter-core'; -import BaseParser from '../parser/BaseParser'; -import ReactParser from '../parser/ReactParser'; -import { - IMaterializeOptions, - IMaterialScanModel, - IScanner, - SourceType, -} from '../types'; - -const log = debug.extend('mat'); - -/** - * 文件扫描器 - * - * @class Scanner - * @implements {IScanner} - */ -class Scanner implements IScanner { - public options: IMaterializeOptions; - - constructor(options: IMaterializeOptions) { - this.options = options; - } - - public async scan(): Promise { - const model: IMaterialScanModel = { - pkgName: '', - pkgVersion: '', - mainEntry: '', - sourceType: SourceType.MODULE, - modules: [], - }; - const options = this.options; - log('options', options); - // 入口文件路径 - let entryFilePath = null; - const cwd = options.cwd ? options.cwd : ''; - const entry = options.entry; - const isDepsMode = cwd !== entry; - const pkgJsonPath = join(cwd, 'package.json'); - // 判断是否存在 package.json - // if (!(await pathExists(pkgJsonPath))) { - // throw new Error(`Cannot find package.json. ${pkgJsonPath}`); - // } - // 读取 package.json - let pkgJson = await this.resolvePkgJson(pkgJsonPath); - model.pkgName = pkgJson.name; - model.pkgVersion = pkgJson.version; - if (isDepsMode) { - pkgJson = await this.resolvePkgJson(join(entry, 'package.json')); - } - if (pkgJson.module) { - // 支持 es module - model.sourceType = SourceType.MODULE; - entryFilePath = pkgJson.module; - } else if (pkgJson.main) { - // 支持 commonjs - model.sourceType = SourceType.MAIN; - entryFilePath = pkgJson.main; - } else { - entryFilePath = './index.js'; - } - entryFilePath = join(isDepsMode ? entry : cwd, entryFilePath); - log('entryFilePath', entryFilePath); - const entryFile = await this.loadFile(entryFilePath); - log('entryFile', entryFile); - model.mainEntry = entryFilePath; - // 记录入口文件 - model.modules.push({ - filePath: entryFilePath, - fileContent: entryFile, - }); - log('model', model); - // debugger; - if (options.isExportedAsMultiple) { - // 解析 entryFile,提取出 export 语句 - const modules = await this.parseEntryFile({ - entryFile, - entryFilePath, - sourceType: model.sourceType, - }); - model.modules = [...modules]; - } - log('model', model); - return model; - } - - /** - * 判断是否为文件夹 - * @param {string} filePath 文件路径 - * @returns {Promise} - * @memberof LocalScanner - */ - public async isDirectory(filePath: string): Promise { - log('materialIn', 'isDirectory - filePath', filePath); - const stats = statSync(filePath); - return stats.isDirectory(); - } - - public async loadFile(filePath: string): Promise { - const content: string | Buffer = await readFile(filePath); - if (typeof content === 'string') { - return content; - } - return content.toString(); - } - - public async resolvePkgJson( - pkgJsonPath: string, - ): Promise<{ [k: string]: any }> { - const content = await this.loadFile(pkgJsonPath); - const json = JSON.parse(content); - return json; - } - - /** - * 解析入口文件,获取要导出的模块内容 - * @private - * @param {{ - * entryFile: string; - * entryFilePath: string; - * sourceType: string; - * }} params - * @returns {Promise} - * @memberof LocalScanner - */ - private async parseEntryFile(params: { - entryFile: string; - entryFilePath: string; - sourceType: string; - }): Promise { - const modules: any = []; - const entryFileDirName = dirname(params.entryFilePath); - const ecology = await BaseParser.recognizeEcology(this.options); - if (ecology === 'react') { - const exportedList = await ReactParser.parseExportedStatement( - params.entryFile, - params.sourceType, - ); - if (Array.isArray(exportedList)) { - for (const item of exportedList) { - if (item.source && item.source.length) { - try { - let filePath = join(entryFileDirName, item.source); - if (await this.isDirectory(filePath)) { - filePath = join(filePath, 'index.js'); - } else { - filePath = join(filePath, '.js'); - } - debug('filePath', filePath); - modules.push({ - filePath, - fileContent: await this.loadFile(filePath), - }); - } catch (e) { - debug('error', 'parseEntryFile', e.message); - } - } - } - } - } - debug('modules', modules); - return modules; - } -} - -export default Scanner; diff --git a/packages/material-parser/src/types/IAccesser.ts b/packages/material-parser/src/types/IAccesser.ts index 45cfd2dd3..3b3506118 100644 --- a/packages/material-parser/src/types/IAccesser.ts +++ b/packages/material-parser/src/types/IAccesser.ts @@ -1,4 +1,4 @@ -import { IComponentMaterial } from '../otter-core'; +import { ComponentMeta } from '../otter-core'; /** * 接入器接口(用于定义物料化组件的接入渠道) @@ -10,7 +10,7 @@ interface IAccesser { * @returns {Promise} * @memberof IAccesser */ - access(): Promise; + access(): Promise; } export default IAccesser; diff --git a/packages/material-parser/src/types/IExtensionConfigManifest.ts b/packages/material-parser/src/types/IExtensionConfigManifest.ts index 5971341f3..40dba966f 100644 --- a/packages/material-parser/src/types/IExtensionConfigManifest.ts +++ b/packages/material-parser/src/types/IExtensionConfigManifest.ts @@ -1,15 +1,15 @@ -import { IComponentMaterial } from '../otter-core'; +import { ComponentMeta } from '../otter-core'; /** * 扩展点:配置 manifest * (物料化场景) */ type IExtensionConfigManifest = (params: { - manifestObj: IComponentMaterial; // manifest 配置对象 + manifestObj: ComponentMeta; // manifest 配置对象 manifestFilePath: string; // manifest 文件默认路径 }) => Promise<{ manifestJSON: string; // manifest 文件内容 manifestFilePath: string; // manifest 文件路径 - manifestObj: IComponentMaterial; // manifest 文件对象 + manifestObj: ComponentMeta; // manifest 文件对象 }>; export default IExtensionConfigManifest; diff --git a/packages/material-parser/src/types/IGenerator.ts b/packages/material-parser/src/types/IGenerator.ts deleted file mode 100644 index bd16d9ead..000000000 --- a/packages/material-parser/src/types/IGenerator.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { IComponentMaterial } from '../otter-core'; -import { IMaterialParsedModel } from './IMaterialParsedModel'; -import IMaterialScanModel from './IMaterialScanModel'; - -/** - * 生成器 - */ -export default interface IGenerator { - /** - * 根据前面两阶段的产物生成最终编排引擎需要的物料 - * @param {IMaterialScanModel} matScanModel 对应扫描阶段产物 - * @param {IMaterialParsedModel[]} matParsedModels 对应解析阶段产物 - * @returns {Promise} - * @memberof IGenerator - */ - generate( - matScanModel: IMaterialScanModel, - matParsedModels: IMaterialParsedModel[], - ): Promise; -} diff --git a/packages/material-parser/src/types/IMaterialParsedModel.ts b/packages/material-parser/src/types/IMaterialParsedModel.ts index e86046674..94cce6f75 100644 --- a/packages/material-parser/src/types/IMaterialParsedModel.ts +++ b/packages/material-parser/src/types/IMaterialParsedModel.ts @@ -12,38 +12,38 @@ export interface IPropType { export type IPropTypes = IPropType[]; export interface IMaterialParsedModel { - filePath: string; - defaultExportName: string; + // filePath: string; + componentName: string; props?: PropsSection['props']; - componentNames: Array<{ - exportedName: string; - localName: string; - source?: string; - }>; - importModules: Array<{ - importDefaultName?: string; - importName?: string; - localName?: string; - source: string; - }>; - exportModules: Array<{ - exportedName: string; - localName: string; - source?: string; - }>; - /** - * 子模块,形如:Demo.SubModule = value; 或者 Demo.SubModule.Sub = subValue; - */ - subModules: Array<{ - objectName: string[]; - propertyName: string; - value?: string; - // value 是否对应匿名函数 - isValueAnonymousFunc: boolean; - }>; - propsTypes: IPropTypes; - propsDefaults: Array<{ - name: string; - defaultValue: any; - }>; + // componentNames: { + // exportedName: string; + // localName: string; + // source?: string; + // }[]; + // importModules: { + // importDefaultName?: string; + // importName?: string; + // localName?: string; + // source: string; + // }[]; + // exportModules: { + // exportedName: string; + // localName: string; + // source?: string; + // }[]; + // /** + // * 子模块,形如:Demo.SubModule = value; 或者 Demo.SubModule.Sub = subValue; + // */ + // subModules: { + // objectName: string[]; + // propertyName: string; + // value?: string; + // // value 是否对应匿名函数 + // isValueAnonymousFunc: boolean; + // }[]; + // propsTypes: IPropTypes; + // propsDefaults: { + // name: string; + // defaultValue: any; + // }[]; } diff --git a/packages/material-parser/src/types/IMaterialScanModel.ts b/packages/material-parser/src/types/IMaterialScanModel.ts index 5e9b1551c..ae40a5043 100644 --- a/packages/material-parser/src/types/IMaterialScanModel.ts +++ b/packages/material-parser/src/types/IMaterialScanModel.ts @@ -2,15 +2,14 @@ * 对应扫描阶段的产物 */ interface IMaterialScanModel { - /** 入口文件地址 */ - mainEntry: string; /** 标记物料组件包所使用的模块规范 */ sourceType: 'module' | 'main'; - /** 每个文件对应的文件内容 */ - modules: Array<{ - filePath: string; - fileContent: string; - }>; + /** 入口文件路径 */ + entryFilePath: string; + /** 入口文件内容 */ + entryFileContent: string; + /** main文件相对路径 */ + mainFilePath: string; /** 当前包名 */ pkgName: string; /** 当前包版本 */ diff --git a/packages/material-parser/src/types/IMaterializeOptions.ts b/packages/material-parser/src/types/IMaterializeOptions.ts index 9896f3916..259656f08 100644 --- a/packages/material-parser/src/types/IMaterializeOptions.ts +++ b/packages/material-parser/src/types/IMaterializeOptions.ts @@ -7,7 +7,7 @@ import IExtensionConfigManifest from './IExtensionConfigManifest'; */ interface IMaterializeOptions { /** - * 入口文件路径或包名 + * 组件文件(夹)路径或包名 * 形如: * 本地路径:/usr/project/src/container/DemoMaterial * 包名:@ali/demo-material@0.0.1 @@ -22,21 +22,6 @@ interface IMaterializeOptions { */ accesser: 'local' | 'online'; - /** - * 是否为多组件透出场景 - * (true:表示多组件透出场景,false:表示单组件透出场景) - * @type {boolean} - * @memberof IMaterializeOptions - */ - isExportedAsMultiple: boolean; - - /** - * 当 accesser=local 时,需要通过此配置项指定当前工作目录,形如:/usr/.../demo-project - * @type {string} - * @memberof IMaterializeOptions - */ - cwd?: string; - /** * 扩展点 */ diff --git a/packages/material-parser/src/types/IParser.ts b/packages/material-parser/src/types/IParser.ts deleted file mode 100644 index 3906b5ec9..000000000 --- a/packages/material-parser/src/types/IParser.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { IMaterialParsedModel } from './IMaterialParsedModel'; -import IMaterialScanModel from './IMaterialScanModel'; - -/** - * 解析器 - * @interface IParser - */ -interface IParser { - /** - * 根据 IScanner 阶段的产出结果,解析对文件内容进行 AST 解析 - * @param {IMaterialScanModel} model IScanner 阶段的产出结果 - * @returns {Promise} - * @memberof IParser - */ - parse(model: IMaterialScanModel): Promise; - - /** - * 解析 ES5 语法 - * @param {IMaterialScanModel} model - * @returns {Promise} - * @memberof IParser - */ - parseES5(model: IMaterialScanModel): Promise; - - /** - * 解析 ESM 语法 - * @param {{ - * model: IMaterialScanModel, - * filePath: string, // 要解析的文件路径 - * fileContent: string // 要解析的文件内容 - * }} params - * @returns {Promise} - * @memberof IParser - */ - parseES6(params: { - model: IMaterialScanModel; - filePath: string; - fileContent: string; - }): Promise; -} - -export default IParser; diff --git a/packages/material-parser/src/types/IScanner.ts b/packages/material-parser/src/types/IScanner.ts deleted file mode 100644 index 2c10eda17..000000000 --- a/packages/material-parser/src/types/IScanner.ts +++ /dev/null @@ -1,32 +0,0 @@ -import IMaterialScanModel from './IMaterialScanModel'; - -/** - * 扫描器接口 - * @interface IScanner - */ -interface IScanner { - /** - * 扫描 - * @returns {Promise} 扫描产物 - * @memberof IScanner - */ - scan(): Promise; - - /** - * 加载文件 - * @param {string} filePath 文件地址 - * @returns {Promise} 返回文件内容 - * @memberof IScanner - */ - loadFile(filePath: string): Promise; - - /** - * 解析 package.json 文件 - * @param {string} pkgJsonPath 文件路径 - * @returns {Promise<{ [k: string]: any }>} package 文件信息 - * @memberof IScanner - */ - resolvePkgJson(pkgJsonPath: string): Promise<{ [k: string]: any }>; -} - -export default IScanner; diff --git a/packages/material-parser/src/types/index.ts b/packages/material-parser/src/types/index.ts index 06f5ae80e..adca16e32 100644 --- a/packages/material-parser/src/types/index.ts +++ b/packages/material-parser/src/types/index.ts @@ -4,20 +4,15 @@ import ExtensionName from './ExtensionName'; import IAccesser from './IAccesser'; import ICompiler from './ICompiler'; import IExtensionConfigManifest from './IExtensionConfigManifest'; -import IGenerator from './IGenerator'; import IMaterializeOptions from './IMaterializeOptions'; -export * from './IMaterialParsedModel'; import IMaterialScanModel from './IMaterialScanModel'; -import IParser from './IParser'; -import IScanner from './IScanner'; +import { IMaterialParsedModel } from './IMaterialParsedModel'; import SourceType from './SourceType'; export { - IGenerator, - IParser, - IScanner, ExtensionName, IExtensionConfigManifest, + IMaterialParsedModel, IMaterializeOptions, IMaterialScanModel, SourceType, diff --git a/packages/material-parser/test/Materialize.ts b/packages/material-parser/test/Materialize.ts deleted file mode 100644 index c4c81bd2a..000000000 --- a/packages/material-parser/test/Materialize.ts +++ /dev/null @@ -1,63 +0,0 @@ -import test from 'ava'; -import Materialize from '../src/Materialize'; -import { IMaterializeOptions } from '../src/types'; -import { getFromFixtures } from './helpers'; - -const multiExportedComptPath = getFromFixtures('multiple-exported-component'); -const singleExportedComptPath = getFromFixtures('single-exported-component'); -const singleExportedComponent = '@ali/demo-biz-test090702@0.0.2'; -const multipleExportedComponent = '@ali/aimake-basic@0.1.0'; - -test('materialize single exported component by local', async t => { - const options: IMaterializeOptions = { - cwd: singleExportedComptPath, - entry: singleExportedComptPath, - accesser: 'local', - isExportedAsMultiple: false, - }; - - const instance = new Materialize(options); - const actual = await instance.start(); - - t.snapshot(actual); -}); - -// test('materialize multiple exported component by local', async t => { -// const options: IMaterializeOptions = { -// cwd: multiExportedComptPath, -// entry: multiExportedComptPath, -// accesser: 'local', -// isExportedAsMultiple: true, -// }; - -// const instance = new Materialize(options); -// const actual = await instance.start(); - -// t.snapshot(actual); -// }); - -// test('materialize single exported component by online', async t => { -// const options: IMaterializeOptions = { -// entry: singleExportedComponent, -// accesser: 'online', -// isExportedAsMultiple: false, -// }; - -// const instance = new Materialize(options); -// const actual = await instance.start(); - -// t.snapshot(actual); -// }); - -// test('materialize multiple exported component by online', async t => { -// const options: IMaterializeOptions = { -// entry: multipleExportedComponent, -// accesser: 'online', -// isExportedAsMultiple: false, -// }; - -// const instance = new Materialize(options); -// const actual = await instance.start(); - -// t.snapshot(actual); -// }); diff --git a/packages/material-parser/test/accesser/LocalAccesser.ts b/packages/material-parser/test/accesser/LocalAccesser.ts deleted file mode 100644 index d09786416..000000000 --- a/packages/material-parser/test/accesser/LocalAccesser.ts +++ /dev/null @@ -1,29 +0,0 @@ -import test from 'ava'; -import LocalAccesser from '../../src/accesser/LocalAccesser'; -import { IMaterializeOptions } from '../../src/types'; -import { getFromFixtures } from '../helpers'; - -const multiExportedComptPath = getFromFixtures('multiple-exported-component'); -const singleExportedComptPath = getFromFixtures('single-exported-component'); - -test.serial('access single exported component by local', async t => { - const options: IMaterializeOptions = { - entry: singleExportedComptPath, - accesser: 'local', - isExportedAsMultiple: false, - }; - const accesser = new LocalAccesser(options); - const actual = await accesser.access(); - t.snapshot(actual); -}); - -// test.serial('access multiple exported component by local', async t => { -// const options: IMaterializeOptions = { -// entry: multiExportedComptPath, -// accesser: 'local', -// isExportedAsMultiple: true, -// }; -// const accesser = new LocalAccesser(options); -// const actual = await accesser.access(); -// t.snapshot(actual); -// }); diff --git a/packages/material-parser/test/accesser/OnlineAccesser.ts b/packages/material-parser/test/accesser/OnlineAccesser.ts deleted file mode 100644 index 83aa50963..000000000 --- a/packages/material-parser/test/accesser/OnlineAccesser.ts +++ /dev/null @@ -1,42 +0,0 @@ -import test from 'ava'; -import OnlineAccesser from '../../src/accesser/OnlineAccesser'; -import { IMaterializeOptions } from '../../src/types'; - -const singleExportedComponent = '@ali/demo-biz-test090702@0.0.2'; -const multipleExportedComponent = '@ali/aimake-basic@0.1.0'; - -test.serial('online accesser', t => { - t.pass(); -}) -// test.serial('access single exported component by online', async t => { -// const options: IMaterializeOptions = { -// entry: singleExportedComponent, -// accesser: 'online', -// isExportedAsMultiple: false, -// }; -// const accesser = new OnlineAccesser(options); -// const actual = await accesser.access(); -// t.snapshot(actual); -// }); - -// test.serial('access multiple exported component by online', async t => { -// const options: IMaterializeOptions = { -// entry: multipleExportedComponent, -// accesser: 'online', -// isExportedAsMultiple: true, -// }; -// const accesser = new OnlineAccesser(options); -// const actual = await accesser.access(); -// t.snapshot(actual); -// }); - -// test.serial('access @alifd/next@1.17.12 by online', async t => { -// const options: IMaterializeOptions = { -// entry: '@alifd/next@1.17.12', -// accesser: 'online', -// isExportedAsMultiple: true, -// }; -// const accesser = new OnlineAccesser(options); -// const actual = await accesser.access(); -// t.snapshot(actual); -// }); diff --git a/packages/material-parser/test/accesser/snapshots/LocalAccesser.ts.md b/packages/material-parser/test/accesser/snapshots/LocalAccesser.ts.md deleted file mode 100644 index b6d56ecd5..000000000 --- a/packages/material-parser/test/accesser/snapshots/LocalAccesser.ts.md +++ /dev/null @@ -1,529 +0,0 @@ -# Snapshot report for `test/accesser/LocalAccesser.ts` - -The actual snapshot is saved in `LocalAccesser.ts.snap`. - -Generated by [AVA](https://ava.li). - -## access multiple exported component by local - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.js', - manifestJS: 'export default {"name":"AIMakeBlank","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"styleFlexLayout","label":"styleFlexLayout","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"},{"name":"id","label":"id","renderer":""}]}}', - manifestObj: { - name: 'AIMakeBlank', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleFlexLayout', - name: 'styleFlexLayout', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - { - defaultValue: undefined, - label: 'id', - name: 'id', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.js', - manifestJS: 'export default {"name":"AIMakeIcon","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"className","label":"className","renderer":""},{"name":"iconClassName","label":"iconClassName","renderer":""},{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleText","label":"styleText","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeIcon', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'className', - name: 'className', - renderer: '', - }, - { - defaultValue: undefined, - label: 'iconClassName', - name: 'iconClassName', - renderer: '', - }, - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleText', - name: 'styleText', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.js', - manifestJS: 'export default {"name":"AIMakeImage","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeImage', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.js', - manifestJS: 'export default {"name":"AIMakeLink","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleText","label":"styleText","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeLink', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleText', - name: 'styleText', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.js', - manifestJS: 'export default {"name":"AIMakePlaceholder","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakePlaceholder', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.js', - manifestJS: 'export default {"name":"AIMakeText","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"type","label":"type","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleText","label":"styleText","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeText', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'type', - name: 'type', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleText', - name: 'styleText', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.js', - manifestJS: 'export default {"name":"Root","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"style","label":"style","renderer":"","defaultValue":"{\\n padding: 0,\\n backgroundColor: \'#f0f2f5\',\\n minHeight: \'100%\'\\n}"},{"name":"children","label":"children","renderer":""}]}}', - manifestObj: { - name: 'Root', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: `{␊ - padding: 0,␊ - backgroundColor: '#f0f2f5',␊ - minHeight: '100%'␊ - }`, - label: 'style', - name: 'style', - renderer: '', - }, - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - ] - -## access single exported component by local - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/manifest.js', - manifestJS: 'export default {"name":"Demo","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"optionalArray","label":"optionalArray","renderer":""},{"name":"optionalBool","label":"optionalBool","renderer":""},{"name":"optionalFunc","label":"optionalFunc","renderer":""},{"name":"optionalNumber","label":"optionalNumber","renderer":""},{"name":"optionalObject","label":"optionalObject","renderer":""},{"name":"optionalString","label":"optionalString","renderer":""},{"name":"optionalSymbol","label":"optionalSymbol","renderer":""},{"name":"optionalNode","label":"optionalNode","renderer":""},{"name":"optionalElement","label":"optionalElement","renderer":""},{"name":"optionalElementType","label":"optionalElementType","renderer":""},{"name":"optionalMessage","label":"optionalMessage","renderer":""},{"name":"optionalEnum","label":"optionalEnum","renderer":""},{"name":"optionalUnion","label":"optionalUnion","renderer":""},{"name":"optionalArrayOf","label":"optionalArrayOf","renderer":""},{"name":"optionalObjectOf","label":"optionalObjectOf","renderer":""},{"name":"optionalObjectWithShape","label":"optionalObjectWithShape","renderer":""},{"name":"optionalObjectWithShape2","label":"optionalObjectWithShape2","renderer":""},{"name":"optionalObjectWithStrictShape","label":"optionalObjectWithStrictShape","renderer":""},{"name":"requiredFunc","label":"requiredFunc","renderer":""},{"name":"requiredAny","label":"requiredAny","renderer":""}]}}', - manifestObj: { - name: 'Demo', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'optionalArray', - name: 'optionalArray', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalBool', - name: 'optionalBool', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalFunc', - name: 'optionalFunc', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalNumber', - name: 'optionalNumber', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalObject', - name: 'optionalObject', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalString', - name: 'optionalString', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalSymbol', - name: 'optionalSymbol', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalNode', - name: 'optionalNode', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalElement', - name: 'optionalElement', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalElementType', - name: 'optionalElementType', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalMessage', - name: 'optionalMessage', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalEnum', - name: 'optionalEnum', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalUnion', - name: 'optionalUnion', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalArrayOf', - name: 'optionalArrayOf', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalObjectOf', - name: 'optionalObjectOf', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalObjectWithShape', - name: 'optionalObjectWithShape', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalObjectWithShape2', - name: 'optionalObjectWithShape2', - renderer: '', - }, - { - defaultValue: undefined, - label: 'optionalObjectWithStrictShape', - name: 'optionalObjectWithStrictShape', - renderer: '', - }, - { - defaultValue: undefined, - label: 'requiredFunc', - name: 'requiredFunc', - renderer: '', - }, - { - defaultValue: undefined, - label: 'requiredAny', - name: 'requiredAny', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - ] diff --git a/packages/material-parser/test/accesser/snapshots/LocalAccesser.ts.snap b/packages/material-parser/test/accesser/snapshots/LocalAccesser.ts.snap deleted file mode 100644 index 0d3c837c2..000000000 Binary files a/packages/material-parser/test/accesser/snapshots/LocalAccesser.ts.snap and /dev/null differ diff --git a/packages/material-parser/test/accesser/snapshots/OnlineAccesser.ts.md b/packages/material-parser/test/accesser/snapshots/OnlineAccesser.ts.md deleted file mode 100644 index fc1e99f97..000000000 --- a/packages/material-parser/test/accesser/snapshots/OnlineAccesser.ts.md +++ /dev/null @@ -1,408 +0,0 @@ -# Snapshot report for `test/accesser/OnlineAccesser.ts` - -The actual snapshot is saved in `OnlineAccesser.ts.snap`. - -Generated by [AVA](https://ava.li). - -## access multiple exported component by online - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/kDKCQ3wGKzpHh6KU5ExdE1/node_modules/@ali/aimake-basic/es/basic/AIMakeBlank/manifest.js', - manifestJS: 'export default {"name":"AIMakeBlank","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"styleFlexLayout","label":"styleFlexLayout","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"},{"name":"id","label":"id","renderer":""}]}}', - manifestObj: { - name: 'AIMakeBlank', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleFlexLayout', - name: 'styleFlexLayout', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - { - defaultValue: undefined, - label: 'id', - name: 'id', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/kDKCQ3wGKzpHh6KU5ExdE1/node_modules/@ali/aimake-basic/es/basic/AIMakeIcon/manifest.js', - manifestJS: 'export default {"name":"AIMakeIcon","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"className","label":"className","renderer":""},{"name":"iconClassName","label":"iconClassName","renderer":""},{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleText","label":"styleText","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeIcon', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'className', - name: 'className', - renderer: '', - }, - { - defaultValue: undefined, - label: 'iconClassName', - name: 'iconClassName', - renderer: '', - }, - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleText', - name: 'styleText', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/kDKCQ3wGKzpHh6KU5ExdE1/node_modules/@ali/aimake-basic/es/basic/AIMakeImage/manifest.js', - manifestJS: 'export default {"name":"AIMakeImage","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeImage', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/kDKCQ3wGKzpHh6KU5ExdE1/node_modules/@ali/aimake-basic/es/basic/AIMakeLink/manifest.js', - manifestJS: 'export default {"name":"AIMakeLink","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleText","label":"styleText","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeLink', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleText', - name: 'styleText', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/kDKCQ3wGKzpHh6KU5ExdE1/node_modules/@ali/aimake-basic/es/basic/AIMakePlaceholder/manifest.js', - manifestJS: 'export default {"name":"AIMakePlaceholder","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakePlaceholder', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/kDKCQ3wGKzpHh6KU5ExdE1/node_modules/@ali/aimake-basic/es/basic/AIMakeText/manifest.js', - manifestJS: 'export default {"name":"AIMakeText","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"children","label":"children","renderer":""},{"name":"type","label":"type","renderer":""},{"name":"styleBoxModel","label":"styleBoxModel","renderer":""},{"name":"styleText","label":"styleText","renderer":""},{"name":"styleLayout","label":"styleLayout","renderer":""},{"name":"styleBackground","label":"styleBackground","renderer":""},{"name":"style","label":"style","renderer":"","defaultValue":"{}"}]}}', - manifestObj: { - name: 'AIMakeText', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - { - defaultValue: undefined, - label: 'type', - name: 'type', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBoxModel', - name: 'styleBoxModel', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleText', - name: 'styleText', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleLayout', - name: 'styleLayout', - renderer: '', - }, - { - defaultValue: undefined, - label: 'styleBackground', - name: 'styleBackground', - renderer: '', - }, - { - defaultValue: '{}', - label: 'style', - name: 'style', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/kDKCQ3wGKzpHh6KU5ExdE1/node_modules/@ali/aimake-basic/es/basic/Root/manifest.js', - manifestJS: 'export default {"name":"Root","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[{"name":"style","label":"style","renderer":"","defaultValue":"{\\n padding: 0,\\n backgroundColor: \'#f0f2f5\',\\n minHeight: \'100%\'\\n}"},{"name":"children","label":"children","renderer":""}]}}', - manifestObj: { - name: 'Root', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [ - { - defaultValue: `{␊ - padding: 0,␊ - backgroundColor: '#f0f2f5',␊ - minHeight: '100%'␊ - }`, - label: 'style', - name: 'style', - renderer: '', - }, - { - defaultValue: undefined, - label: 'children', - name: 'children', - renderer: '', - }, - ], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - ] - -## access single exported component by online - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/node_modules/.temp/todtaTTK9KxDGepu5Kbb9G/node_modules/@ali/demo-biz-test090702/es/manifest.js', - manifestJS: 'export default {"name":"Demo","settings":{"type":"element_inline","insertionModes":"tbrl","handles":["cut","copy","duplicate","delete","paste"],"shouldActive":true,"shouldDrag":true,"props":[]}}', - manifestObj: { - name: 'Demo', - settings: { - handles: [ - 'cut', - 'copy', - 'duplicate', - 'delete', - 'paste', - ], - insertionModes: 'tbrl', - props: [], - shouldActive: true, - shouldDrag: true, - type: 'element_inline', - }, - }, - }, - ] diff --git a/packages/material-parser/test/accesser/snapshots/OnlineAccesser.ts.snap b/packages/material-parser/test/accesser/snapshots/OnlineAccesser.ts.snap deleted file mode 100644 index e8ea50d94..000000000 Binary files a/packages/material-parser/test/accesser/snapshots/OnlineAccesser.ts.snap and /dev/null differ diff --git a/packages/material-parser/test/fixtures/__snapshots__/test/Materialize.ts.md b/packages/material-parser/test/fixtures/__snapshots__/test/Materialize.ts.md deleted file mode 100644 index 7a2d6f6db..000000000 --- a/packages/material-parser/test/fixtures/__snapshots__/test/Materialize.ts.md +++ /dev/null @@ -1,188 +0,0 @@ -# Snapshot report for `test/Materialize.ts` - -The actual snapshot is saved in `Materialize.ts.snap`. - -Generated by [AVA](https://avajs.dev). - -## materialize single exported component by local - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js', - package: 'single-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'optionalArray', - propType: 'array', - }, - { - name: 'optionalBool', - propType: 'bool', - }, - { - name: 'optionalFunc', - propType: 'func', - }, - { - defaultValue: 123, - name: 'optionalNumber', - propType: 'number', - }, - { - name: 'optionalObject', - propType: 'object', - }, - { - name: 'optionalString', - propType: 'string', - }, - { - name: 'optionalSymbol', - propType: 'symbol', - }, - { - name: 'optionalNode', - propType: 'node', - }, - { - name: 'optionalElement', - propType: 'element', - }, - { - name: 'optionalElementType', - propType: 'elementType', - }, - { - name: 'optionalMessage', - propType: { - type: 'instanceOf', - value: 'Demo', - }, - }, - { - name: 'optionalEnum', - propType: { - type: 'oneOf', - value: [ - 'News', - 'Photos', - ], - }, - }, - { - name: 'optionalUnion', - propType: { - type: 'oneOfType', - value: [ - 'string', - 'number', - { - type: 'instanceOf', - value: 'Demo', - }, - ], - }, - }, - { - name: 'optionalArrayOf', - propType: { - type: 'arrayOf', - value: 'number', - }, - }, - { - name: 'optionalObjectOf', - propType: { - type: 'objectOf', - value: 'number', - }, - }, - { - name: 'optionalObjectWithShape', - propType: { - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithShape2', - propType: { - isRequired: true, - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithStrictShape', - propType: { - type: 'exact', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'requiredFunc', - propType: { - isRequired: true, - type: 'func', - }, - }, - { - name: 'requiredAny', - propType: { - isRequired: true, - type: 'any', - }, - }, - ], - screenshot: '', - title: 'single-exported-component', - }, - }, - ] diff --git a/packages/material-parser/test/fixtures/__snapshots__/test/Materialize.ts.snap b/packages/material-parser/test/fixtures/__snapshots__/test/Materialize.ts.snap deleted file mode 100644 index c49d07908..000000000 Binary files a/packages/material-parser/test/fixtures/__snapshots__/test/Materialize.ts.snap and /dev/null differ diff --git a/packages/material-parser/test/fixtures/__snapshots__/test/accesser/LocalAccesser.ts.md b/packages/material-parser/test/fixtures/__snapshots__/test/accesser/LocalAccesser.ts.md deleted file mode 100644 index 27bbbe3db..000000000 --- a/packages/material-parser/test/fixtures/__snapshots__/test/accesser/LocalAccesser.ts.md +++ /dev/null @@ -1,188 +0,0 @@ -# Snapshot report for `test/accesser/LocalAccesser.ts` - -The actual snapshot is saved in `LocalAccesser.ts.snap`. - -Generated by [AVA](https://avajs.dev). - -## access single exported component by local - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js', - package: '@ali/lowcode-engine-material-parser', - subName: '', - version: '0.1.0', - }, - props: [ - { - name: 'optionalArray', - propType: 'array', - }, - { - name: 'optionalBool', - propType: 'bool', - }, - { - name: 'optionalFunc', - propType: 'func', - }, - { - defaultValue: 123, - name: 'optionalNumber', - propType: 'number', - }, - { - name: 'optionalObject', - propType: 'object', - }, - { - name: 'optionalString', - propType: 'string', - }, - { - name: 'optionalSymbol', - propType: 'symbol', - }, - { - name: 'optionalNode', - propType: 'node', - }, - { - name: 'optionalElement', - propType: 'element', - }, - { - name: 'optionalElementType', - propType: 'elementType', - }, - { - name: 'optionalMessage', - propType: { - type: 'instanceOf', - value: 'Demo', - }, - }, - { - name: 'optionalEnum', - propType: { - type: 'oneOf', - value: [ - 'News', - 'Photos', - ], - }, - }, - { - name: 'optionalUnion', - propType: { - type: 'oneOfType', - value: [ - 'string', - 'number', - { - type: 'instanceOf', - value: 'Demo', - }, - ], - }, - }, - { - name: 'optionalArrayOf', - propType: { - type: 'arrayOf', - value: 'number', - }, - }, - { - name: 'optionalObjectOf', - propType: { - type: 'objectOf', - value: 'number', - }, - }, - { - name: 'optionalObjectWithShape', - propType: { - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithShape2', - propType: { - isRequired: true, - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithStrictShape', - propType: { - type: 'exact', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'requiredFunc', - propType: { - isRequired: true, - type: 'func', - }, - }, - { - name: 'requiredAny', - propType: { - isRequired: true, - type: 'any', - }, - }, - ], - screenshot: '', - title: '@ali/lowcode-engine-material-parser', - }, - }, - ] diff --git a/packages/material-parser/test/fixtures/__snapshots__/test/accesser/LocalAccesser.ts.snap b/packages/material-parser/test/fixtures/__snapshots__/test/accesser/LocalAccesser.ts.snap deleted file mode 100644 index 368768b7c..000000000 Binary files a/packages/material-parser/test/fixtures/__snapshots__/test/accesser/LocalAccesser.ts.snap and /dev/null differ diff --git a/packages/material-parser/test/fixtures/__snapshots__/test/generator/Generator.ts.md b/packages/material-parser/test/fixtures/__snapshots__/test/generator/Generator.ts.md deleted file mode 100644 index d01bf610e..000000000 --- a/packages/material-parser/test/fixtures/__snapshots__/test/generator/Generator.ts.md +++ /dev/null @@ -1,1135 +0,0 @@ -# Snapshot report for `test/generator/Generator.ts` - -The actual snapshot is saved in `Generator.ts.snap`. - -Generated by [AVA](https://avajs.dev). - -## generate multiple exported components - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleFlexLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - { - name: 'id', - propType: 'string', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'className', - propType: 'string', - }, - { - name: 'iconClassName', - propType: 'string', - }, - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleText', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleText', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - 'string', - ], - }, - }, - { - name: 'type', - propType: 'string', - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleText', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'style', - propType: 'object', - }, - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - 'element', - { - type: 'arrayOf', - value: 'element', - }, - ], - }, - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - ] - -## generate multiple exported components with extensions - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleFlexLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - { - name: 'id', - propType: 'string', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'className', - propType: 'string', - }, - { - name: 'iconClassName', - propType: 'string', - }, - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleText', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleText', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - ], - }, - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - { - type: 'arrayOf', - value: 'node', - }, - 'node', - 'string', - ], - }, - }, - { - name: 'type', - propType: 'string', - }, - { - name: 'styleBoxModel', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleText', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleLayout', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'styleBackground', - propType: { - isRequired: true, - type: 'object', - }, - }, - { - name: 'style', - propType: 'object', - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js', - package: 'multiple-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'style', - propType: 'object', - }, - { - name: 'children', - propType: { - type: 'oneOfType', - value: [ - 'element', - { - type: 'arrayOf', - value: 'element', - }, - ], - }, - }, - ], - screenshot: '', - title: 'multiple-exported-component', - }, - }, - ] - -## generate single exported components - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js', - package: 'single-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'optionalArray', - propType: 'array', - }, - { - name: 'optionalBool', - propType: 'bool', - }, - { - name: 'optionalFunc', - propType: 'func', - }, - { - defaultValue: 123, - name: 'optionalNumber', - propType: 'number', - }, - { - name: 'optionalObject', - propType: 'object', - }, - { - name: 'optionalString', - propType: 'string', - }, - { - name: 'optionalSymbol', - propType: 'symbol', - }, - { - name: 'optionalNode', - propType: 'node', - }, - { - name: 'optionalElement', - propType: 'element', - }, - { - name: 'optionalElementType', - propType: 'elementType', - }, - { - name: 'optionalMessage', - propType: { - type: 'instanceOf', - value: 'Demo', - }, - }, - { - name: 'optionalEnum', - propType: { - type: 'oneOf', - value: [ - 'News', - 'Photos', - ], - }, - }, - { - name: 'optionalUnion', - propType: { - type: 'oneOfType', - value: [ - 'string', - 'number', - { - type: 'instanceOf', - value: 'Demo', - }, - ], - }, - }, - { - name: 'optionalArrayOf', - propType: { - type: 'arrayOf', - value: 'number', - }, - }, - { - name: 'optionalObjectOf', - propType: { - type: 'objectOf', - value: 'number', - }, - }, - { - name: 'optionalObjectWithShape', - propType: { - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithShape2', - propType: { - isRequired: true, - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithStrictShape', - propType: { - type: 'exact', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'requiredFunc', - propType: { - isRequired: true, - type: 'func', - }, - }, - { - name: 'requiredAny', - propType: { - isRequired: true, - type: 'any', - }, - }, - ], - screenshot: '', - title: 'single-exported-component', - }, - }, - ] - -## generate single exported components with extensions - -> Snapshot 1 - - [ - { - manifestFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/src/manifest.json', - manifestObj: { - docUrl: '', - npm: { - destructuring: false, - exportName: '', - main: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js', - package: 'single-exported-component', - subName: '', - version: '1.0.0', - }, - props: [ - { - name: 'optionalArray', - propType: 'array', - }, - { - name: 'optionalBool', - propType: 'bool', - }, - { - name: 'optionalFunc', - propType: 'func', - }, - { - defaultValue: 123, - name: 'optionalNumber', - propType: 'number', - }, - { - name: 'optionalObject', - propType: 'object', - }, - { - name: 'optionalString', - propType: 'string', - }, - { - name: 'optionalSymbol', - propType: 'symbol', - }, - { - name: 'optionalNode', - propType: 'node', - }, - { - name: 'optionalElement', - propType: 'element', - }, - { - name: 'optionalElementType', - propType: 'elementType', - }, - { - name: 'optionalMessage', - propType: { - type: 'instanceOf', - value: 'Demo', - }, - }, - { - name: 'optionalEnum', - propType: { - type: 'oneOf', - value: [ - 'News', - 'Photos', - ], - }, - }, - { - name: 'optionalUnion', - propType: { - type: 'oneOfType', - value: [ - 'string', - 'number', - { - type: 'instanceOf', - value: 'Demo', - }, - ], - }, - }, - { - name: 'optionalArrayOf', - propType: { - type: 'arrayOf', - value: 'number', - }, - }, - { - name: 'optionalObjectOf', - propType: { - type: 'objectOf', - value: 'number', - }, - }, - { - name: 'optionalObjectWithShape', - propType: { - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithShape2', - propType: { - isRequired: true, - type: 'shape', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'optionalObjectWithStrictShape', - propType: { - type: 'exact', - value: [ - { - name: 'optionalProperty', - propType: 'string', - }, - { - name: 'requiredProperty', - propType: { - isRequired: true, - type: 'number', - }, - }, - ], - }, - }, - { - name: 'requiredFunc', - propType: { - isRequired: true, - type: 'func', - }, - }, - { - name: 'requiredAny', - propType: { - isRequired: true, - type: 'any', - }, - }, - ], - screenshot: '', - title: 'single-exported-component', - }, - }, - ] diff --git a/packages/material-parser/test/fixtures/__snapshots__/test/generator/Generator.ts.snap b/packages/material-parser/test/fixtures/__snapshots__/test/generator/Generator.ts.snap deleted file mode 100644 index 6da53d5f1..000000000 Binary files a/packages/material-parser/test/fixtures/__snapshots__/test/generator/Generator.ts.snap and /dev/null differ diff --git a/packages/material-parser/test/fixtures/__snapshots__/test/index.ts.md b/packages/material-parser/test/fixtures/__snapshots__/test/index.ts.md new file mode 100644 index 000000000..79bf25dc7 --- /dev/null +++ b/packages/material-parser/test/fixtures/__snapshots__/test/index.ts.md @@ -0,0 +1,9746 @@ +# Snapshot report for `test/index.ts` + +The actual snapshot is saved in `index.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## fusion next component by local + +> Snapshot 1 + + [ + { + componentName: 'Affix', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Affix', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: Function {}, + description: `设置 Affix 需要监听滚动事件的容器元素␊ + @return {ReactElement} 目标容器元素的实例`, + name: 'container', + propType: 'func', + }, + { + description: '距离窗口顶部达到指定偏移量后触发', + name: 'offsetTop', + propType: 'number', + }, + { + description: '距离窗口底部达到制定偏移量后触发', + name: 'offsetBottom', + propType: 'number', + }, + { + description: `当元素的样式发生固钉样式变化时触发的回调函数␊ + @param {Boolean} affixed 元素是否被固钉`, + name: 'onAffix', + propType: 'func', + }, + { + description: `是否启用绝对布局实现 affix␊ + @param {Boolean} 是否启用绝对布局`, + name: 'useAbsolute', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'style', + propType: 'object', + }, + { + name: 'children', + propType: 'any', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Animate', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Animate', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + description: '动画 className', + name: 'animation', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'object', + ], + }, + }, + { + defaultValue: true, + description: '子元素第一次挂载时是否执行动画', + name: 'animationAppear', + propType: 'bool', + }, + { + defaultValue: 'div', + description: '包裹子元素的标签', + name: 'component', + propType: 'any', + }, + { + defaultValue: true, + description: '是否只有单个子元素,如果有多个子元素,请设置为 false', + name: 'singleMode', + propType: 'bool', + }, + { + description: '子元素', + name: 'children', + propType: { + type: 'oneOfType', + value: [ + 'element', + { + type: 'arrayOf', + value: 'element', + }, + ], + }, + }, + { + defaultValue: Function {}, + description: `执行第一次挂载动画前触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'beforeAppear', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行第一次挂载动画,添加 xxx-appear-active 类名后触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'onAppear', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行完第一次挂载动画后触发的函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'afterAppear', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行进场动画前触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'beforeEnter', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行进场动画,添加 xxx-enter-active 类名后触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'onEnter', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行完进场动画后触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'afterEnter', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行离场动画前触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'beforeLeave', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行离场动画,添加 xxx-leave-active 类名后触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'onLeave', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `执行完离场动画后触发的回调函数␊ + @param {HTMLElement} node 执行动画的 dom 元素`, + name: 'afterLeave', + propType: 'func', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Badge', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Badge', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'style', + propType: 'object', + }, + { + description: '徽章依托的内容', + name: 'children', + propType: 'node', + }, + { + defaultValue: 0, + description: '展示的数字,大于 overflowCount 时显示为 ${overflowCount}+,为 0 时默认隐藏', + name: 'count', + propType: { + type: 'oneOfType', + value: [ + 'number', + 'string', + ], + }, + }, + { + defaultValue: false, + description: '当count为0时,是否显示count', + name: 'showZero', + propType: 'bool', + }, + { + description: '自定义节点内容', + name: 'content', + propType: 'node', + }, + { + defaultValue: 99, + description: '展示的封顶的数字', + name: 'overflowCount', + propType: { + type: 'oneOfType', + value: [ + 'number', + 'string', + ], + }, + }, + { + defaultValue: false, + description: '不展示数字,只展示一个小红点', + name: 'dot', + propType: 'bool', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Balloon', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Balloon', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + description: '自定义类名', + name: 'className', + propType: 'string', + }, + { + description: '自定义内敛样式', + name: 'style', + propType: 'object', + }, + { + description: '浮层的内容', + name: 'children', + propType: 'any', + }, + { + defaultValue: 'medium', + name: 'size', + propType: 'string', + }, + { + defaultValue: 'normal', + description: '样式类型', + name: 'type', + propType: { + type: 'oneOf', + value: [ + 'normal', + 'primary', + ], + }, + }, + { + description: '弹层当前显示的状态', + name: 'visible', + propType: 'bool', + }, + { + defaultValue: false, + description: '弹层默认显示的状态', + name: 'defaultVisible', + propType: 'bool', + }, + { + description: `弹层在显示和隐藏触发的事件␊ + @param {Boolean} visible 弹层是否隐藏和显示␊ + @param {String} type 触发弹层显示或隐藏的来源, closeClick 表示由自带的关闭按钮触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发`, + name: 'onVisibleChange', + propType: 'func', + }, + { + defaultValue: false, + description: '弹出层对齐方式, 是否为边缘对齐', + name: 'alignEdge', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否显示关闭按钮', + name: 'closable', + propType: 'bool', + }, + { + defaultValue: 'b', + description: `弹出层位置␊ + @enumdesc 上, 右, 下, 左, 上左, 上右, 下左, 下右, 左上, 左下, 右上, 右下 及其 两两组合`, + name: 'align', + propType: { + type: 'oneOf', + value: [ + 't', + 'r', + 'b', + 'l', + 'tl', + 'tr', + 'bl', + 'br', + 'lt', + 'lb', + 'rt', + 'rb', + ], + }, + }, + { + defaultValue: [ + 0, + 0, + ], + description: `弹层相对于trigger的定位的微调, 接收数组[hoz, ver], 表示弹层在 left / top 上的增量␊ + e.g. [100, 100] 表示往右(RTL 模式下是往左) 、下分布偏移100px`, + name: 'offset', + propType: 'array', + }, + { + description: '触发元素', + name: 'trigger', + propType: 'any', + }, + { + defaultValue: 'hover', + description: `触发行为␊ + 鼠标悬浮, 鼠标点击('hover','click')或者它们组成的数组,如 ['hover', 'click'], 强烈不建议使用'focus',若弹窗内容有复杂交互请使用click`, + name: 'triggerType', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + name: 'onClick', + propType: 'func', + }, + { + description: '任何visible为false时会触发的事件', + name: 'onClose', + propType: 'func', + }, + { + name: 'onHover', + propType: 'func', + }, + { + defaultValue: false, + description: '是否进行自动位置调整', + name: 'needAdjust', + propType: 'bool', + }, + { + description: '弹层在触发以后的延时显示, 单位毫秒 ms', + name: 'delay', + propType: 'number', + }, + { + description: '浮层关闭后触发的事件, 如果有动画,则在动画结束后触发', + name: 'afterClose', + propType: 'func', + }, + { + description: '强制更新定位信息', + name: 'shouldUpdatePosition', + propType: 'bool', + }, + { + defaultValue: true, + description: '弹层出现后是否自动focus到内部第一个元素', + name: 'autoFocus', + propType: 'bool', + }, + { + defaultValue: undefined, + description: '安全节点:对于triggetType为click的浮层,会在点击除了浮层外的其它区域时关闭浮层.safeNode用于添加不触发关闭的节点, 值可以是dom节点的id或者是节点的dom对象', + name: 'safeNode', + propType: 'string', + }, + { + defaultValue: null, + description: '用来指定safeNode节点的id,和safeNode配合使用', + name: 'safeId', + propType: 'string', + }, + { + description: `配置动画的播放方式␊ + @param {String} in 进场动画␊ + @param {String} out 出场动画`, + name: 'animation', + propType: { + type: 'oneOfType', + value: [ + 'object', + 'bool', + ], + }, + }, + { + defaultValue: false, + description: '弹层的dom节点关闭时是否删除', + name: 'cache', + propType: 'bool', + }, + { + description: '指定浮层渲染的父节点, 可以为节点id的字符串,也可以返回节点的函数。', + name: 'popupContainer', + propType: 'any', + }, + { + name: 'container', + propType: 'any', + }, + { + defaultValue: undefined, + description: '弹层组件style,透传给Popup', + name: 'popupStyle', + propType: 'object', + }, + { + defaultValue: '', + description: '弹层组件className,透传给Popup', + name: 'popupClassName', + propType: 'string', + }, + { + defaultValue: undefined, + description: '弹层组件属性,透传给Popup', + name: 'popupProps', + propType: 'object', + }, + { + description: '是否跟随滚动', + name: 'followTrigger', + propType: 'bool', + }, + { + description: '弹层id, 传入值才会支持无障碍', + name: 'id', + propType: 'string', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Breadcrumb', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Breadcrumb', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + description: '样式类名的品牌前缀', + name: 'prefix', + propType: 'string', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + description: '面包屑子节点,需传入 Breadcrumb.Item', + name: 'children', + propType: 'custom', + }, + { + defaultValue: 100, + description: '面包屑最多显示个数,超出部分会被隐藏, 设置为 auto 会自动根据父元素的宽度适配。', + name: 'maxNode', + propType: { + type: 'oneOfType', + value: [ + 'number', + { + type: 'oneOf', + value: [ + 'auto', + ], + }, + ], + }, + }, + { + description: '分隔符,可以是文本或 Icon', + name: 'separator', + propType: 'node', + }, + { + defaultValue: 'nav', + description: '设置标签类型', + name: 'component', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'func', + ], + }, + }, + { + name: 'className', + propType: 'any', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Button', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Button', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + defaultValue: 'normal', + description: '按钮的类型', + name: 'type', + propType: { + type: 'oneOf', + value: [ + 'primary', + 'secondary', + 'normal', + ], + }, + }, + { + defaultValue: 'medium', + description: '按钮的尺寸', + name: 'size', + propType: { + type: 'oneOf', + value: [ + 'small', + 'medium', + 'large', + ], + }, + }, + { + description: '按钮中 Icon 的尺寸,用于替代 Icon 的默认大小', + name: 'iconSize', + propType: { + type: 'oneOf', + value: [ + 'xxs', + 'xs', + 'small', + 'medium', + 'large', + 'xl', + 'xxl', + 'xxxl', + ], + }, + }, + { + defaultValue: 'button', + description: '当 component = \'button\' 时,设置 button 标签的 type 值', + name: 'htmlType', + propType: { + type: 'oneOf', + value: [ + 'submit', + 'reset', + 'button', + ], + }, + }, + { + defaultValue: 'button', + description: '设置标签类型', + name: 'component', + propType: { + type: 'oneOf', + value: [ + 'button', + 'a', + 'div', + 'span', + ], + }, + }, + { + defaultValue: false, + description: '设置按钮的载入状态', + name: 'loading', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否为幽灵按钮', + name: 'ghost', + propType: { + type: 'oneOf', + value: [ + true, + false, + 'light', + 'dark', + ], + }, + }, + { + defaultValue: false, + description: '是否为文本按钮', + name: 'text', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否为警告按钮', + name: 'warning', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否禁用', + name: 'disabled', + propType: 'bool', + }, + { + defaultValue: Function {}, + description: `点击按钮的回调␊ + @param {Object} e Event Object`, + name: 'onClick', + propType: 'func', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'onMouseUp', + propType: 'func', + }, + { + name: 'children', + propType: 'node', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Calendar', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Calendar', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'rtl', + propType: 'bool', + }, + { + description: '默认选中的日期(moment 对象)', + name: 'defaultValue', + propType: 'custom', + }, + { + description: '选中的日期值 (moment 对象)', + name: 'value', + propType: 'custom', + }, + { + name: 'modes', + propType: 'array', + }, + { + defaultValue: false, + name: 'disableChangeMode', + propType: 'bool', + }, + { + defaultValue: 'YYYY-MM-DD', + name: 'format', + propType: 'string', + }, + { + defaultValue: true, + description: '是否展示非本月的日期', + name: 'showOtherMonth', + propType: 'bool', + }, + { + description: '默认展示的月份', + name: 'defaultVisibleMonth', + propType: 'func', + }, + { + defaultValue: 'fullscreen', + description: '展现形态', + name: 'shape', + propType: { + type: 'oneOf', + value: [ + 'card', + 'fullscreen', + 'panel', + ], + }, + }, + { + description: `选择日期单元格时的回调␊ + @param {Object} value 对应的日期值 (moment 对象)`, + name: 'onSelect', + propType: 'func', + }, + { + description: `面板模式变化时的回调␊ + @param {String} mode 对应面板模式 date month year`, + name: 'onModeChange', + propType: 'func', + }, + { + description: `展现的月份变化时的回调␊ + @param {Object} value 显示的月份 (moment 对象)␊ + @param {String} reason 触发月份改变原因`, + name: 'onVisibleMonthChange', + propType: 'func', + }, + { + description: '自定义样式类', + name: 'className', + propType: 'string', + }, + { + defaultValue: Function {}, + description: `自定义日期渲染函数␊ + @param {Object} value 日期值(moment对象)␊ + @returns {ReactNode}`, + name: 'dateCellRender', + propType: 'func', + }, + { + description: `自定义月份渲染函数␊ + @param {Object} calendarDate 对应 Calendar 返回的自定义日期对象␊ + @returns {ReactNode}`, + name: 'monthCellRender', + propType: 'func', + }, + { + name: 'yearCellRender', + propType: 'func', + }, + { + description: '年份范围,[START_YEAR, END_YEAR] (只在shape 为 ‘card’, \'fullscreen\' 下生效)', + name: 'yearRange', + propType: { + type: 'arrayOf', + value: 'number', + }, + }, + { + description: `不可选择的日期␊ + @param {Object} calendarDate 对应 Calendar 返回的自定义日期对象␊ + @param {String} view 当前视图类型,year: 年, month: 月, date: 日␊ + @returns {Boolean}`, + name: 'disabledDate', + propType: 'func', + }, + { + description: '国际化配置', + name: 'locale', + propType: 'object', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Card', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Card', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + description: '卡片的上的图片 / 视频', + name: 'media', + propType: 'node', + }, + { + description: '卡片的标题', + name: 'title', + propType: 'node', + }, + { + description: '卡片的副标题', + name: 'subTitle', + propType: 'node', + }, + { + description: '卡片操作组,位置在卡片底部', + name: 'actions', + propType: 'node', + }, + { + defaultValue: true, + description: '是否显示标题的项目符号', + name: 'showTitleBullet', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否展示头部的分隔线', + name: 'showHeadDivider', + propType: 'bool', + }, + { + defaultValue: 120, + description: '内容区域的固定高度', + name: 'contentHeight', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'number', + ], + }, + }, + { + description: '标题区域的用户自定义内容', + name: 'extra', + propType: 'node', + }, + { + defaultValue: false, + description: '是否开启自由模式,开启后card 将使用子组件配合使用, 设置此项后 title, subtitle, 等等属性都将失效', + name: 'free', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'children', + propType: 'node', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Cascader', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Cascader', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'rtl', + propType: 'bool', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + defaultValue: [], + description: '数据源,结构可参考下方说明', + name: 'dataSource', + propType: { + type: 'arrayOf', + value: 'object', + }, + }, + { + defaultValue: null, + description: '(非受控)默认值', + name: 'defaultValue', + propType: { + type: 'oneOfType', + value: [ + 'string', + { + type: 'arrayOf', + value: 'string', + }, + ], + }, + }, + { + description: '(受控)当前值', + name: 'value', + propType: { + type: 'oneOfType', + value: [ + 'string', + { + type: 'arrayOf', + value: 'string', + }, + ], + }, + }, + { + description: `选中值改变时触发的回调函数␊ + @param {String|Array} value 选中的值,单选时返回单个值,多选时返回数组␊ + @param {Object|Array} data 选中的数据,包括 value 和 label,单选时返回单个值,多选时返回数组,父子节点选中关联时,同时选中,只返回父节点␊ + @param {Object} extra 额外参数␊ + @param {Array} extra.selectedPath 单选时选中的数据的路径␊ + @param {Boolean} extra.checked 多选时当前的操作是选中还是取消选中␊ + @param {Object} extra.currentData 多选时当前操作的数据␊ + @param {Array} extra.checkedData 多选时所有被选中的数据␊ + @param {Array} extra.indeterminateData 多选时半选的数据`, + name: 'onChange', + propType: 'func', + }, + { + name: 'onSelect', + propType: 'func', + }, + { + description: '(非受控)默认展开值,如果不设置,组件内部会根据 defaultValue/value 进行自动设置', + name: 'defaultExpandedValue', + propType: { + type: 'arrayOf', + value: 'string', + }, + }, + { + description: '(受控)当前展开值', + name: 'expandedValue', + propType: { + type: 'arrayOf', + value: 'string', + }, + }, + { + defaultValue: 'click', + description: '展开触发的方式', + name: 'expandTriggerType', + propType: { + type: 'oneOf', + value: [ + 'click', + 'hover', + ], + }, + }, + { + description: `展开时触发的回调函数␊ + @param {Array} expandedValue 各列展开值的数组`, + name: 'onExpand', + propType: 'func', + }, + { + defaultValue: false, + description: '是否开启虚拟滚动', + name: 'useVirtual', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否多选', + name: 'multiple', + propType: 'bool', + }, + { + defaultValue: false, + description: '单选时是否只能选中叶子节点', + name: 'canOnlySelectLeaf', + propType: 'bool', + }, + { + defaultValue: false, + description: '多选时是否只能选中叶子节点', + name: 'canOnlyCheckLeaf', + propType: 'bool', + }, + { + defaultValue: false, + description: '父子节点是否选中不关联', + name: 'checkStrictly', + propType: 'bool', + }, + { + description: '每列列表样式对象', + name: 'listStyle', + propType: 'object', + }, + { + description: '每列列表类名', + name: 'listClassName', + propType: 'string', + }, + { + defaultValue: Function {}, + description: `每列列表项渲染函数␊ + @param {Object} data 数据␊ + @return {ReactNode} 列表项内容`, + name: 'itemRender', + propType: 'func', + }, + { + description: `异步加载数据函数␊ + @param {Object} data 当前点击异步加载的数据␊ + @param {Object} source 当前点击数据,source是原始对象`, + name: 'loadData', + propType: 'func', + }, + { + name: 'searchValue', + propType: 'string', + }, + { + name: 'onBlur', + propType: 'func', + }, + { + name: 'filteredPaths', + propType: 'array', + }, + { + name: 'filteredListStyle', + propType: 'object', + }, + { + name: 'resultRender', + propType: 'func', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'CascaderSelect', + docUrl: '', + npm: { + destructuring: false, + exportName: 'CascaderSelect', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + defaultValue: 'medium', + description: '选择框大小', + name: 'size', + propType: { + type: 'oneOf', + value: [ + 'small', + 'medium', + 'large', + ], + }, + }, + { + description: '选择框占位符', + name: 'placeholder', + propType: 'string', + }, + { + defaultValue: false, + description: '是否禁用', + name: 'disabled', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否有下拉箭头', + name: 'hasArrow', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否有边框', + name: 'hasBorder', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否有清除按钮', + name: 'hasClear', + propType: 'bool', + }, + { + description: '自定义内联 label', + name: 'label', + propType: 'node', + }, + { + description: '是否只读,只读模式下可以展开弹层但不能选', + name: 'readOnly', + propType: 'bool', + }, + { + defaultValue: [], + description: '数据源,结构可参考下方说明', + name: 'dataSource', + propType: { + type: 'arrayOf', + value: 'object', + }, + }, + { + defaultValue: null, + description: '(非受控)默认值', + name: 'defaultValue', + propType: { + type: 'oneOfType', + value: [ + 'string', + { + type: 'arrayOf', + value: 'string', + }, + ], + }, + }, + { + description: '(受控)当前值', + name: 'value', + propType: { + type: 'oneOfType', + value: [ + 'string', + { + type: 'arrayOf', + value: 'string', + }, + ], + }, + }, + { + description: `选中值改变时触发的回调函数␊ + @param {String|Array} value 选中的值,单选时返回单个值,多选时返回数组␊ + @param {Object|Array} data 选中的数据,包括 value 和 label,单选时返回单个值,多选时返回数组,父子节点选中关联时,同时选中,只返回父节点␊ + @param {Object} extra 额外参数␊ + @param {Array} extra.selectedPath 单选时选中的数据的路径␊ + @param {Boolean} extra.checked 多选时当前的操作是选中还是取消选中␊ + @param {Object} extra.currentData 多选时当前操作的数据␊ + @param {Array} extra.checkedData 多选时所有被选中的数据␊ + @param {Array} extra.indeterminateData 多选时半选的数据`, + name: 'onChange', + propType: 'func', + }, + { + description: '默认展开值,如果不设置,组件内部会根据 defaultValue/value 进行自动设置', + name: 'defaultExpandedValue', + propType: { + type: 'arrayOf', + value: 'string', + }, + }, + { + defaultValue: 'click', + description: '展开触发的方式', + name: 'expandTriggerType', + propType: { + type: 'oneOf', + value: [ + 'click', + 'hover', + ], + }, + }, + { + defaultValue: Function {}, + name: 'onExpand', + propType: 'func', + }, + { + defaultValue: false, + description: '是否开启虚拟滚动', + name: 'useVirtual', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否多选', + name: 'multiple', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否选中即发生改变, 该属性仅在单选模式下有效', + name: 'changeOnSelect', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否只能勾选叶子项的checkbox,该属性仅在多选模式下有效', + name: 'canOnlyCheckLeaf', + propType: 'bool', + }, + { + defaultValue: false, + description: '父子节点是否选中不关联', + name: 'checkStrictly', + propType: 'bool', + }, + { + description: '每列列表样式对象', + name: 'listStyle', + propType: 'object', + }, + { + description: '每列列表类名', + name: 'listClassName', + propType: 'string', + }, + { + description: `选择框单选时展示结果的自定义渲染函数␊ + @param {Array} label 选中路径的文本数组␊ + @return {ReactNode} 渲染在选择框中的内容␊ + @default 单选时:labelPath => labelPath.join(' / ');多选时:labelPath => labelPath[labelPath.length - 1]`, + name: 'displayRender', + propType: 'func', + }, + { + description: `渲染 item 内容的方法␊ + @param {Object} item 渲染节点的item␊ + @return {ReactNode} item node`, + name: 'itemRender', + propType: 'func', + }, + { + defaultValue: false, + description: '是否显示搜索框', + name: 'showSearch', + propType: 'bool', + }, + { + defaultValue: Function {}, + description: `自定义搜索函数␊ + @param {String} searchValue 搜索的关键字␊ + @param {Array} path 节点路径␊ + @return {Boolean} 是否匹配␊ + @default 根据路径所有节点的文本值模糊匹配`, + name: 'filter', + propType: 'func', + }, + { + description: `搜索结果自定义渲染函数␊ + @param {String} searchValue 搜索的关键字␊ + @param {Array} path 匹配到的节点路径␊ + @return {ReactNode} 渲染的内容␊ + @default 按照节点文本 a / b / c 的模式渲染`, + name: 'resultRender', + propType: 'func', + }, + { + defaultValue: true, + description: '搜索结果列表是否和选择框等宽', + name: 'resultAutoWidth', + propType: 'bool', + }, + { + defaultValue: 'Not Found', + description: '无数据时显示内容', + name: 'notFoundContent', + propType: 'node', + }, + { + description: `异步加载数据函数␊ + @param {Object} data 当前点击异步加载的数据`, + name: 'loadData', + propType: 'func', + }, + { + description: '自定义下拉框头部', + name: 'header', + propType: 'node', + }, + { + description: '自定义下拉框底部', + name: 'footer', + propType: 'node', + }, + { + defaultValue: false, + description: '初始下拉框是否显示', + name: 'defaultVisible', + propType: 'bool', + }, + { + description: '当前下拉框是否显示', + name: 'visible', + propType: 'bool', + }, + { + defaultValue: Function {}, + description: `下拉框显示或关闭时触发事件的回调函数␊ + @param {Boolean} visible 是否显示␊ + @param {String} type 触发显示关闭的操作类型, fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发`, + name: 'onVisibleChange', + propType: 'func', + }, + { + description: '下拉框自定义样式对象', + name: 'popupStyle', + propType: 'object', + }, + { + description: '下拉框样式自定义类名', + name: 'popupClassName', + propType: 'string', + }, + { + description: '下拉框挂载的容器节点', + name: 'popupContainer', + propType: 'any', + }, + { + defaultValue: undefined, + description: '透传到 Popup 的属性对象', + name: 'popupProps', + propType: 'object', + }, + { + description: '是否跟随滚动', + name: 'followTrigger', + propType: 'bool', + }, + { + description: '是否为预览态', + name: 'isPreview', + propType: 'bool', + }, + { + description: `预览态模式下渲染的内容␊ + @param {Array} value 选择值 { label: , value:}`, + name: 'renderPreview', + propType: 'func', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Checkbox', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Checkbox', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + description: '自定义类名', + name: 'className', + propType: 'string', + }, + { + description: 'checkbox id, 挂载在input上', + name: 'id', + propType: 'string', + }, + { + description: '自定义内敛样式', + name: 'style', + propType: 'object', + }, + { + description: '选中状态', + name: 'checked', + propType: 'bool', + }, + { + defaultValue: false, + description: '默认选中状态', + name: 'defaultChecked', + propType: 'bool', + }, + { + description: '禁用', + name: 'disabled', + propType: 'bool', + }, + { + description: '通过属性配置label,', + name: 'label', + propType: 'node', + }, + { + description: 'Checkbox 的中间状态,只会影响到 Checkbox 的样式,并不影响其 checked 属性', + name: 'indeterminate', + propType: 'bool', + }, + { + defaultValue: false, + description: 'Checkbox 的默认中间态,只会影响到 Checkbox 的样式,并不影响其 checked 属性', + name: 'defaultIndeterminate', + propType: 'bool', + }, + { + description: `状态变化时触发的事件␊ + @param {Boolean} checked 是否选中␊ + @param {Event} e Dom 事件对象`, + name: 'onChange', + propType: 'func', + }, + { + description: `鼠标进入enter事件␊ + @param {Event} e Dom 事件对象`, + name: 'onMouseEnter', + propType: 'func', + }, + { + description: `鼠标离开Leave事件␊ + @param {Event} e Dom 事件对象`, + name: 'onMouseLeave', + propType: 'func', + }, + { + description: 'checkbox 的value', + name: 'value', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'number', + ], + }, + }, + { + description: 'name', + name: 'name', + propType: 'string', + }, + { + defaultValue: false, + description: '是否为预览态', + name: 'isPreview', + propType: 'bool', + }, + { + description: `预览态模式下渲染的内容␊ + @param {number} value 评分值`, + name: 'renderPreview', + propType: 'func', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Collapse', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Collapse', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + description: '样式前缀', + name: 'prefix', + propType: 'string', + }, + { + description: '组件接受行内样式', + name: 'style', + propType: 'object', + }, + { + description: '使用数据模型构建', + name: 'dataSource', + propType: 'array', + }, + { + description: '默认展开keys', + name: 'defaultExpandedKeys', + propType: 'array', + }, + { + description: '受控展开keys', + name: 'expandedKeys', + propType: 'array', + }, + { + description: '展开状态发升变化时候的回调', + name: 'onExpand', + propType: 'func', + }, + { + description: '所有禁用', + name: 'disabled', + propType: 'bool', + }, + { + description: '扩展class', + name: 'className', + propType: 'string', + }, + { + defaultValue: false, + description: '手风琴模式,一次只能打开一个', + name: 'accordion', + propType: 'bool', + }, + { + name: 'children', + propType: 'node', + }, + { + name: 'id', + propType: 'string', + }, + { + name: 'rtl', + propType: 'bool', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'ConfigProvider', + docUrl: '', + npm: { + destructuring: false, + exportName: 'ConfigProvider', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + description: '样式类名的品牌前缀', + name: 'prefix', + propType: 'string', + }, + { + description: '国际化文案对象,属性为组件的 displayName', + name: 'locale', + propType: 'object', + }, + { + defaultValue: false, + description: `是否开启错误捕捉 errorBoundary␊ + 如需自定义参数,请传入对象 对象接受参数列表如下:␊ + ␊ + fallbackUI `Function(error?: {}, errorInfo?: {}) => Element` 捕获错误后的展示␊ + afterCatch `Function(error?: {}, errorInfo?: {})` 捕获错误后的行为, 比如埋点上传`, + name: 'errorBoundary', + propType: { + type: 'oneOfType', + value: [ + 'bool', + 'object', + ], + }, + }, + { + description: '是否开启 Pure Render 模式,会提高性能,但是也会带来副作用', + name: 'pure', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否在开发模式下显示组件属性被废弃的 warning 提示', + name: 'warning', + propType: 'bool', + }, + { + description: '是否开启 rtl 模式', + name: 'rtl', + propType: 'bool', + }, + { + description: '设备类型,针对不同的设备类型组件做出对应的响应式变化', + name: 'device', + propType: { + type: 'oneOf', + value: [ + 'tablet', + 'desktop', + 'phone', + ], + }, + }, + { + description: '组件树', + name: 'children', + propType: 'any', + }, + { + description: '指定浮层渲染的父节点, 可以为节点id的字符串,也可以返回节点的函数', + name: 'popupContainer', + propType: 'any', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'DatePicker', + docUrl: '', + npm: { + destructuring: false, + exportName: 'DatePicker', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'rtl', + propType: 'bool', + }, + { + description: '输入框内置标签', + name: 'label', + propType: 'node', + }, + { + description: '输入框状态', + name: 'state', + propType: { + type: 'oneOf', + value: [ + 'success', + 'loading', + 'error', + ], + }, + }, + { + description: '输入提示', + name: 'placeholder', + propType: 'string', + }, + { + description: `默认展现的月␊ + @return {MomentObject} 返回包含指定月份的 moment 对象实例`, + name: 'defaultVisibleMonth', + propType: 'func', + }, + { + name: 'onVisibleMonthChange', + propType: 'func', + }, + { + description: '日期值(受控)moment 对象', + name: 'value', + propType: 'custom', + }, + { + description: '初始日期值,moment 对象', + name: 'defaultValue', + propType: 'custom', + }, + { + defaultValue: 'YYYY-MM-DD', + description: '日期值的格式(用于限定用户输入和展示)', + name: 'format', + propType: 'string', + }, + { + defaultValue: false, + description: '是否使用时间控件,传入 TimePicker 的属性 { defaultValue, format, ... }', + name: 'showTime', + propType: { + type: 'oneOfType', + value: [ + 'object', + 'bool', + ], + }, + }, + { + defaultValue: false, + description: '每次选择日期时是否重置时间(仅在 showTime 开启时有效)', + name: 'resetTime', + propType: 'bool', + }, + { + defaultValue: Function {}, + description: `禁用日期函数␊ + @param {MomentObject} 日期值␊ + @param {String} view 当前视图类型,year: 年, month: 月, date: 日␊ + @return {Boolean} 是否禁用`, + name: 'disabledDate', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `自定义面板页脚␊ + @return {Node} 自定义的面板页脚组件`, + name: 'footerRender', + propType: 'func', + }, + { + description: `日期值改变时的回调␊ + @param {MomentObject|String} value 日期值`, + name: 'onChange', + propType: 'func', + }, + { + description: `点击确认按钮时的回调␊ + @return {MomentObject|String} 日期值`, + name: 'onOk', + propType: 'func', + }, + { + defaultValue: 'medium', + description: '输入框尺寸', + name: 'size', + propType: { + type: 'oneOf', + value: [ + 'small', + 'medium', + 'large', + ], + }, + }, + { + description: '是否禁用', + name: 'disabled', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否显示清空按钮', + name: 'hasClear', + propType: 'bool', + }, + { + description: '弹层显示状态', + name: 'visible', + propType: 'bool', + }, + { + defaultValue: false, + description: '弹层默认是否显示', + name: 'defaultVisible', + propType: 'bool', + }, + { + description: `弹层展示状态变化时的回调␊ + @param {Boolean} visible 弹层是否显示␊ + @param {String} type 触发弹层显示和隐藏的来源 calendarSelect 表示由日期表盘的选择触发; okBtnClick 表示由确认按钮触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发`, + name: 'onVisibleChange', + propType: 'func', + }, + { + defaultValue: 'click', + description: '弹层触发方式', + name: 'popupTriggerType', + propType: { + type: 'oneOf', + value: [ + 'click', + 'hover', + ], + }, + }, + { + defaultValue: 'tl tl', + description: '弹层对齐方式,具体含义见 OverLay文档', + name: 'popupAlign', + propType: 'string', + }, + { + description: `弹层容器␊ + @param {Element} target 目标元素␊ + @return {Element} 弹层的容器元素`, + name: 'popupContainer', + propType: 'any', + }, + { + description: '弹层自定义样式', + name: 'popupStyle', + propType: 'object', + }, + { + description: '弹层自定义样式类', + name: 'popupClassName', + propType: 'string', + }, + { + description: '弹层其他属性', + name: 'popupProps', + propType: 'object', + }, + { + description: '是否跟随滚动', + name: 'followTrigger', + propType: 'bool', + }, + { + description: '输入框其他属性', + name: 'inputProps', + propType: 'object', + }, + { + description: `自定义日期渲染函数␊ + @param {Object} value 日期值(moment对象)␊ + @returns {ReactNode}`, + name: 'dateCellRender', + propType: 'func', + }, + { + description: `自定义月份渲染函数␊ + @param {Object} calendarDate 对应 Calendar 返回的自定义日期对象␊ + @returns {ReactNode}`, + name: 'monthCellRender', + propType: 'func', + }, + { + name: 'yearCellRender', + propType: 'func', + }, + { + description: '日期输入框的 aria-label 属性', + name: 'dateInputAriaLabel', + propType: 'string', + }, + { + description: '时间输入框的 aria-label 属性', + name: 'timeInputAriaLabel', + propType: 'string', + }, + { + description: '是否为预览态', + name: 'isPreview', + propType: 'bool', + }, + { + description: `预览态模式下渲染的内容␊ + @param {MomentObject} value 日期`, + name: 'renderPreview', + propType: 'func', + }, + { + name: 'locale', + propType: 'object', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'name', + propType: 'string', + }, + { + name: 'popupComponent', + propType: 'elementType', + }, + { + name: 'popupContent', + propType: 'node', + }, + { + name: 'disableChangeMode', + propType: 'bool', + }, + { + name: 'yearRange', + propType: { + type: 'arrayOf', + value: 'number', + }, + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Dialog', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Dialog', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + defaultValue: false, + description: '是否显示', + name: 'visible', + propType: 'bool', + }, + { + description: '标题', + name: 'title', + propType: 'node', + }, + { + description: '内容', + name: 'children', + propType: 'node', + }, + { + description: `底部内容,设置为 false,则不进行显示␊ + @default [, ]`, + name: 'footer', + propType: { + type: 'oneOfType', + value: [ + 'bool', + 'node', + ], + }, + }, + { + defaultValue: 'right', + description: '底部按钮的对齐方式', + name: 'footerAlign', + propType: { + type: 'oneOf', + value: [ + 'left', + 'center', + 'right', + ], + }, + }, + { + defaultValue: [ + 'ok', + 'cancel', + ], + description: `指定确定按钮和取消按钮是否存在以及如何排列,

**可选值**:␊ + ['ok', 'cancel'](确认取消按钮同时存在,确认按钮在左)␊ + ['cancel', 'ok'](确认取消按钮同时存在,确认按钮在右)␊ + ['ok'](只存在确认按钮)␊ + ['cancel'](只存在取消按钮)`, + name: 'footerActions', + propType: 'array', + }, + { + defaultValue: Function {}, + description: `在点击确定按钮时触发的回调函数␊ + @param {Object} event 点击事件对象`, + name: 'onOk', + propType: 'func', + }, + { + defaultValue: Function {}, + description: `在点击取消按钮时触发的回调函数␊ + @param {Object} event 点击事件对象`, + name: 'onCancel', + propType: 'func', + }, + { + defaultValue: undefined, + description: '应用于确定按钮的属性对象', + name: 'okProps', + propType: 'object', + }, + { + defaultValue: undefined, + description: '应用于取消按钮的属性对象', + name: 'cancelProps', + propType: 'object', + }, + { + defaultValue: 'esc,close', + description: `控制对话框关闭的方式,值可以为字符串或者布尔值,其中字符串是由以下值组成:␊ + **close** 表示点击关闭按钮可以关闭对话框␊ + **mask** 表示点击遮罩区域可以关闭对话框␊ + **esc** 表示按下 esc 键可以关闭对话框␊ + 如 'close' 或 'close,esc,mask'␊ + 如果设置为 true,则以上关闭方式全部生效␊ + 如果设置为 false,则以上关闭方式全部失效`, + name: 'closeable', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'bool', + ], + }, + }, + { + defaultValue: Function {}, + description: `对话框关闭时触发的回调函数␊ + @param {String} trigger 关闭触发行为的描述字符串␊ + @param {Object} event 关闭时事件对象`, + name: 'onClose', + propType: 'func', + }, + { + defaultValue: Function {}, + description: '对话框关闭后触发的回调函数, 如果有动画,则在动画结束后触发', + name: 'afterClose', + propType: 'func', + }, + { + defaultValue: true, + description: '是否显示遮罩', + name: 'hasMask', + propType: 'bool', + }, + { + description: `显示隐藏时动画的播放方式␊ + @property {String} in 进场动画␊ + @property {String} out 出场动画`, + name: 'animation', + propType: { + type: 'oneOfType', + value: [ + 'object', + 'bool', + ], + }, + }, + { + defaultValue: false, + description: '对话框弹出时是否自动获得焦点', + name: 'autoFocus', + propType: 'bool', + }, + { + defaultValue: 'cc cc', + description: '对话框对齐方式, 具体见Overlay文档', + name: 'align', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'bool', + ], + }, + }, + { + defaultValue: false, + description: '当对话框高度超过浏览器视口高度时,是否显示所有内容而不是出现滚动条以保证对话框完整显示在浏览器视口内,该属性仅在对话框垂直水平居中时生效,即 align 被设置为 \'cc cc\' 时', + name: 'isFullScreen', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否在对话框重新渲染时及时更新对话框位置,一般用于对话框高度变化后依然能保证原来的对齐方式', + name: 'shouldUpdatePosition', + propType: 'bool', + }, + { + defaultValue: 40, + description: '对话框距离浏览器顶部和底部的最小间距,align 被设置为 \'cc cc\' 并且 isFullScreen 被设置为 true 时不生效', + name: 'minMargin', + propType: 'number', + }, + { + defaultValue: undefined, + description: '透传到弹层组件的属性对象', + name: 'overlayProps', + propType: 'object', + }, + { + description: `自定义国际化文案对象␊ + @property {String} ok 确认按钮文案␊ + @property {String} cancel 取消按钮文案`, + name: 'locale', + propType: 'object', + }, + { + description: '对话框的高度样式属性', + name: 'height', + propType: 'string', + }, + { + name: 'popupContainer', + propType: 'any', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Dropdown', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Dropdown', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + description: '弹层内容', + name: 'children', + propType: 'node', + }, + { + description: '弹层当前是否显示', + name: 'visible', + propType: 'bool', + }, + { + defaultValue: false, + description: '弹层默认是否显示', + name: 'defaultVisible', + propType: 'bool', + }, + { + description: `弹层显示或隐藏时触发的回调函数␊ + @param {Boolean} visible 弹层是否显示␊ + @param {String} type 触发弹层显示或隐藏的来源 fromContent 表示由Dropdown内容触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发`, + name: 'onVisibleChange', + propType: 'func', + }, + { + description: '触发弹层显示或者隐藏的元素', + name: 'trigger', + propType: 'node', + }, + { + defaultValue: 'hover', + description: '触发弹层显示或隐藏的操作类型,可以是 \'click\',\'hover\',或者它们组成的数组,如 [\'hover\', \'click\']', + name: 'triggerType', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + defaultValue: false, + description: '设置此属性,弹层无法显示或隐藏', + name: 'disabled', + propType: 'bool', + }, + { + defaultValue: 'tl bl', + description: '弹层相对于触发元素的定位, 详见 Overlay 的定位部分', + name: 'align', + propType: 'string', + }, + { + defaultValue: [ + 0, + 0, + ], + description: `弹层相对于trigger的定位的微调, 接收数组[hoz, ver], 表示弹层在 left / top 上的增量␊ + e.g. [100, 100] 表示往右(RTL 模式下是往左) 、下分布偏移100px`, + name: 'offset', + propType: 'array', + }, + { + defaultValue: 200, + description: '弹层显示或隐藏的延时时间(以毫秒为单位),在 triggerType 被设置为 hover 时生效', + name: 'delay', + propType: 'number', + }, + { + description: '弹层打开时是否让其中的元素自动获取焦点', + name: 'autoFocus', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否显示遮罩', + name: 'hasMask', + propType: 'bool', + }, + { + defaultValue: false, + description: '隐藏时是否保留子节点', + name: 'cache', + propType: 'bool', + }, + { + description: `配置动画的播放方式,支持 { in: 'enter-class', out: 'leave-class' } 的对象参数,如果设置为 false,则不播放动画␊ + @default { in: 'expandInDown', out: 'expandOutUp' }`, + name: 'animation', + propType: { + type: 'oneOfType', + value: [ + 'object', + 'bool', + ], + }, + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Drawer', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Drawer', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + name: 'pure', + propType: 'bool', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + defaultValue: null, + name: 'trigger', + propType: 'element', + }, + { + defaultValue: 'click', + name: 'triggerType', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + description: '宽度,仅在 placement是 left right 的时候生效', + name: 'width', + propType: { + type: 'oneOfType', + value: [ + 'number', + 'string', + ], + }, + }, + { + description: '高度,仅在 placement是 top bottom 的时候生效', + name: 'height', + propType: { + type: 'oneOfType', + value: [ + 'number', + 'string', + ], + }, + }, + { + defaultValue: true, + description: `控制对话框关闭的方式,值可以为字符串或者布尔值,其中字符串是由以下值组成:␊ + **close** 表示点击关闭按钮可以关闭对话框␊ + **mask** 表示点击遮罩区域可以关闭对话框␊ + **esc** 表示按下 esc 键可以关闭对话框␊ + 如 'close' 或 'close,esc,mask'␊ + 如果设置为 true,则以上关闭方式全部生效␊ + 如果设置为 false,则以上关闭方式全部失效`, + name: 'closeable', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'bool', + ], + }, + }, + { + defaultValue: Function {}, + description: `对话框关闭时触发的回调函数␊ + @param {String} trigger 关闭触发行为的描述字符串␊ + @param {Object} event 关闭时事件对象`, + name: 'onClose', + propType: 'func', + }, + { + defaultValue: 'right', + description: '位于页面的位置', + name: 'placement', + propType: { + type: 'oneOf', + value: [ + 'top', + 'right', + 'bottom', + 'left', + ], + }, + }, + { + description: '标题', + name: 'title', + propType: 'node', + }, + { + description: 'header上的样式', + name: 'headerStyle', + propType: 'object', + }, + { + description: 'body上的样式', + name: 'bodyStyle', + propType: 'object', + }, + { + description: '是否显示', + name: 'visible', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否显示遮罩', + name: 'hasMask', + propType: 'bool', + }, + { + name: 'onVisibleChange', + propType: 'func', + }, + { + description: `显示隐藏时动画的播放方式␊ + @property {String} in 进场动画␊ + @property {String} out 出场动画`, + name: 'animation', + propType: { + type: 'oneOfType', + value: [ + 'object', + 'bool', + ], + }, + }, + { + name: 'locale', + propType: 'object', + }, + { + name: 'popupContainer', + propType: 'any', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Form', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Form', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + description: '样式前缀', + name: 'prefix', + propType: 'string', + }, + { + description: '内联表单', + name: 'inline', + propType: 'bool', + }, + { + defaultValue: 'medium', + description: `单个 Item 的 size 自定义,优先级高于 Form 的 size, 并且当组件与 Item 一起使用时,组件自身设置 size 属性无效。␊ + @enumdesc 大, 中, 小`, + name: 'size', + propType: { + type: 'oneOf', + value: [ + 'large', + 'medium', + 'small', + ], + }, + }, + { + description: '单个 Item 中表单类组件宽度是否是100%', + name: 'fullWidth', + propType: 'bool', + }, + { + defaultValue: 'left', + description: `标签的位置␊ + @enumdesc 上, 左, 内`, + name: 'labelAlign', + propType: { + type: 'oneOf', + value: [ + 'top', + 'left', + 'inset', + ], + }, + }, + { + description: `标签的左右对齐方式␊ + @enumdesc 左, 右`, + name: 'labelTextAlign', + propType: { + type: 'oneOf', + value: [ + 'left', + 'right', + ], + }, + }, + { + description: 'field 实例, 传 false 会禁用 field', + name: 'field', + propType: 'any', + }, + { + description: '保存 Form 自动生成的 field 对象', + name: 'saveField', + propType: 'func', + }, + { + description: '控制第一级 Item 的 labelCol', + name: 'labelCol', + propType: 'object', + }, + { + description: '控制第一级 Item 的 wrapperCol', + name: 'wrapperCol', + propType: 'object', + }, + { + defaultValue: undefined, + description: 'form内有 `htmlType="submit"` 的元素的时候会触发', + name: 'onSubmit', + propType: 'func', + }, + { + description: '子元素', + name: 'children', + propType: 'any', + }, + { + description: '扩展class', + name: 'className', + propType: 'string', + }, + { + description: '自定义内联样式', + name: 'style', + propType: 'object', + }, + { + description: '表单数值', + name: 'value', + propType: 'object', + }, + { + description: `表单变化回调␊ + @param {Object} values 表单数据␊ + @param {Object} item 详细␊ + @param {String} item.name 变化的组件名␊ + @param {String} item.value 变化的数据␊ + @param {Object} item.field field 实例`, + name: 'onChange', + propType: 'func', + }, + { + defaultValue: 'form', + description: '设置标签类型', + name: 'component', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'func', + ], + }, + }, + { + name: 'fieldOptions', + propType: 'object', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + defaultValue: 'desktop', + description: '预设屏幕宽度', + name: 'device', + propType: { + type: 'oneOf', + value: [ + 'phone', + 'tablet', + 'desktop', + ], + }, + }, + { + description: '是否开启内置的响应式布局 (使用ResponsiveGrid)', + name: 'responsive', + propType: 'bool', + }, + { + description: '是否开启预览态', + name: 'isPreview', + propType: 'bool', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Icon', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Icon', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + description: '指定显示哪种图标', + name: 'type', + propType: 'string', + }, + { + name: 'children', + propType: 'node', + }, + { + defaultValue: 'medium', + description: `指定图标大小␊ +
**可选值**
xxs, xs, small, medium, large, xl, xxl, xxxl, inherit`, + name: 'size', + propType: { + type: 'oneOfType', + value: [ + { + type: 'oneOf', + value: [ + 'xxs', + 'xs', + 'small', + 'medium', + 'large', + 'xl', + 'xxl', + 'xxxl', + 'inherit', + ], + }, + 'number', + ], + }, + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'style', + propType: 'object', + }, + { + defaultValue: 'next-', + name: 'prefix', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Input', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Input', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + description: 'label', + name: 'label', + propType: 'node', + }, + { + description: '是否出现clear按钮', + name: 'hasClear', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否有边框', + name: 'hasBorder', + propType: 'bool', + }, + { + description: `状态␊ + @enumdesc 错误, 校验中, 成功, 警告`, + name: 'state', + propType: { + type: 'oneOf', + value: [ + 'error', + 'loading', + 'success', + 'warning', + ], + }, + }, + { + defaultValue: 'medium', + description: `尺寸␊ + @enumdesc 小, 中, 大`, + name: 'size', + propType: { + type: 'oneOf', + value: [ + 'small', + 'medium', + 'large', + ], + }, + }, + { + description: '按下回车的回调', + name: 'onPressEnter', + propType: 'func', + }, + { + name: 'onClear', + propType: 'func', + }, + { + description: '原生type', + name: 'htmlType', + propType: 'string', + }, + { + name: 'htmlSize', + propType: 'string', + }, + { + description: '水印 (Icon的type类型,和hasClear占用一个地方)', + name: 'hint', + propType: 'string', + }, + { + description: '文字前附加内容', + name: 'innerBefore', + propType: 'node', + }, + { + description: '文字后附加内容', + name: 'innerAfter', + propType: 'node', + }, + { + description: '输入框前附加内容', + name: 'addonBefore', + propType: 'node', + }, + { + description: '输入框后附加内容', + name: 'addonAfter', + propType: 'node', + }, + { + description: '输入框前附加文字', + name: 'addonTextBefore', + propType: 'node', + }, + { + description: '输入框后附加文字', + name: 'addonTextAfter', + propType: 'node', + }, + { + defaultValue: 'off', + description: '(原生input支持)', + name: 'autoComplete', + propType: 'string', + }, + { + description: '自动聚焦(原生input支持)', + name: 'autoFocus', + propType: 'bool', + }, + { + defaultValue: Function {}, + name: 'inputRender', + propType: 'func', + }, + { + name: 'extra', + propType: 'node', + }, + { + name: 'innerBeforeClassName', + propType: 'string', + }, + { + name: 'innerAfterClassName', + propType: 'string', + }, + { + defaultValue: false, + description: '是否为预览态', + name: 'isPreview', + propType: 'bool', + }, + { + description: `预览态模式下渲染的内容␊ + @param {number} value 评分值`, + name: 'renderPreview', + propType: 'func', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Loading', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Loading', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + description: '样式前缀', + name: 'prefix', + propType: 'string', + }, + { + description: '自定义内容', + name: 'tip', + propType: 'any', + }, + { + defaultValue: 'bottom', + description: `自定义内容位置␊ + @enumdesc 出现在动画右边, 出现在动画下面`, + name: 'tipAlign', + propType: { + type: 'oneOf', + value: [ + 'right', + 'bottom', + ], + }, + }, + { + defaultValue: true, + description: 'loading 状态, 默认 true', + name: 'visible', + propType: 'bool', + }, + { + name: 'onVisibleChange', + propType: 'func', + }, + { + description: '自定义class', + name: 'className', + propType: 'string', + }, + { + description: '自定义内联样式', + name: 'style', + propType: 'object', + }, + { + defaultValue: 'large', + description: `设置动画尺寸␊ + @description 仅仅对默认动画效果起作用␊ + @enumdesc 大号, 中号`, + name: 'size', + propType: { + type: 'oneOf', + value: [ + 'large', + 'medium', + ], + }, + }, + { + description: '自定义动画', + name: 'indicator', + propType: 'any', + }, + { + description: '动画颜色', + name: 'color', + propType: 'string', + }, + { + description: '全屏展示', + name: 'fullScreen', + propType: 'bool', + }, + { + description: '子元素', + name: 'children', + propType: 'any', + }, + { + defaultValue: true, + description: 'should loader be displayed inline', + name: 'inline', + propType: 'bool', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + defaultValue: null, + name: 'animate', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Menu', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Menu', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + description: '菜单项和子菜单', + name: 'children', + propType: 'node', + }, + { + defaultValue: Function {}, + description: `点击菜单项触发的回调函数␊ + @param {String} key 点击的菜单项的 key 值␊ + @param {Object} item 点击的菜单项对象␊ + @param {Object} event 点击的事件对象`, + name: 'onItemClick', + propType: 'func', + }, + { + description: '当前打开的子菜单的 key 值', + name: 'openKeys', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + defaultValue: [], + description: '初始打开的子菜单的 key 值', + name: 'defaultOpenKeys', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + defaultValue: false, + description: '初始展开所有的子菜单,只在 mode 设置为 \'inline\' 以及 openMode 设置为 \'multiple\' 下生效,优先级高于 defaultOpenKeys', + name: 'defaultOpenAll', + propType: 'bool', + }, + { + defaultValue: Function {}, + description: `打开或关闭子菜单触发的回调函数␊ + @param {String} key 打开的所有子菜单的 key 值␊ + @param {Object} extra 额外参数␊ + @param {String} extra.key 当前操作子菜单的 key 值␊ + @param {Boolean} extra.open 是否是打开`, + name: 'onOpen', + propType: 'func', + }, + { + defaultValue: 'inline', + description: '子菜单打开的模式', + name: 'mode', + propType: { + type: 'oneOf', + value: [ + 'inline', + 'popup', + ], + }, + }, + { + defaultValue: 'click', + description: '子菜单打开的触发行为', + name: 'triggerType', + propType: { + type: 'oneOf', + value: [ + 'click', + 'hover', + ], + }, + }, + { + defaultValue: 'multiple', + description: '展开内连子菜单的模式,同时可以展开一个子菜单还是多个子菜单,该属性仅在 mode 为 inline 时生效', + name: 'openMode', + propType: { + type: 'oneOf', + value: [ + 'single', + 'multiple', + ], + }, + }, + { + defaultValue: 20, + description: '内连子菜单缩进距离', + name: 'inlineIndent', + propType: 'number', + }, + { + defaultValue: 'down', + name: 'inlineArrowDirection', + propType: { + type: 'oneOf', + value: [ + 'down', + 'right', + ], + }, + }, + { + defaultValue: false, + description: '是否自动让弹层的宽度和菜单项保持一致,如果弹层的宽度比菜单项小则和菜单项保持一致,如果宽度大于菜单项则不做处理', + name: 'popupAutoWidth', + propType: 'bool', + }, + { + defaultValue: 'follow', + description: '弹层的对齐方式', + name: 'popupAlign', + propType: { + type: 'oneOf', + value: [ + 'follow', + 'outside', + ], + }, + }, + { + defaultValue: undefined, + description: '弹层自定义 props', + name: 'popupProps', + propType: { + type: 'oneOfType', + value: [ + 'object', + 'func', + ], + }, + }, + { + description: '弹出子菜单自定义 className', + name: 'popupClassName', + propType: 'string', + }, + { + description: '弹出子菜单自定义 style', + name: 'popupStyle', + propType: 'object', + }, + { + description: '当前选中菜单项的 key 值', + name: 'selectedKeys', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + defaultValue: [], + description: '初始选中菜单项的 key 值', + name: 'defaultSelectedKeys', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + defaultValue: Function {}, + description: `选中或取消选中菜单项触发的回调函数␊ + @param {Array} selectedKeys 选中的所有菜单项的值␊ + @param {Object} item 选中或取消选中的菜单项␊ + @param {Object} extra 额外参数␊ + @param {Boolean} extra.select 是否是选中␊ + @param {Array} extra.key 菜单项的 key␊ + @param {Object} extra.label 菜单项的文本␊ + @param {Array} extra.keyPath 菜单项 key 的路径`, + name: 'onSelect', + propType: 'func', + }, + { + description: '选中模式,单选还是多选,默认无值,不可选', + name: 'selectMode', + propType: { + type: 'oneOf', + value: [ + 'single', + 'multiple', + ], + }, + }, + { + defaultValue: false, + description: '是否只能选择第一层菜单项(不能选择子菜单中的菜单项)', + name: 'shallowSelect', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否显示选中图标,如果设置为 false 需配合配置平台设置选中时的背景色以示区分', + name: 'hasSelectedIcon', + propType: 'bool', + }, + { + defaultValue: true, + name: 'labelToggleChecked', + propType: 'bool', + }, + { + defaultValue: false, + description: `是否将选中图标居右,仅当 hasSelectedIcon 为true 时生效。␊ + 注意:SubMenu 上的选中图标一直居左,不受此API控制`, + name: 'isSelectIconRight', + propType: 'bool', + }, + { + defaultValue: 'ver', + description: '菜单第一层展示方向', + name: 'direction', + propType: { + type: 'oneOf', + value: [ + 'ver', + 'hoz', + ], + }, + }, + { + defaultValue: 'left', + description: '横向菜单条 item 和 footer 的对齐方向,在 direction 设置为 \'hoz\' 并且 header 存在时生效', + name: 'hozAlign', + propType: { + type: 'oneOf', + value: [ + 'left', + 'right', + ], + }, + }, + { + defaultValue: false, + description: '横向菜单模式下,是否维持在一行,即超出一行折叠成 SubMenu 显示, 仅在 direction=\'hoz\' mode=\'popup\' 时生效', + name: 'hozInLine', + propType: 'bool', + }, + { + name: 'renderMore', + propType: 'func', + }, + { + description: '自定义菜单头部', + name: 'header', + propType: 'node', + }, + { + description: '自定义菜单尾部', + name: 'footer', + propType: 'node', + }, + { + defaultValue: false, + description: '是否自动获得焦点', + name: 'autoFocus', + propType: 'bool', + }, + { + description: '当前获得焦点的子菜单或菜单项 key 值', + name: 'focusedKey', + propType: 'string', + }, + { + defaultValue: true, + name: 'focusable', + propType: 'bool', + }, + { + defaultValue: Function {}, + name: 'onItemFocus', + propType: 'func', + }, + { + name: 'onBlur', + propType: 'func', + }, + { + defaultValue: false, + description: '是否开启嵌入式模式,一般用于Layout的布局中,开启后没有默认背景、外层border、box-shadow,可以配合`` 自定义高度', + name: 'embeddable', + propType: 'bool', + }, + { + defaultValue: Function {}, + name: 'onItemKeyDown', + propType: 'func', + }, + { + defaultValue: true, + name: 'expandAnimation', + propType: 'bool', + }, + { + name: 'itemClassName', + propType: 'string', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'MenuButton', + docUrl: '', + npm: { + destructuring: false, + exportName: 'MenuButton', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + description: '按钮上的文本内容', + name: 'label', + propType: 'node', + }, + { + defaultValue: true, + description: '弹层是否与按钮宽度相同', + name: 'autoWidth', + propType: 'bool', + }, + { + defaultValue: 'click', + description: '弹层触发方式', + name: 'popupTriggerType', + propType: { + type: 'oneOf', + value: [ + 'click', + 'hover', + ], + }, + }, + { + description: '弹层容器', + name: 'popupContainer', + propType: 'any', + }, + { + description: '弹层展开状态', + name: 'visible', + propType: 'bool', + }, + { + description: '弹层默认是否展开', + name: 'defaultVisible', + propType: 'bool', + }, + { + description: '弹层在显示和隐藏触发的事件', + name: 'onVisibleChange', + propType: 'func', + }, + { + description: '弹层自定义样式', + name: 'popupStyle', + propType: 'object', + }, + { + description: '弹层自定义样式类', + name: 'popupClassName', + propType: 'string', + }, + { + description: '弹层属性透传', + name: 'popupProps', + propType: 'object', + }, + { + description: '是否跟随滚动', + name: 'followTrigger', + propType: 'bool', + }, + { + defaultValue: [], + description: '默认激活的菜单项(用法同 Menu 非受控)', + name: 'defaultSelectedKeys', + propType: 'array', + }, + { + description: '激活的菜单项(用法同 Menu 受控)', + name: 'selectedKeys', + propType: 'array', + }, + { + description: '菜单的选择模式,同 Menu', + name: 'selectMode', + propType: { + type: 'oneOf', + value: [ + 'single', + 'multiple', + ], + }, + }, + { + description: '点击菜单项后的回调,同 Menu', + name: 'onItemClick', + propType: 'func', + }, + { + description: '选择菜单后的回调,同 Menu', + name: 'onSelect', + propType: 'func', + }, + { + defaultValue: undefined, + description: '菜单属性透传', + name: 'menuProps', + propType: 'object', + }, + { + name: 'style', + propType: 'object', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'children', + propType: 'any', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Message', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Message', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'style', + propType: 'object', + }, + { + defaultValue: 'success', + description: '反馈类型', + name: 'type', + propType: { + type: 'oneOf', + value: [ + 'success', + 'warning', + 'error', + 'notice', + 'help', + 'loading', + ], + }, + }, + { + defaultValue: 'inline', + description: '反馈外观', + name: 'shape', + propType: { + type: 'oneOf', + value: [ + 'inline', + 'addon', + 'toast', + ], + }, + }, + { + defaultValue: 'medium', + description: '反馈大小', + name: 'size', + propType: { + type: 'oneOf', + value: [ + 'medium', + 'large', + ], + }, + }, + { + description: '标题', + name: 'title', + propType: 'node', + }, + { + description: '内容', + name: 'children', + propType: 'node', + }, + { + defaultValue: true, + description: '默认是否显示', + name: 'defaultVisible', + propType: 'bool', + }, + { + description: '当前是否显示', + name: 'visible', + propType: 'bool', + }, + { + description: '显示的图标类型,会覆盖内部设置的IconType', + name: 'iconType', + propType: 'string', + }, + { + defaultValue: false, + description: '显示关闭按钮', + name: 'closeable', + propType: 'bool', + }, + { + defaultValue: Function {}, + description: '关闭按钮的回调', + name: 'onClose', + propType: 'func', + }, + { + defaultValue: Function {}, + description: '关闭之后调用的函数', + name: 'afterClose', + propType: 'func', + }, + { + defaultValue: true, + description: '是否开启展开收起动画', + name: 'animation', + propType: 'bool', + }, + { + name: 'locale', + propType: 'object', + }, + { + name: 'rtl', + propType: 'bool', + }, + ], + screenshot: '', + title: '@alifd/next', + }, + { + componentName: 'Nav', + docUrl: '', + npm: { + destructuring: false, + exportName: 'Nav', + main: 'src/index.js', + package: '@alifd/next', + subName: '', + version: '1.19.18', + }, + props: [ + { + defaultValue: 'next-', + name: 'prefix', + propType: 'string', + }, + { + defaultValue: false, + name: 'pure', + propType: 'bool', + }, + { + name: 'rtl', + propType: 'bool', + }, + { + name: 'className', + propType: 'string', + }, + { + name: 'style', + propType: 'object', + }, + { + description: '导航项和子导航', + name: 'children', + propType: 'node', + }, + { + defaultValue: 'normal', + description: `导航类型␊ + @enumdesc 普通, 主要, 次要, 线形`, + name: 'type', + propType: { + type: 'oneOf', + value: [ + 'normal', + 'primary', + 'secondary', + 'line', + ], + }, + }, + { + defaultValue: 'ver', + description: `导航布局␊ + @enumdesc 水平, 垂直`, + name: 'direction', + propType: { + type: 'oneOf', + value: [ + 'hoz', + 'ver', + ], + }, + }, + { + defaultValue: 'left', + description: '横向导航条 items 和 footer 的对齐方向,在 direction 设置为 \'hoz\' 并且 header 存在时生效', + name: 'hozAlign', + propType: { + type: 'oneOf', + value: [ + 'left', + 'right', + ], + }, + }, + { + description: `设置组件选中状态的 active 边方向␊ + @enumdesc 无, 上, 下, 左, 右␊ + @default 当 direction 为 'hoz' 时,默认值为 'bottom',当 direction 为 'ver' 时,默认值为 'left'`, + name: 'activeDirection', + propType: { + type: 'oneOf', + value: [ + null, + 'top', + 'bottom', + 'left', + 'right', + ], + }, + }, + { + defaultValue: 'inline', + description: `子导航打开的模式(水平导航只支持弹出)␊ + @eumdesc 行内, 弹出`, + name: 'mode', + propType: { + type: 'oneOf', + value: [ + 'inline', + 'popup', + ], + }, + }, + { + defaultValue: 'click', + description: '子导航打开的触发方式', + name: 'triggerType', + propType: { + type: 'oneOf', + value: [ + 'click', + 'hover', + ], + }, + }, + { + defaultValue: 20, + description: '内联子导航缩进距离', + name: 'inlineIndent', + propType: 'number', + }, + { + defaultValue: false, + description: '初始展开所有的子导航,只在 mode 设置为 \'inline\' 以及 openMode 设置为 \'multiple\' 下生效', + name: 'defaultOpenAll', + propType: 'bool', + }, + { + defaultValue: 'multiple', + description: `内联子导航的展开模式,同时可以展开一个同级子导航还是多个同级子导航,该属性仅在 mode 为 inline 时生效␊ + @eumdesc 一个, 多个`, + name: 'openMode', + propType: { + type: 'oneOf', + value: [ + 'single', + 'multiple', + ], + }, + }, + { + description: '当前选中导航项的 key 值', + name: 'selectedKeys', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + defaultValue: [], + description: '初始选中导航项的 key 值', + name: 'defaultSelectedKeys', + propType: { + type: 'oneOfType', + value: [ + 'string', + 'array', + ], + }, + }, + { + description: `选中或取消选中导航项触发的回调函数␊ + @param {Array} selectedKeys 选中的所有导航项的 key␊ + @param {Object} item 选中或取消选中的导航项␊ + @param {Object} extra 额外参数␊ + @param {Boolean} extra.select 是否是选中␊ + @param {Array} extra.key 导航项的 key␊ + @param {Object} extra.label 导航项的文本␊ + @param {Array} extra.keyPath 导航项 key 的路径`, + name: 'onSelect', + propType: 'func', + }, + { + defaultValue: 'follow', + description: `弹出子导航的对齐方式(水平导航只支持 follow )␊ + @eumdesc Item 顶端对齐, Nav 顶端对齐`, + name: 'popupAlign', + propType: { + type: 'oneOf', + value: [ + 'follow', + 'outside', + ], + }, + }, + { + description: '弹出子导航的自定义类名', + name: 'popupClassName', + propType: 'string', + }, + { + description: '是否只显示图标', + name: 'iconOnly', + propType: 'bool', + }, + { + defaultValue: true, + description: '是否显示右侧的箭头(仅在 iconOnly=true 时生效)', + name: 'hasArrow', + propType: 'bool', + }, + { + defaultValue: false, + description: '是否有 ToolTips (仅在 iconOnly=true 时生效)', + name: 'hasTooltip', + propType: 'bool', + }, + { + description: '自定义导航头部', + name: 'header', + propType: 'node', + }, + { + description: '自定义导航尾部', + name: 'footer', + propType: 'node', + }, + { + defaultValue: false, + description: '是否开启嵌入式模式,一般用于Layout的布局中,开启后没有默认背景、外层border、box-shadow,可以配合`