[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nquote_type = single\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintignore",
    "content": "# 忽略目录\nnode_modules\ntest-cases\ntest\noutput\nbuild\ndist\ndemo\nes\nlib\ntests\n.*\n~*\n\n# 忽略文件\n**/*.min.js\n**/*-min.js\n**/*.bundle.js\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  extends: 'eslint-config-ali/typescript/react',\n  parserOptions: {\n    project: [], // for lint performance\n    createDefaultProgram: false, // for lint performance\n  },\n  rules: {\n    'react/no-multi-comp': 0,\n    'no-unused-expressions': 0,\n    'implicit-arrow-linebreak': 1,\n    'no-nested-ternary': 1,\n    'no-mixed-operators': 1,\n    '@typescript-eslint/ban-types': 1,\n    'no-shadow': 1,\n    'no-prototype-builtins': 1,\n    'no-useless-constructor': 1,\n    'no-empty-function': 1,\n    'lines-between-class-members': 0,\n    'no-await-in-loop': 0,\n    'no-plusplus': 0,\n    '@typescript-eslint/no-parameter-properties': 0,\n    'no-restricted-exports': ['error'],\n    'no-multi-assign': 1,\n    'no-dupe-class-members': 1,\n    'react/no-deprecated': 1,\n    'no-useless-escape': 1,\n    'brace-style': 1,\n    '@typescript-eslint/no-inferrable-types': 0,\n    'no-proto': 0,\n    'prefer-const': 0,\n    'eol-last': 0,\n    'react/no-find-dom-node': 0,\n    'no-case-declarations': 0,\n    '@typescript-eslint/indent': 0,\n    'import/no-cycle': 0,\n    '@typescript-eslint/no-shadow': 0,\n    '@typescript-eslint/method-signature-style': 0,\n    '@typescript-eslint/consistent-type-assertions': 0,\n    '@typescript-eslint/no-useless-constructor': 0,\n    '@typescript-eslint/dot-notation': 0, // for lint performance\n    '@typescript-eslint/restrict-plus-operands': 0, // for lint performance\n    'no-unexpected-multiline': 1,\n    'no-multiple-empty-lines': ['error', { max: 1 }],\n    'lines-around-comment': ['error', {\n      beforeBlockComment: true,\n      afterBlockComment: false,\n      afterLineComment: false,\n      allowBlockStart: true,\n    }],\n    'comma-dangle': ['error', 'always-multiline'],\n    '@typescript-eslint/member-ordering': [\n      'error',\n      { default: ['signature', 'field', 'constructor', 'method'] }\n    ],\n    '@typescript-eslint/no-unused-vars': ['error'],\n    'no-redeclare': 0,\n    '@typescript-eslint/no-redeclare': 1,\n  },\n};\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# ref: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners\n\n# These owners will be the default owners for everything in\n# the repo. Unless a later match takes precedence\n* @liujuping @1ncounter\n\n/modules/material-parser @akirakai\n/modules/code-generator @qingniaotonghua\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "content": "---\nname: Bug report / 提交 bug\nabout: Create a report to help us improve / 提交一个好的 issue 帮助我们优化引擎，[引擎的 issue 说明](https://lowcode-engine.cn/site/community/issue)\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n## **Describe the bug (required)** / **详细描述 bug（必填）**\n\nA clear and concise description of what the bug is. / 请提供清晰且精确的 bug 描述\n\n---\n\n## **To Reproduce (required)** / **如何复现 bug？（必填，非常重要）**\n\nSteps to reproduce the behavior: / 详细复现步骤：\n\n---\n\nEnglish version example：\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n中文版示例：\n1. 打开 [demo](http://lowcode-engine.cn/demo)；\n2. 点击标题；\n3. 在右侧修改标题内容为「修改后的标题」；\n4. 渲染画布标题组件没有更新显示为「修改后的标题」；\n\n## **Expected behavior (required)** / **预期行为（必填，非常重要）**\nA clear and concise description of what did you expect to happen. / 请清晰和精确的描述你预期的行为\n\n---\n\n## **Screenshots (optional)** / **bug 截图（可选）**\nSceenshots for further information. (If applicable.) / 一些有用的截图将会帮助我们更好的明确以及定位问题\n\n---\n\n## **Environments (please complete the following information) (required):** / **请提供如下信息（必填）**\n - AliLowCodeEngine version: [e.g. 1.0.0] / 低代码引擎版本\n - AliLowCodeEngineExt version: [e.g. 1.0.0] / 低代码引擎扩展包版本\n - Browser [e.g. chrome, safari] / 浏览器版本\n - materials / plugins / tools / 其他物料 / 插件 / 工具链版本\n\n> (this information can be collected via [the manual plugin](https://img.alicdn.com/imgextra/i1/O1CN0115zonY1IsgbkZ2ir7_!!6000000000949-2-tps-3066-1650.png) / 版本信息可[通过低代码用户手册插件收集](https://img.alicdn.com/imgextra/i1/O1CN0115zonY1IsgbkZ2ir7_!!6000000000949-2-tps-3066-1650.png))\n\n## **Additional context (optional)** / **更多额外信息（可选）**\nAny other context of the problem here. / 可以追加更多的额外信息，帮助定位问题\n"
  },
  {
    "path": ".github/workflows/check base branch.yml",
    "content": "name: Check Base Branch\n\non:\n  pull_request:\n    types: [opened]\n\njobs:\n  code-review:\n    name: Check\n    runs-on: ubuntu-latest\n\n    steps:\n      # 判断用户是否有写仓库权限\n      - name: 'Check User Permission'\n        uses: 'lannonbr/repo-permission-check-action@2.0.0'\n        with:\n          permission: 'write'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: 'Check base branch name is develop or not'\n        if: github.event.pull_request.base.ref != 'develop'   # check the target branch if it's master\n        uses: actions-cool/issues-helper@v2\n        with:\n          actions: 'create-comment'\n          token: ${{ secrets.GITHUB_TOKEN }}\n          issue-number: ${{ github.event.pull_request.number }}\n          body: |\n            感谢你的 PR，根据引擎的 [研发协作流程](https://lowcode-engine.cn/site/docs/participate/flow)，请将目标合入分支设置为 **develop**。\n\n            Thanks in advance, according to the [Contribution Guideline](https://lowcode-engine.cn/site/docs/participate/flow), please set the base branch to **develop**.\n\n            @${{ github.event.pull_request.user.login }}"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Node CI\n\non:\n push:\n    branches:\n      - main\n pull_request:\n    branches:\n      - main\n\njobs:\n  upload-designer-codecov:\n    runs-on: ubuntu-latest\n    # if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test designer\n        run: cd packages/designer && npm run test:cov && cd ../..\n\n      - name: Upload designer coverage to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          # working-directory: packages/designer\n          directory: ./packages/designer/coverage\n          token: ${{ secrets.CODECOV_TOKEN }}\n          name: designer\n          fail_ci_if_error: true\n          verbose: true\n\n  upload-renderer-core:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test renderer-core\n        run: cd packages/renderer-core && npm run test:cov && cd ../..\n\n      - name: Upload renderer-core coverage to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          # working-directory: packages/designer\n          directory: ./packages/renderer-core/coverage\n          token: ${{ secrets.CODECOV_TOKEN }}\n          name: renderer-core\n          fail_ci_if_error: true\n          verbose: true\n\n  upload-react-simulator-renderer:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test react-simulator-renderer\n        run: cd packages/react-simulator-renderer && npm run test:cov && cd ../..\n\n      - name: Upload react-simulator-renderer coverage to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          # working-directory: packages/designer\n          directory: ./packages/react-simulator-renderer/coverage\n          token: ${{ secrets.CODECOV_TOKEN }}\n          name: react-simulator-renderer\n          fail_ci_if_error: true\n          verbose: true\n\n  upload-code-generator:\n    runs-on: ubuntu-latest\n    # if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test code-generator\n        run: cd modules/code-generator && npm i && npm run build && npm run test:cov && cd ../..\n\n      - name: Upload code-generator coverage to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          # working-directory: packages/designer\n          directory: ./modules/code-generator/coverage\n          token: ${{ secrets.CODECOV_TOKEN }}\n          name: code-generator\n          fail_ci_if_error: true\n          verbose: true"
  },
  {
    "path": ".github/workflows/cov packages.yml",
    "content": "name: coverage\n\non:\n  pull_request:\n    paths:\n      - 'packages/**'\n      - '!packages/**.md'\n\njobs:\n  cov-designer:\n    runs-on: ubuntu-latest\n    # skip fork's PR, otherwise it fails while making a comment\n    if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - uses: ArtiomTr/jest-coverage-report-action@v2\n        with:\n          working-directory: packages/designer\n          test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json\n          package-manager: yarn\n          annotations: none\n\n  cov-renderer-core:\n    runs-on: ubuntu-latest\n    # skip fork's PR, otherwise it fails while making a comment\n    if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - uses: ArtiomTr/jest-coverage-report-action@v2\n        with:\n          working-directory: packages/renderer-core\n          test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json\n          package-manager: yarn\n          annotations: none\n\n  cov-react-simulator-renderer:\n    runs-on: ubuntu-latest\n    # skip fork's PR, otherwise it fails while making a comment\n    if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - uses: ArtiomTr/jest-coverage-report-action@v2\n        with:\n          working-directory: packages/react-simulator-renderer\n          test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json\n          package-manager: yarn\n          annotations: none\n\n  cov-utils:\n    runs-on: ubuntu-latest\n    # skip fork's PR, otherwise it fails while making a comment\n    if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - uses: ArtiomTr/jest-coverage-report-action@v2\n        with:\n          working-directory: packages/utils\n          test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json\n          package-manager: yarn\n          annotations: none"
  },
  {
    "path": ".github/workflows/help wanted.yml",
    "content": "name: Help Wanted\n\non:\n  issues:\n    types: [labeled]\n\njobs:\n  reply-helper:\n    runs-on: ubuntu-latest\n    steps:\n      - name: help wanted\n        if: github.event.label.name == 'help wanted'\n        uses: actions-cool/issues-helper@v2\n        with:\n          actions: 'create-comment'\n          token: ${{ secrets.GITHUB_TOKEN }}\n          issue-number: ${{ github.event.issue.number }}\n          body: |\n            Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, PR wanted。\n\n            你好 @${{ github.event.issue.user.login }}，我们完全同意你的提议/反馈，欢迎 PR。\n"
  },
  {
    "path": ".github/workflows/insufficient information.yml",
    "content": "name: Insufficient Info\n\non:\n  issues:\n    types: [labeled]\n\njobs:\n  reply-helper:\n    runs-on: ubuntu-latest\n    steps:\n      - name: insufficient information\n        if: github.event.label.name == 'insufficient information'\n        uses: actions-cool/issues-helper@v2\n        with:\n          actions: 'create-comment'\n          token: ${{ secrets.GITHUB_TOKEN }}\n          issue-number: ${{ github.event.issue.number }}\n          body: |\n            你好 @${{ github.event.issue.user.login }}，由于缺乏必要的信息（如 bug 重现步骤、引擎版本信息 等），无法定位问题，请按照 [issue bug 模板](https://github.com/alibaba/lowcode-engine/blob/main/.github/ISSUE_TEMPLATE/bug-report.md) 补全信息，也可以通过阅读 [引擎的 issue 说明](https://lowcode-engine.cn/site/community/issue) 了解什么类型的 issue 可以获得更好、更快的支持。\n"
  },
  {
    "path": ".github/workflows/pr comment by chatgpt.yml",
    "content": "name: Pull Request Review By ChatGPT\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened]\n\njobs:\n  code-review:\n    name: Code Review\n    runs-on: ubuntu-latest\n\n    steps:\n      # 判断用户是否有写仓库权限\n      - name: 'Check User Permission'\n        uses: 'lannonbr/repo-permission-check-action@2.0.0'\n        with:\n          permission: 'write'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: opensumi/actions/.github/actions/code-review@main\n        env:\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}"
  },
  {
    "path": ".github/workflows/pre build.yml",
    "content": "name: Pre Build\n\non:\n  push:\n    paths:\n      - 'packages/**'\n      - '!packages/**.md'\n  pull_request:\n    paths:\n      - 'packages/**'\n      - '!packages/**.md'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v2\n\n    - name: Install dependencies and setup\n      run: npm install && npm run setup\n\n    - name: Build\n      run: npm run build\n\n    - name: Check build status\n      run: |\n        if [ $? -eq 0 ]; then\n          echo \"Build succeeded!\"\n        else\n          echo \"Build failed!\"\n          exit 1\n        fi\n"
  },
  {
    "path": ".github/workflows/publish docs.yml",
    "content": "name: Update and Publish Docs\n\non:\n  push:\n    branches:\n      - develop\n    paths:\n      - 'docs/docs/**'\n  workflow_dispatch:\n\njobs:\n  publish-docs:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup Node.js\n        uses: actions/setup-node@v2\n        with:\n          ref: 'develop'\n          node-version: '16'\n          registry-url: 'https://registry.npmjs.org'\n      - run: cd docs && npm install\n      - run: |\n          cd docs\n          npm version patch\n          git config --local user.email \"action@github.com\"\n          git config --local user.name \"GitHub Action\"\n          git add package.json\n          git commit -m \"chore(docs): publish documentation\"\n          git push\n      - run: cd docs && npm run build && npm publish\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n      - name: Get version\n        id: get_version\n        run: echo \"version=$(node -p \"require('./docs/package.json').version\")\" >> $GITHUB_OUTPUT\n\n  comment-pr:\n    needs: publish-docs\n    runs-on: ubuntu-latest\n    steps:\n      - name: Comment on PR\n        if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true\n        uses: actions/github-script@v4\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          script: |\n            github.issues.createComment({\n              issue_number: context.issue.number,\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}'\n            })\n"
  },
  {
    "path": ".github/workflows/publish engine beta.yml",
    "content": "name: Publish Engine Beta\n\non:\n  push:\n    branches:\n      - 'release/[0-9]+.[0-9]+.[0-9]+-beta'\n    paths:\n      - 'packages/**'\n\njobs:\n  publish-engine:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup Node.js\n        uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n          registry-url: 'https://registry.npmjs.org'\n      - run: npm install && npm run setup\n      - run: |\n          npm run build\n          git config --local user.email \"action@github.com\"\n          git config --local user.name \"GitHub Action\"\n      - run: npm run pub:prerelease\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n      - name: Get version\n        id: get_version\n        run: echo \"version=$(node -p \"require('./package.json').version\")\" >> $GITHUB_OUTPUT\n"
  },
  {
    "path": ".github/workflows/publish engine.yml",
    "content": "name: Publish Engine\n\non:\n  workflow_dispatch:\n    inputs:\n      publishCommand:\n        description: 'publish command'\n        required: true\n\njobs:\n  publish-engine:\n    runs-on: ubuntu-latest\n    if: >-\n      contains(github.ref, 'refs/heads/release/') &&\n      (github.actor == '1ncounter' || github.actor == 'liujuping')\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup Node.js\n        uses: actions/setup-node@v2\n        with:\n          node-version: '16'\n          registry-url: 'https://registry.npmjs.org'\n      - run: npm install && npm run setup\n      - run: |\n          npm run build\n          git config --local user.email \"action@github.com\"\n          git config --local user.name \"GitHub Action\"\n      - run: npm run ${{ github.event.inputs.publishCommand }}\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n      - name: Get version\n        id: get_version\n        run: echo \"version=$(node -p \"require('./package.json').version\")\" >> $GITHUB_OUTPUT\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: 'Close stale issues and PRs'\non:\n  schedule:\n    - cron: '30 1 * * *'\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v4\n        with:\n          stale-issue-message: 'This issue is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 2 days.'\n          stale-pr-message: 'This PR is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 2 days.'\n          close-issue-message: 'This issue was closed because it has been stalled for 10 days with no activity.'\n          close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.'\n          days-before-issue-stale: 10\n          days-before-issue-close: 10\n          days-before-pr-stale: 10\n          days-before-pr-close: 10\n          exempt-issue-labels: 'bug,enhancement,good first issue,help wanted,WIP,discussion,documentation,later,material'\n          stale-issue-label: 'stale'\n          stale-pr-label: 'stale'\n          exempt-all-assignee: true"
  },
  {
    "path": ".github/workflows/test modules.yml",
    "content": "name: Lint & Test (Mods)\n\non:\n  push:\n    paths:\n      - 'modules/**'\n      - '!modules/**.md'\n  pull_request:\n    paths:\n      - 'modules/**'\n      - '!modules/**.md'\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i\n\n      - name: lint\n        run: npm run lint:modules\n\n  test-code-generator:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd modules/code-generator && npm i && npm run build && npm test"
  },
  {
    "path": ".github/workflows/test packages.yml",
    "content": "name: Lint & Test (Pkgs)\n\non:\n  push:\n    paths:\n      - 'packages/**'\n      - '!packages/**.md'\n  pull_request:\n    paths:\n      - 'packages/**'\n      - '!packages/**.md'\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: lint\n        run: npm run lint\n\n  test-designer:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd packages/designer && npm test\n\n  test-editor-skeleton:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd packages/editor-skeleton && npm test\n\n  test-renderer-core:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd packages/renderer-core && npm test\n\n  test-react-simulator-renderer:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd packages/react-simulator-renderer && npm test\n\n  test-utils:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd packages/utils && npm test\n\n  test-editor-core:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd packages/editor-core && npm test\n\n  test-plugin-command:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v2\n\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14'\n\n      - name: install\n        run: npm i && npm run setup:skip-build\n\n      - name: test\n        run: cd packages/plugin-command && npm test"
  },
  {
    "path": ".gitignore",
    "content": "# project custom\nbuild\ndist\npackages/*/lib/\npackages/*/es/\npackages/*/dist/\npackages/*/output/\npackages/demo/\npackage-lock.json\nyarn.lock\npnpm-lock.yaml\ndeploy-space/packages\ndeploy-space/.env\n\n\n# IDE\n.vscode\n.idea\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\ncoverage-all\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\nlib\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# mac config files\n.DS_Store\n\n# codealike\ncodealike.json\n.node\n\n.must.config.js"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n  printWidth: 100,\n  tabWidth: 2,\n  semi: true,\n  singleQuote: true,\n  trailingComma: 'all',\n};\n"
  },
  {
    "path": ".stylelintignore",
    "content": "# 忽略目录\nnode_modules/\nbuild/\ndist/\n\n# 忽略文件\n**/*.min.css\n**/*-min.css\n**/*.bundle.css\n"
  },
  {
    "path": ".stylelintrc.js",
    "content": "module.exports = {\n  extends: 'stylelint-config-ali',\n  rules: {\n    \"selector-max-id\": 2\n  }\n};\n"
  },
  {
    "path": "CONTRIBUTOR.md",
    "content": "十分感谢参与贡献过低代码引擎的小伙伴们，下面名单按字母排序：\n- [albertxiao1994](https://github.com/albertxiao1994)\n- [alex-mm](https://github.com/alex-mm)\n- [alvarto](https://github.com/alvarto)\n- [alvinhui](https://github.com/alvinhui)\n- [boycgit](https://github.com/boycgit)\n- [chenmingjia](https://github.com/chenmingjia)\n- [Clarence-pan](https://github.com/Clarence-pan)\n- [hujiulong](https://github.com/hujiulong)\n- [hzd822](https://github.com/hzd822)\n- [JackLian](https://github.com/JackLian)\n- [jayjliang](https://github.com/jayjliang)\n- [Jeffery-Young](https://github.com/Jeffery-Young)\n- [jinggk](https://github.com/jinggk)\n- [junlonghuo](https://github.com/junlonghuo)\n- [leoyuan](https://github.com/leoyuan)\n- [liujuping](https://github.com/liujuping)\n- [lqy978599280](https://github.com/lqy978599280)\n- [markyun](https://github.com/markyun)\n- [mark-ck](https://github.com/mark-ck)\n- [mochen666](https://github.com/mochen666)\n- [tsy77](https://github.com/tsy77)\n- [yanbingbing](https://github.com/yanbingbing)\n- [Ychangqing](https://github.com/Ychangqing)\n- [yize](https://github.com/yize)\n- [youluna](https://github.com/youluna)\n- [ibreathebsb](https://github.com/ibreathebsb)\n\n如果您贡献过低代码引擎，但是没有看到您的名字，为我们的疏忽感到抱歉。欢迎您通过 PR 补充上自己的名字。\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Alibaba\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "abc.json",
    "content": "{\n  \"name\": \"lowcode-engine\",\n  \"assets\": {\n    \"type\": \"command\",\n    \"command\": {\n      \"cmd\": [\n        \"./scripts/deploy.sh $BUILD_DEST\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  plugins: [\n    ['@babel/plugin-proposal-decorators', { legacy: true }],\n    [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }],\n  ],\n};"
  },
  {
    "path": "commitlint.config.js",
    "content": "module.exports = {\n  extends: ['ali'],\n};\n"
  },
  {
    "path": "deploy-space/lerna.json",
    "content": "{\n  \"version\": \"independent\",\n  \"npmClient\": \"yarn\",\n  \"registry\": \"http://registry.npm.alibaba-inc.com\",\n  \"useWorkspaces\": true,\n  \"packages\": [\n    \"packages/*\"\n  ]\n}\n"
  },
  {
    "path": "deploy-space/package.json",
    "content": "{\n  \"private\": true,\n  \"workspaces\": {\n    \"packages\": [\n      \"packages/*\"\n    ],\n    \"nohoist\": [\n      \"**/css-modules-typescript-loader\",\n      \"**/@alife/theme-lowcode-*\"\n    ]\n  },\n  \"dependencies\": {\n    \"tslib\": \"^1.11.1\",\n    \"typescript\": \"^3.8.3\"\n  }\n}\n"
  },
  {
    "path": "deploy-space/static/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>LowCodeEngine Editor DEMO</title>\n    <link rel=\"shortcut icon\" href=\"./favicon.png\" />\n    <script src=\"https://g.alicdn.com/code/lib/react/16.9.0/umd/react.development.js\"></script>\n    <script src=\"https://g.alicdn.com/code/lib/react-dom/16.9.0/umd/react-dom.development.js\"></script>\n    <script src=\"https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\"></script>\n    <script> React.PropTypes = PropTypes; </script>\n    <script src=\"https://g.alicdn.com/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js\"></script>\n    <script src=\"https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css\" />\n    <script src=\"https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js\"></script>\n    <!-- lowcode engine globals -->\n    <link rel=\"stylesheet\" href=\"./editor-preset-vision.css\" />\n    <!-- lowcode engine app -->\n    <link rel=\"stylesheet\" href=\"./lowcode-editor.css\" />\n    <script>\n      window.pageConfig = {\n        env: 'release',\n        locale: 'zh-CN',\n        pageType: 'single',\n        deviceType: 'web',\n        appName: '基础包管理后台',\n        appType: '',\n        templateType: '',\n        pageId: 'FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V',\n        slug: 'test',\n        appMode: 'back',\n        isAppAdmin: 'y',\n        isSuperAdmin: 'n',\n        isBetaDeveloper: 'n',\n        formType: 'display',\n        title: { 'en-US': 'Test', type: 'i18n', 'zh-CN': '测试' },\n        urlPrefix: 'https://go.alibaba-inc.com',\n        APIUrlPrefix: 'https://mocks.alibaba-inc.com/mock/lowCodeEngine',\n        devVersion: '0.1.0', // 这个是子应用的变更 id\n        subAppType: '0.1.0',\n        appKey: '',\n        RE_VERSION: '7.1.1',\n        appSource: '',\n        isDomainDefault: 'n',\n        useReleaseBundle: 'n',\n        isDomainPkg: 'n',\n        medusaAppName: '',\n        domainCode: 'kS6SyH',\n        aecp: {\n          mdcDomain: '',\n          projectId: '',\n          appCode: '',\n        },\n        designerConfigs: {},\n        navConfig:\n          '{\"appName\":{\"en-US\":\"基础包管理后台\",\"key\":\"\",\"type\":\"i18n\",\"zh-CN\":\"基础包管理后台\"},\"bgColor\":\"white\",\"data\":[{\"children\":[],\"hidden\":false,\"icon\":\"\",\"inner\":true,\"navUuid\":\"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V\",\"relateUuid\":\"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V\",\"slug\":\"test\",\"targetNew\":false,\"title\":{\"en-US\":\"测试\",\"type\":\"i18n\",\"zh-CN\":\"测试\"}}],\"isFixed\":\"y\",\"isFold\":\"y\",\"isFoldHorizontal\":\"n\",\"languageChangeUrl\":{\"en-US\":\"/common/account/changeAccountLanguage.json\",\"type\":\"i18n\",\"zh-CN\":\"/common/account/changeAccountLanguage.json\"},\"layout\":\"auto\",\"navStyle\":\"orange\",\"navTheme\":\"light\",\"openSubMode\":false,\"showAppTitle\":true,\"showCrumb\":true,\"showIcon\":false,\"showLanguageChange\":true,\"showNav\":true,\"showSearch\":\"n\",\"singletons\":{\"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V\":{\"isFixed\":\"n\",\"isFold\":\"n\",\"isFoldHorizontal\":\"n\",\"showAppTitle\":false,\"showCrumb\":false,\"showLanguageChange\":false,\"showNav\":false,\"showSearch\":\"n\",\"singleton\":false},\"test\":{\"$ref\":\"$.singletons.FORM\\\\-3KYJN7RV\\\\-DIOD8LLK1WGQ89S7NHA92\\\\-QJVH497K\\\\-V\"}},\"type\":\"top_fold\"}',\n        historyType: 'HASH',\n        isSinglePage: 'n',\n        rhino: 'n',\n        isMiniApp: '',\n        taskId: '',\n        appSchema: 'V5',\n        openSubMode: 'n',\n      };\n      window.g_config = {};\n    </script>\n  </head>\n\n  <body>\n    <div id=\"lce-container\"></div>\n    <!-- lowcode engine globals -->\n    <script src=\"./editor-preset-vision.js\"></script>\n    <script src=\"https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js\"></script>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"//g.alicdn.com/??platform/common/s/1.1/global/global.css,uxcore/uxcore-kuma/2.2.1/orange.min.css\">\n    <!-- lowcode engine app -->\n    <script src=\"./lowcode-editor.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "deploy-space/static/preview.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>LowCodeEngine Editor DEMO</title>\n    <link rel=\"shortcut icon\" href=\"./favicon.png\" />\n    <script src=\"https://g.alicdn.com/code/lib/react/16.9.0/umd/react.development.js\"></script>\n    <script src=\"https://g.alicdn.com/code/lib/react-dom/16.9.0/umd/react-dom.development.js\"></script>\n    <script src=\"https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\"></script>\n    <script> React.PropTypes = PropTypes; </script>\n    <script src=\"https://g.alicdn.com/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js\"></script>\n    <script src=\"https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css\" />\n    <script src=\"https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js\"></script>\n    <!-- lowcode engine globals -->\n    <link rel=\"stylesheet\" href=\"./core.css\" />\n    <!-- lowcode engine globals -->\n    <link rel=\"stylesheet\" href=\"./vision-preset.css\" />\n    <!-- lowcode engine app -->\n    <link rel=\"stylesheet\" href=\"./lowcode-editor.css\" />\n    <script>\n      window.pageConfig = {\n        env: 'release',\n        locale: 'zh-CN',\n        pageType: 'single',\n        deviceType: 'web',\n        appName: '基础包管理后台',\n        appType: '',\n        templateType: '',\n        pageId: 'FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V',\n        slug: 'test',\n        appMode: 'back',\n        isAppAdmin: 'y',\n        isSuperAdmin: 'n',\n        isBetaDeveloper: 'n',\n        formType: 'display',\n        title: { 'en-US': 'Test', type: 'i18n', 'zh-CN': '测试' },\n        urlPrefix: 'https://go.alibaba-inc.com',\n        APIUrlPrefix: 'https://mocks.alibaba-inc.com/mock/lowCodeEngine',\n        devVersion: '0.1.0', // 这个是子应用的变更 id\n        subAppType: '0.1.0',\n        appKey: '',\n        RE_VERSION: '7.1.1',\n        appSource: '',\n        isDomainDefault: 'n',\n        useReleaseBundle: 'n',\n        isDomainPkg: 'n',\n        medusaAppName: '',\n        domainCode: 'kS6SyH',\n        aecp: {\n          mdcDomain: '',\n          projectId: '',\n          appCode: '',\n        },\n        designerConfigs: {},\n        navConfig:\n          '{\"appName\":{\"en-US\":\"基础包管理后台\",\"key\":\"\",\"type\":\"i18n\",\"zh-CN\":\"基础包管理后台\"},\"bgColor\":\"white\",\"data\":[{\"children\":[],\"hidden\":false,\"icon\":\"\",\"inner\":true,\"navUuid\":\"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V\",\"relateUuid\":\"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V\",\"slug\":\"test\",\"targetNew\":false,\"title\":{\"en-US\":\"测试\",\"type\":\"i18n\",\"zh-CN\":\"测试\"}}],\"isFixed\":\"y\",\"isFold\":\"y\",\"isFoldHorizontal\":\"n\",\"languageChangeUrl\":{\"en-US\":\"/common/account/changeAccountLanguage.json\",\"type\":\"i18n\",\"zh-CN\":\"/common/account/changeAccountLanguage.json\"},\"layout\":\"auto\",\"navStyle\":\"orange\",\"navTheme\":\"light\",\"openSubMode\":false,\"showAppTitle\":true,\"showCrumb\":true,\"showIcon\":false,\"showLanguageChange\":true,\"showNav\":true,\"showSearch\":\"n\",\"singletons\":{\"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V\":{\"isFixed\":\"n\",\"isFold\":\"n\",\"isFoldHorizontal\":\"n\",\"showAppTitle\":false,\"showCrumb\":false,\"showLanguageChange\":false,\"showNav\":false,\"showSearch\":\"n\",\"singleton\":false},\"test\":{\"$ref\":\"$.singletons.FORM\\\\-3KYJN7RV\\\\-DIOD8LLK1WGQ89S7NHA92\\\\-QJVH497K\\\\-V\"}},\"type\":\"top_fold\"}',\n        historyType: 'HASH',\n        isSinglePage: 'n',\n        rhino: 'n',\n        isMiniApp: '',\n        taskId: '',\n        appSchema: 'V5',\n        openSubMode: 'n',\n      };\n      window.g_config = {};\n    </script>\n  </head>\n\n  <body>\n    <div id=\"lce-container\"></div>\n    <!-- lowcode engine globals -->\n    <script src=\"./core.js\"></script>\n    <!-- lowcode engine globals -->\n    <script src=\"./vision-preset.js\"></script>\n    <script src=\"https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js\"></script>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"//g.alicdn.com/??platform/common/s/1.1/global/global.css,uxcore/uxcore-kuma/2.2.1/orange.min.css\">\n    <!-- lowcode engine app -->\n    <script src=\"./lowcode-editor.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "deploy-space/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"declaration\": false,\n    \"lib\": [\"es2015\", \"dom\"],\n    // Target latest version of ECMAScript.\n    \"target\": \"esnext\",\n    // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.\n    \"module\": \"esnext\",\n    // Search under node_modules for non-relative imports.\n    \"moduleResolution\": \"node\",\n    // Process & infer types from .js files.\n    \"allowJs\": true,\n    // Report errors in .js files.\n    \"checkJs\": false,\n    // Don't emit; allow Babel to transform files.\n    // \"noEmit\": true,\n    // Enable strictest settings like strictNullChecks & noImplicitAny.\n    \"strict\": false,\n    // Allow default imports from modules with no default export. This does not affect code emit, just typechecking.\n    \"allowSyntheticDefaultImports\": true,\n    // Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.\n    \"esModuleInterop\": true,\n    // Specify JSX code generation: 'preserve', 'react-native', or 'react'.\n    \"jsx\": \"preserve\",\n    // Import emit helpers (e.g. __extends, __rest, etc..) from tslib\n    \"importHelpers\": true,\n    // Enables experimental support for ES7 decorators.\n    \"experimentalDecorators\": true,\n    // Generates corresponding .map file.\n    \"sourceMap\": false,\n    // Disallow inconsistently-cased references to the same file.\n    \"forceConsistentCasingInFileNames\": true,\n    // Allow json import\n    \"resolveJsonModule\": true,\n    // skip type checking of declaration files\n    \"skipLibCheck\": true,\n    \"outDir\": \"lib\"\n  },\n  \"exclude\": [\"**/test\", \"**/lib\", \"**/es\", \"node_modules\"]\n}\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "docs/README.md",
    "content": "# Low-Code Engine 文档中心（site）\n\nThis website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.\n\n### 安装\n\n```\n$ yarn\n```\n\n### 本地开发\n\n```\n$ yarn start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.\n\n### 构建\n\n```\n$ yarn build\n```\n\n### 部署\n```bash\n1. npm run build\n2. npm publish # 记得改下版本号，比如 1.0.1\n\n# 发布完后执行 tnpm syncOss 同步到 uipaas CDN\n3. tnpm syncOss\n\n4. 更新 diamond 版本 1.0.1\n5. lowcode-engine.cn 站点生效\n```\n\n\n## 功能\n- [x] 支持本地离线搜搜\n- [x] 版本化文档管理\n- [x] 离线静态部署\n- [x] 主题（fork 宜搭开发者中心）\n\n## 使用文档\nhttps://docusaurus.io/zh-CN/docs/docs-introduction\n"
  },
  {
    "path": "docs/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "docs/community/issue.md",
    "content": "---\ntitle: 关于引擎的 issue 说明\nsidebar_position: 2\n---\n> 提交地址：[https://github.com/alibaba/lowcode-engine/issues](https://github.com/alibaba/lowcode-engine/issues)\n\n### 提交前必读\n由于引擎项目复杂，很多问题在复现和沟通上无法花费太多时间，需要大家尽力将复现步骤说明白。\n\n\n![image.png](./img/you-think.png)\n\n**你以为的 issue**\n\n\n![image.png](./img/i-see.png)\n\n**我们看到的 issue**\n\n为了更好的进行协作，对引擎 issue 的处理定了一些处理的优先级。请大家认真阅读 Orz.\n\n- 【支持快】通过线上 Demo 地址 + 控制台输入 API 可复现。\n- 【支持快】通过线上 Demo + 导入 schema 可复现\n- 【支持稍慢】通过线上 Demo + 完整操作步骤可复现\n- 【支持稍慢】通过线上 Demo + 变更代码可复现，并清楚的说明变更代码的位置和内容\n- 【支持慢】有完整的项目地址，下载下来可直接安装依赖并启动复现的\n- 【支持慢】需求类型的由于人力有限，欢迎大家 PR，如能讲清楚背景上下文和场景，项目维护团队更容易给出方案建议或方向指引。\n- 【不保证提供支持】其他\n   - 只有标题没有复现步骤\n   - 复现步骤不清晰\n   - 和引擎无关的\n\n### 不同优先级的示例\n#### 【支持快】通过线上 Demo 地址 + 控制台输入 API 可复现。\n**示例**\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01np6ARb1KnJFOELjXg_!!6000000001208-2-tps-3322-1862.png)\n复现步骤：\n\n- 打开线上 demo\n- 在控制台输入\n```json\n// 当前 doc\nconst doc = window.AliLowCodeEngine.project.currentDocument\n\n// 新建 doc 并成功切换\nwindow.AliLowCodeEngine.project.openDocument({\n    componentName: 'Page'\n});\n\n// 无法切换回来\nwindow.AliLowCodeEngine.project.openDocument('docl4xkca5b')\n```\n\n预期效果：\n\n- 使用 openDocument 可以正常的切换回原来的 doc\n\n#### 【支持快】通过线上 demo + 导入 schema 可复现\n步骤：\n\n- 使用线上 demo\n- 导入下面的 schema\n- schema 代码/schema zip 压缩包\n- 页面效果如下\n\n期望：\n\n- 页面中的 xxx 部分和预期不符合，期望的效果是 xxx\n\n#### 【支持稍慢】通过线上 demo + 完整操作步骤可复现\n**示例**\n1.使用 antd 组件\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN019dFe4Y24SDKbmpbdw_!!6000000007389-2-tps-3584-1812.png)\n\n2.拖拽这个组件\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN0109SdxO1OtxSbpLn4Q_!!6000000001764-2-tps-3584-1802.png)\n\n3.配置该属性值为 100\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01WeVXpW1HBny0VmQcS_!!6000000000720-2-tps-3584-1800.png)\n\n期望效果：\n\n- 组件同配置一致\n\n#### 【支持稍慢】通过线上 demo + 变更代码可复现，并清楚的说明变更代码的位置和内容\n**示例**\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01FL0Urq1tl1pLcYhJH_!!6000000005941-2-tps-1892-754.png)\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01WIpR9V1i363wzyFzi_!!6000000004356-2-tps-1917-778.png)\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01ZDkR3n1MNmP2uk15t_!!6000000001423-2-tps-1836-253.png)\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01OKzt1Z28b9WZIbM6B_!!6000000007950-2-tps-1912-914.png)\n\n#### 【支持慢】有完整的项目地址，下载下来可直接安装依赖并启动复现的\n由于完整的项目中有很多冗余的信息，这部分排查起来十分耗时且困难。不推荐使用改方式。\n\n#### 【不保证提供支持】其他\n##### 只有标题没有复现步骤\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN017rO2gR1YKpEgIMBjh_!!6000000003041-2-tps-2520-1020.png)\n\n##### 复现步骤不清晰\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01vtHi5z225CC7aFVS2_!!6000000007068-2-tps-3584-1666.png)\n\n##### 和引擎无关的\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01KxqT9M1vcu25xJHFP_!!6000000006194-2-tps-2548-1430.png)\n\n\n\n\n### 扩展阅读\n强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393)，更好的问题更容易获得帮助。（此段参考 [antd](https://github.com/ant-design/ant-design)）\n"
  },
  {
    "path": "docs/config/navbar.js",
    "content": "/**\n * 此配置的修改，如未生效，可以重新启动下即可\n */\nmodule.exports = {\n  title: '',\n  logo: {\n    alt: 'LowCode-Engine',\n    src: 'https://img.alicdn.com/imgextra/i2/O1CN01uv6vu822RBCSYLro2_!!6000000007116-55-tps-139-26.svg',\n    srcDark: 'https://tianshu.alicdn.com/052a190e-c961-4afe-aa4c-49ee9722952d.svg',\n  },\n  items: [\n    {\n      type: 'doc',\n      docId: 'guide/quickStart/intro',\n      position: 'left',\n      label: '文档',\n    },\n    {\n      type: 'doc',\n      docId: 'api/index',\n      position: 'left',\n      label: 'API',\n    },\n    {\n      type: 'doc',\n      docId: 'specs/lowcode-spec',\n      position: 'left',\n      label: '协议',\n    },\n    {\n      type: 'doc',\n      docId: 'faq/index',\n      position: 'left',\n      label: 'FAQ',\n    },\n    {\n      type: 'doc',\n      docId: 'article/index',\n      position: 'left',\n      label: '文章',\n    },\n    {\n      type: 'doc',\n      docId: 'video/index',\n      position: 'left',\n      label: '视频',\n    },\n    {\n      type: 'doc',\n      docId: 'demoUsage/intro',\n      position: 'left',\n      label: 'Demo 使用文档',\n    },\n    {\n      to: '/community/issue',\n      position: 'left',\n      label: '社区',\n      activeBaseRegex: '/community/',\n    },\n    // 版本切换，如需，这里开启即可\n    // {\n    //   type: 'docsVersionDropdown',\n    //   position: 'right',\n    //   dropdownActiveClassDisabled: true,\n    // },\n    // {\n    {\n      href: 'https://github.com/alibaba/lowcode-engine',\n      position: 'right',\n      className: 'header-github-link',\n      'aria-label': 'GitHub repository',\n    },\n    {\n      type: 'doc',\n      docId: 'participate/index',\n      position: 'right',\n      label: '参与贡献',\n    },\n    {\n      type: 'search',\n      position: 'right',\n    },\n  ],\n};\n"
  },
  {
    "path": "docs/config/sidebars.js",
    "content": "/*\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nconst getDocsFromDir = require('../scripts/getDocsFromDir');\n\nmodule.exports = {\n  // 手动配置的导航\n  // guide: [\n  //   'guide/quickStart/intro',\n  //   'guide/quickStart/start',\n  //   {\n  //     type: 'category',\n  //     label: 'FAQ',\n  //     collapsed: false,\n  //     items: getDocsFromDir('guide/quickStart/faq'),\n  //   },\n  // ],\n  /**\n   * 根据当前目录自动生成导航配置\n   */\n  guide: [\n    [\n      {\n        type: 'category',\n        label: '入门',\n        collapsed: false,\n        items: getDocsFromDir('guide/quickStart'),\n      },\n      {\n        type: 'category',\n        label: '创建编辑器',\n        collapsed: false,\n        items: getDocsFromDir('guide/create'),\n      },\n      {\n        type: 'category',\n        label: '扩展编辑器',\n        collapsed: false,\n        items: getDocsFromDir('guide/expand/editor', [{ dir: 'guide/expand/editor/parts', label: 'Parts·造物' }]),\n      },\n      {\n        type: 'category',\n        label: '扩展运行时',\n        collapsed: false,\n        items: getDocsFromDir('guide/expand/runtime'),\n      },\n      {\n        type: 'category',\n        label: '设计原理',\n        collapsed: false,\n        items: getDocsFromDir('guide/design'),\n      },\n      {\n        type: 'category',\n        label: '附录',\n        collapsed: false,\n        items: [\n          {\n            type: 'link',\n            label: '更新日志',\n            href: 'https://github.com/alibaba/lowcode-engine/releases',\n          },\n          ...getDocsFromDir('guide/appendix'),\n          {\n            type: 'category',\n            label: '预置设置器详情',\n            items: getDocsFromDir('guide/appendix/setterDetails'),\n          },\n        ],\n      },\n      {\n        type: 'link',\n        label: '技术白皮书',\n        href: 'https://developer.aliyun.com/ebook/7507',\n      },\n    ],\n  ],\n  api: [\n    {\n      type: 'autogenerated',\n      dirName: 'api',\n    },\n  ],\n  specs: [\n    {\n      type: 'autogenerated',\n      dirName: 'specs',\n    },\n  ],\n  faq: [\n    {\n      type: 'autogenerated',\n      dirName: 'faq',\n    },\n  ],\n  participate: [\n    {\n      type: 'autogenerated',\n      dirName: 'participate',\n    },\n  ],\n  demoUsage: [\n    {\n      type: 'autogenerated',\n      dirName: 'demoUsage',\n    },\n  ],\n};\n"
  },
  {
    "path": "docs/config/sidebarsCommunity.js",
    "content": "module.exports = {\n  community: [\n    {\n      type: 'autogenerated',\n      dirName: '.',\n    },\n    {\n      type: 'link',\n      label: '生态资源',\n      href: 'https://github.com/lowcode-workspace/awesome-lowcode-engine',\n    },\n  ],\n};\n"
  },
  {
    "path": "docs/docs/api/canvas.md",
    "content": "---\ntitle: canvas - 画布 API\nsidebar_position: 10\n---\n\n> **@types** [IPublicApiCanvas](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/canvas.ts)<br/>\n> **@since** v1.1.0\n\n\n## 模块简介\n\n通过该模块可以触达对画布拖拽相关的一些能力。\n\n## 变量\n\n### dragon\n\n获取拖拽操作对象的实例\n\n`@type {IPublicModelDragon | null}`\n\n\n相关类型：[IPublicModelDragon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/dragon.ts)\n\n### activeTracker\n\n获取活动追踪器实例\n\n`@type {IPublicModelActiveTracker | null}`\n\n相关类型：[IPublicModelActiveTracker](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/active-tracker.ts)\n\n### isInLiveEditing\n\n是否处于 LiveEditing 状态\n\n`@type {boolean}`\n\n### clipboard\n全局剪贴板实例\n\n`@type {IPublicModelClipboard}`\n\n相关类型：[IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)\n\n## 方法\n\n### createLocation\n创建一个文档插入位置对象，该对象用来描述一个即将插入的节点在文档中的位置\n\n```typescript\n/**\n * 创建一个文档插入位置对象，该对象用来描述一个即将插入的节点在文档中的位置\n * create a drop location for document, drop location describes a location in document\n * @since v1.1.0\n */\ncreateLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation;\n```\n\n### createScroller\n创建一个滚动控制器 Scroller，赋予一个视图滚动的基本能力，\n```typescript\n/**\n * 创建一个滚动控制器 Scroller，赋予一个视图滚动的基本能力，\n * a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling\n * to some cordination by api scrollTo.\n *\n * when a scroller is inited, will need to pass is a scrollable, which has a scrollTarget.\n * and when scrollTo(options: { left?: number; top?: number }) is called, scroller will\n * move scrollTarget`s top-left corner to (options.left, options.top) that passed in.\n * @since v1.1.0\n */\ncreateScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller;\n\n```\n\n### createScrollTarget\n创建一个 ScrollTarget，与 Scroller 一起发挥作用，详见 [createScroller](#createscroller) 中的描述\n\n```typescript\n/**\n * 创建一个 ScrollTarget，与 Scroller 一起发挥作用，详见 createScroller 中的描述\n * this works with Scroller, refer to createScroller`s description\n * @since v1.1.0\n */\ncreateScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget;\n```\n"
  },
  {
    "path": "docs/docs/api/command.md",
    "content": "---\ntitle: command - 指令 API\nsidebar_position: 10\n---\n\n\n\n## 模块概览\n\n该模块使得与命令系统的交互成为可能，提供了一种全面的方式来处理、执行和管理应用程序中的命令。\n\n\n\n## 接口\n\n### IPublicApiCommand\n\n与命令交互的接口。它提供了注册、注销、执行和管理命令的方法。\n\n\n\n## 方法\n\n### registerCommand\n\n注册一个新命令及其处理函数。\n\n```\ntypescriptCopy code\n/**\n * 注册一个新的命令及其处理程序。\n * @param command {IPublicTypeCommand} - 要注册的命令。\n */\nregisterCommand(command: IPublicTypeCommand): void;\n```\n\n### unregisterCommand\n\n注销一个已存在的命令。\n\n```\ntypescriptCopy code\n/**\n * 注销一个已存在的命令。\n * @param name {string} - 要注销的命令的名称。\n */\nunregisterCommand(name: string): void;\n```\n\n### executeCommand\n\n根据名称和提供的参数执行命令，确保参数符合命令的定义。\n\n```\ntypescriptCopy code\n/**\n * 根据名称和提供的参数执行命令。\n * @param name {string} - 要执行的命令的名称。\n * @param args {IPublicTypeCommandHandlerArgs} - 命令的参数。\n */\nexecuteCommand(name: string, args?: IPublicTypeCommandHandlerArgs): void;\n```\n\n### batchExecuteCommand\n\n批量执行命令，在所有命令执行后进行重绘，历史记录中只记录一次。\n\n```\ntypescriptCopy code\n/**\n * 批量执行命令，随后进行重绘，历史记录中只记录一次。\n * @param commands {Array} - 命令对象的数组，包含名称和可选参数。\n */\nbatchExecuteCommand(commands: { name: string; args?: IPublicTypeCommandHandlerArgs }[]): void;\n```\n\n### listCommands\n\n列出所有已注册的命令。\n\n```\ntypescriptCopy code\n/**\n * 列出所有已注册的命令。\n * @returns {IPublicTypeListCommand[]} - 已注册命令的数组。\n */\nlistCommands(): IPublicTypeListCommand[];\n```\n\n### onCommandError\n\n为命令执行过程中的错误注册错误处理回调函数。\n\n```\ntypescriptCopy code\n/**\n * 为命令执行过程中的错误注册一个回调函数。\n * @param callback {(name: string, error: Error) => void} - 错误处理的回调函数。\n */\nonCommandError(callback: (name: string, error: Error) => void): void;\n```\n"
  },
  {
    "path": "docs/docs/api/common.md",
    "content": "---\ntitle: common - 通用 API\nsidebar_position: 10\n---\n\n> **@types** [IPublicApiCommon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/common.ts)<br/>\n> **@since** v1.0.0\n\n\n## 模块简介\n通用模块里包含除了几大核心模块 API 之外的所有 API，比如通用 utils、面板扩展相关 等。\n> 高能预警：之所以叫 skeletonCabin / designerCabin 跟兼容上一个版本的引擎有关系。若有必要，后面将用更有意义的命名空间来组织这些 API。\n\n## 变量\n#### utils\n通用 utils，详见下方方法签名\n\n相关类型：[IPublicApiCommonUtils](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/common.ts)\n\n#### skeletonCabin\n面板扩展相关，详见下方方法签名\n\n## 方法\n### utils\n#### isNodeSchema\n是否为合法的 schema 结构\n\n```typscript\n/**\n  * 是否为合法的 schema 结构\n  * check if data is valid NodeSchema\n  *\n  * @param {*} data\n  * @returns {boolean}\n  */\nisNodeSchema(data: any): boolean;\n```\n\n#### isFormEvent\n是否为表单事件类型\n\n```typescript\n/**\n * 是否为表单事件类型\n * check if e is a form event\n * @param {(KeyboardEvent | MouseEvent)} e\n * @returns {boolean}\n */\nisFormEvent(e: KeyboardEvent | MouseEvent): boolean;\n```\n\n#### getNodeSchemaById\n从 schema 结构中查找指定 id 节点\n```typescript\n/**\n * 从 schema 结构中查找指定 id 节点\n * get node schema from a larger schema with node id\n * @param {IPublicTypeNodeSchema} schema\n * @param {string} nodeId\n * @returns {(IPublicTypeNodeSchema | undefined)}\n */\ngetNodeSchemaById(\n    schema: IPublicTypeNodeSchema,\n    nodeId: string,\n  ): IPublicTypeNodeSchema | undefined;\n```\n相关类型：[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n#### executeTransaction\n批处理事务，用于优化特定场景的性能\n\n```typescript\n/**\n * 批处理事务，用于优化特定场景的性能\n * excute something in a transaction for performence\n *\n * @param {() => void} fn\n * @param {IPublicEnumTransitionType} type\n * @since v1.0.16\n */\nexecuteTransaction(fn: () => void, type: IPublicEnumTransitionType): void;\n```\n**@since v1.0.16**\n\n**示例**\n```typescript\nimport { common } from '@alilc/lowcode-engine';\nimport { IPublicEnumTransitionType } from '@alilc/lowcode-types';\n\ncommon.utils.startTransaction(() => {\n  node1.setProps();\n  node2.setProps();\n  node3.setProps();\n  // ...\n}, IPublicEnumTransitionType.repaint);\n```\n\n#### getConvertedExtraKey\n\nprops key 转化工具\n\n```typescript\ngetConvertedExtraKey(key: string): string\n\n```\n\n**@since v1.0.17**\n\n#### createIntl\ni18n 相关工具\n```typescript\n/**\n * i18n 相关工具\n * i18n tools\n *\n * @param {(string | object)} instance\n * @returns {{\n *     intlNode(id: string, params?: object): ReactNode;\n *     intl(id: string, params?: object): string;\n *     getLocale(): string;\n *     setLocale(locale: string): void;\n *   }}\n * @since v1.0.17\n */\ncreateIntl(instance: string | object): {\n  intlNode(id: string, params?: object): ReactNode;\n  intl(id: string, params?: object): string;\n  getLocale(): string;\n  setLocale(locale: string): void;\n};\n```\n\n**@since v1.0.17**\n\n**示例**\n\n```typescript\nimport { common } from '@alilc/lowcode-engine';\nimport enUS from './en-US.json';\nimport zhCN from './zh-CN.json';\n\nconst { intl, getLocale, setLocale } = common.utils.createIntl({\n  'en-US': enUS,\n  'zh-CN': zhCN,\n});\n\n```\n\n#### intl\n\ni18n 转换方法\n\n```typescript\n/**\n * i18n 转换方法\n */\nintl(data: IPublicTypeI18nData | string, params?: object): string;\n```\n\n**示例**\n```\nconst title = common.utils.intl(node.title)\n```\n\n### skeletonCabin\n#### Workbench\n编辑器框架 View\n\n```typescript\n/**\n * 编辑器框架 View\n * get Workbench Component\n */\nget Workbench(): Component;\n```\n"
  },
  {
    "path": "docs/docs/api/commonUI.md",
    "content": "---\ntitle: commonUI - UI 组件库\nsidebar_position: 10\n---\n\n## 简介\nCommonUI API 是一个专为低代码引擎设计的组件 UI 库，使用它开发的插件，可以保证在不同项目和主题切换中能够保持一致性和兼容性。\n\n## 组件列表\n\n### Tip\n\n提示组件\n\n| 参数      | 说明         | 类型                                  | 默认值 |\n|-----------|--------------|---------------------------------------|--------|\n| className | className    | string (optional)                     |        |\n| children  | tip 的内容   | IPublicTypeI18nData \\| ReactNode      |        |\n| direction | tip 的方向   | 'top' \\| 'bottom' \\| 'left' \\| 'right' |        |\n\n\n### HelpTip\n\n带 help icon 的提示组件\n\n| 参数      | 说明   | 类型                              | 默认值 |\n|-----------|--------|-----------------------------------|--------|\n| help      | 描述   | IPublicTypeHelpTipConfig          |        |\n| direction | 方向   | IPublicTypeTipConfig['direction'] | 'top'  |\n| size      | 方向   | IconProps['size']                 | 'small'|\n\n### Title\n\n标题组件\n\n| 参数      | 说明       | 类型                        | 默认值 |\n|-----------|------------|-----------------------------|--------|\n| title     | 标题内容   | IPublicTypeTitleContent     |        |\n| className | className  | string (optional)           |        |\n| onClick   | 点击事件   | () => void (optional)       |        |\n\n### ContextMenu\n\n| 参数   | 说明                                               | 类型                               | 默认值 |\n|--------|----------------------------------------------------|------------------------------------|--------|\n| menus  | 定义上下文菜单的动作数组                           | IPublicTypeContextMenuAction[]     |        |\n| children | 组件的子元素                                      | React.ReactElement[]               |        |\n\n**IPublicTypeContextMenuAction Interface**\n\n| 参数       | 说明                                                         | 类型                                                                                                           | 默认值                                 |\n|------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------|\n| name       | 动作的唯一标识符<br/>Unique identifier for the action         | string                                                                                                         |                                        |\n| title      | 显示的标题，可以是字符串或国际化数据<br/>Display title, can be a string or internationalized data | string \\| IPublicTypeI18nData (optional)                |                                        |\n| type       | 菜单项类型<br/>Menu item type                                 | IPublicEnumContextMenuType (optional)                                                                          | IPublicEnumContextMenuType.MENU_ITEM  |\n| action     | 点击时执行的动作，可选<br/>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional)                                                                 |                                        |\n| items      | 子菜单项或生成子节点的函数，可选，仅支持两级<br/>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \\| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) |                                        |\n| condition  | 显示条件函数<br/>Function to determine display condition      | (nodes: IPublicModelNode[]) => boolean (optional)                                                              |                                        |\n| disabled   | 禁用条件函数，可选<br/>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional)                                                              |                                        |\n\n**ContextMenu 示例**\n\n```typescript\nconst App = () => {\n  const menuItems: IPublicTypeContextMenuAction[] = [\n    {\n      name: 'a',\n      title: '选项 1',\n      action: () => console.log('选项 1 被点击'),\n    },\n    {\n      name: 'b',\n      title: '选项 2',\n      action: () => console.log('选项 2 被点击'),\n    },\n  ];\n\n  const ContextMenu = ctx.commonUI.ContextMenu;\n\n  return (\n    <div>\n      <ContextMenu menus={menuItems}>\n        <div>右键点击这里</div>\n      </ContextMenu>\n    </div>\n  );\n};\n\nexport default App;\n```\n\n**ContextMenu.create 示例**\n\n```typescript\nconst App = () => {\n  const menuItems: IPublicTypeContextMenuAction[] = [\n    {\n      name: 'a',\n      title: '选项 1',\n      action: () => console.log('选项 1 被点击'),\n    },\n    {\n      name: 'b',\n      title: '选项 2',\n      action: () => console.log('选项 2 被点击'),\n    },\n  ];\n\n  const ContextMenu = ctx.commonUI.ContextMenu;\n\n  return (\n    <div>\n      <div onClick={(e) => {\n      \tContextMenu.create(menuItems, e);\n      }}>点击这里</div>\n    </div>\n  );\n};\n\nexport default App;\n```\n\n### Balloon\n\n详细文档： [Balloon Documentation](https://fusion.design/pc/component/balloon)\n\n### Breadcrumb\n详细文档： [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb)\n\n### Button\n详细文档： [Button Documentation](https://fusion.design/pc/component/button)\n\n### Card\n详细文档：[Card Documentation](https://fusion.design/pc/component/card)\n\n### Checkbox\n详细文档：[Checkbox Documentation](https://fusion.design/pc/component/checkbox)\n\n### DatePicker\n详细文档：[DatePicker Documentation](https://fusion.design/pc/component/datepicker)\n\n### Dialog\n详细文档：[Dialog Documentation](https://fusion.design/pc/component/dialog)\n\n### Dropdown\n详细文档：[Dropdown Documentation](https://fusion.design/pc/component/dropdown)\n\n### Form\n详细文档：[Form Documentation](https://fusion.design/pc/component/form)\n\n### Icon\n详细文档：[Icon Documentation](https://fusion.design/pc/component/icon)\n\n引擎默认主题支持的 icon 列表：https://fusion.design/64063/component/icon?themeid=20133\n\n\n### Input\n详细文档：[Input Documentation](https://fusion.design/pc/component/input)\n\n### Loading\n详细文档：[Loading Documentation](https://fusion.design/pc/component/loading)\n\n### Message\n详细文档：[Message Documentation](https://fusion.design/pc/component/message)\n\n### Overlay\n详细文档：[Overlay Documentation](https://fusion.design/pc/component/overlay)\n\n### Pagination\n详细文档：[Pagination Documentation](https://fusion.design/pc/component/pagination)\n\n### Radio\n详细文档：[Radio Documentation](https://fusion.design/pc/component/radio)\n\n### Search\n详细文档：[Search Documentation](https://fusion.design/pc/component/search)\n\n### Select\n详细文档：[Select Documentation](https://fusion.design/pc/component/select)\n\n### SplitButton\n详细文档：[SplitButton Documentation](https://fusion.design/pc/component/splitbutton)\n\n### Step\n详细文档：[Step Documentation](https://fusion.design/pc/component/step)\n\n### Switch\n详细文档：[Switch Documentation](https://fusion.design/pc/component/switch)\n\n### Tab\n详细文档：[Tab Documentation](https://fusion.design/pc/component/tab)\n\n### Table\n详细文档：[Table Documentation](https://fusion.design/pc/component/table)\n\n### Tree\n详细文档：[Tree Documentation](https://fusion.design/pc/component/tree)\n\n### TreeSelect\n详细文档：[TreeSelect Documentation](https://fusion.design/pc/component/treeselect)\n\n### Upload\n详细文档：[Upload Documentation](https://fusion.design/pc/component/upload)\n\n### Divider\n详细文档：[Divider Documentation](https://fusion.design/pc/component/divider)\n\n## 说明\n\n如果需要其他组件，可以提 issue 给我们。\n"
  },
  {
    "path": "docs/docs/api/config.md",
    "content": "---\ntitle: config - 配置 API\nsidebar_position: 5\n---\n\n> **@types** [IPublicModelEngineConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/engine-config.ts)<br/>\n> **@since** v1.0.0\n\n\n## 模块简介\n配置模块，负责配置的读、写等操作。\n\n## 方法\n### get\n获取指定 key 的值\n\n```typescript\n/**\n * 获取指定 key 的值\n * get value by key\n * @param key\n * @param defaultValue\n * @returns\n */\nget(key: string, defaultValue?: any): any;\n```\n**示例**\n```typescript\nimport { config } from '@alilc/lowcode-engine';\n\nconfig.get('keyA', true);\nconfig.get('keyB', { a: 1 });\n```\n### set\n设置指定 key 的值\n\n```typescript\n/**\n * 设置指定 key 的值\n * set value for certain key\n * @param key\n * @param value\n */\nset(key: string, value: any): void;\n```\n**示例**\n```typescript\nimport { config } from '@alilc/lowcode-engine';\n\nconfig.set('keyC', 1);\n```\n\n### has\n判断指定 key 是否有值\n\n```typescript\n/**\n * 判断指定 key 是否有值\n * check if config has certain key configed\n * @param key\n * @returns\n */\nhas(key: string): boolean;\n```\n\n**示例**\n```typescript\nimport { config } from '@alilc/lowcode-engine';\n\nconfig.has('keyD');\n```\n\n### setConfig\n批量设值，set 的对象版本\n\n```typescript\n/**\n * 批量设值，set 的对象版本\n * set multiple config key-values\n * @param config\n */\nsetConfig(config: { [key: string]: any }): void;\n```\n**示例**\n```typescript\nimport { config } from '@alilc/lowcode-engine';\n\nconfig.setConfig({ keyA: false, keyB: 2 });\n```\n\n### getPreference\n获取全局 Preference 管理器，用于管理全局浏览器侧用户 Preference，如 Panel 是否钉住\n\n```typescript\n/**\n * 获取全局 Preference, 用于管理全局浏览器侧用户 Preference，如 Panel 是否钉住\n * get global user preference manager, which can be use to store\n * user`s preference in user localstorage, such as a panel is pinned or not.\n * @returns {IPublicModelPreference}\n * @since v1.1.0\n */\ngetPreference(): IPublicModelPreference;\n```\n相关类型：[IPublicModelPreference](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/preference.ts)\n\n**@since v1.1.0**\n\n示例\n\n```javascript\nimport { config } from '@alilc/lowcode-engine';\n\nconst panelName = 'outline-master-pane';\n\n// 设置大纲树面板钉住，在大纲树下次重新打开时生效\nconfig.getPreference().set(`${panelName}-pinned-status-isFloat`, false, 'skeleton')\n```\n\n## 事件\n\n### onceGot\n获取指定 key 的值，若此时还未赋值，则等待，若已有值，则直接返回值\n注：此函数返回 Promise 实例\n\n\n```typescript\n/**\n * 获取指定 key 的值，若此时还未赋值，则等待，若已有值，则直接返回值\n *  注：此函数返回 Promise 实例，只会执行（fullfill）一次\n * wait until value of certain key is set, will only be\n * triggered once.\n * @param key\n * @returns\n */\nonceGot(key: string): Promise<any>;\n```\n**示例**\n```typescript\nimport { config } from '@alilc/lowcode-engine';\n\nconfig.onceGot('keyA').then(value => {\n  console.log(`The value of keyA is ${value}`);\n});\n\n// or\nconst value = await config.onceGot('keyA');\n```\n\n### onGot\n获取指定 key 的值，函数回调模式，若多次被赋值，回调会被多次调用\n\n```typescript\n  /**\n   * 获取指定 key 的值，函数回调模式，若多次被赋值，回调会被多次调用\n   * set callback for event of value set for some key\n   * this will be called each time the value is set\n   * @param key\n   * @param fn\n   * @returns\n   */\n  onGot(key: string, fn: (data: any) => void): () => void;\n```\n**示例**\n```typescript\nimport { config } from '@alilc/lowcode-engine';\n\nconfig.onGot('keyA', (value) => {\n  console.log(`The value of keyA is ${value}`);\n});\n\nconst.set('keyA', 1); // 'The value of keyA is 1'\nconst.set('keyA', 2); // 'The value of keyA is 2'\n```"
  },
  {
    "path": "docs/docs/api/configOptions.md",
    "content": "---\ntitle: config options - 配置列表\nsidebar_position: 5\n---\n\n> **@types** [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts)<br/>\n\n## 配置方式\n\n#### init API\n\n```javascript\nimport { init } from '@alilc/lowcode-engine';\n\ninit(document.getElementById('engine'), {\n  enableCondition: false,\n});\n```\n\n[**init api**](./init)\n\n#### config API\n\n```javascript\nimport { config } from '@alilc/lowcode-engine';\n\nconfig.set('enableCondition', false)\n```\n\n[**config api**](./config)\n\n## 配置详情\n\n> 源码详见 [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts)\n\n\n### 画布\n\n#### locale - 语言\n\n`@type {string}`、`@default {zh-CN}`\n\n语言\n\n#### device - 设备类型\n\n`@type {string}`\n\n引擎默认支持的 device 类型有 `default`、`mobile`、`iphonex`、`iphone6`。\n\n插件 `@alilc/lowcode-plugin-simulator-select` 支持的 device 类型有 `default`、`phone`、`tablet`、`desktop`。\n\n如果需要自定义的 device 类型，需要补充 device 类型对应的样式，例如 device 为 phone 时，需要补充样式如下：\n\n```css\n.lc-simulator-device-phone {\n  top: 16px;\n  bottom: 16px;\n  left: 50%;\n  width: 375px;\n  transform: translateX(-50%);\n  margin: auto;\n}\n```\n\n#### deviceClassName\n\n`@type {string}`\n\n指定初始化的 deviceClassName，挂载到画布的顶层节点上\n\n#### appHelper\n\n与 react-renderer 的 appHelper 一致，https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper\n\n\n#### enableCondition\n\n`@type {boolean}`\n\n是否开启 condition 的能力，默认在设计器中不管 condition 是啥都正常展示\n\n#### disableAutoRender\n\n`@type {boolean}` `@default {false}`\n\n关闭画布自动渲染，在资产包多重异步加载的场景有效\n\n#### renderEnv - 渲染器类型\n\n渲染器类型\n\n`@type {string}`、`@default {react}`\n\n#### simulatorUrl\n\n`@type {string[]}`\n\n设置 simulator 相关的 url\n\n#### enableStrictNotFoundMode\n\n`@type {boolean}` `@default {false}`\n\n当开启组件未找到严格模式时，渲染模块不会默认给一个容器组件\n\n### 编排\n\n#### focusNodeSelector - 指定根组件\n\n配置指定节点为根组件\n\n类型定义\n\n```typescript\n  focusNodeSelector?: (rootNode: IPublicModelNode) => Node;\n```\n\n#### supportVariableGlobally - 全局变量配置\n\n`@type {boolean}` `@default {false}`\n\n设置所有属性支持变量配置\n\n开启拖拽组件时，即将被放入的容器是否有视觉反馈\n\n#### customizeIgnoreSelectors - 点击忽略\n\n配置画布中，需要屏蔽点击事件的元素，即配置的元素默认点击行为均不生效。\n\n类型定义:\n\n```typescript\n  customizeIgnoreSelectors?: (defaultIgnoreSelectors: string[], e: MouseEvent) => string[];\n```\n\n默认值:\n\n```javascript\n() => {\n  return [\n    '.next-input-group',\n    '.next-checkbox-group',\n    '.next-checkbox-wrapper',\n    '.next-date-picker',\n    '.next-input',\n    '.next-month-picker',\n    '.next-number-picker',\n    '.next-radio-group',\n    '.next-range',\n    '.next-range-picker',\n    '.next-rating',\n    '.next-select',\n    '.next-switch',\n    '.next-time-picker',\n    '.next-upload',\n    '.next-year-picker',\n    '.next-breadcrumb-item',\n    '.next-calendar-header',\n    '.next-calendar-table',\n    '.editor-container', // 富文本组件\n  ]\n}\n```\n\n#### enableCanvasLock\n\n`@type {boolean}` `@default {false}`\n\n打开画布的锁定操作\n\n#### enableLockedNodeSetting\n\n`@type {boolean}` `@default {false}`\n\n容器锁定后，容器本身是否可以设置属性，仅当画布锁定特性开启时生效\n\n#### enableMouseEventPropagationInCanvas\n\n`@type {boolean}` `@default {false}`\n\n鼠标事件（mouseover、mouseleave、mousemove）在画布中是否允许冒泡，默认不允许。\n\n#### enableReactiveContainer\n\n`@type {boolean}` `@default {false}`\n\n#### enableContextMenu - 开启右键菜单\n\n`@type {boolean}` `@default {false}`\n\n是否开启右键菜单\n\n#### disableDetecting\n\n`@type {boolean}` `@default {false}`\n\n关闭拖拽组件时的虚线响应，性能考虑\n\n\n#### disableDefaultSettingPanel\n\n`@type {boolean}` `@default {false}`\n\n禁止默认的设置面板\n\n#### disableDefaultSetters\n\n`@type {boolean}` `@default {false}`\n\n禁止默认的设置器\n\n#### stayOnTheSameSettingTab\n\n`@type {boolean}` `@default {false}`\n\n当选中节点切换时，是否停留在相同的设置 tab 上\n\n#### hideSettingsTabsWhenOnlyOneItem\n\n`@type {boolean}` `@default {false}`\n\n是否在只有一个 item 的时候隐藏设置 tabs\n\n#### hideComponentAction\n\n`@type {boolean}` `@default {false}`\n\n隐藏设计器辅助层\n\n#### thisRequiredInJSE\n\n`@type {boolean}` `@default {true}`\n\nJSExpression 是否只支持使用 this 来访问上下文变量，假如需要兼容原来的 'state.xxx'，则设置为 false\n\n### 应用级设计器\n\n#### enableWorkspaceMode - 应用级设计模式\n\n`@type {boolean}` `@default {false}`\n\n开启应用级设计模式\n\n#### enableAutoOpenFirstWindow\n\n`@type {boolean}` `@default {true}`\n\n应用级设计模式下，自动打开第一个窗口\n\n#### workspaceEmptyComponent\n\n应用级设计模式下，当窗口为空时，展示的占位组件\n\n### 定制组件\n\n#### faultComponent\n\n组件渲染错误时的占位组件\n\n#### notFoundComponent\n\n组件不存在时的占位组件\n\n#### loadingComponent - loading 组件\n\n自定义 loading 组件\n\n### 插件\n\n#### defaultSettingPanelProps\n\n内置设置面板插件的 panelProps\n\n#### defaultOutlinePaneProps\n\n内置大纲树面板插件的 panelProps\n\n### 其他\n\n#### enableStrictPluginMode\n\n`@type {boolean}`\n\n开启严格插件模式，默认值：STRICT_PLUGIN_MODE_DEFAULT , 严格模式下，插件将无法通过 engineOptions 传递自定义配置项\n\n#### requestHandlersMap\n\n数据源引擎的请求处理器映射\n\n#### customPluginTransducer\n\n插件处理中间件，方便提供插件调试能力\n\n类型定义\n\n```typescript\ncustomPluginTransducer: async (originPlugin: IPublicTypePlugin, ctx: IPublicModelPluginContext, options): IPublicTypePlugin;\n```\n\n#### defaultOutlinePaneProps\n\n`@type {object}`\n\n大纲树插件面板默认 props\n\n"
  },
  {
    "path": "docs/docs/api/event.md",
    "content": "---\ntitle: event - 事件 API\nsidebar_position: 10\n---\n\n> **@types** [IPublicApiEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/event.ts)<br/>\n> **@since** v1.0.0\n\n\n## 模块简介\n负责事件处理 API，支持自定义监听事件、触发事件。\n\n## 方法\n### on\n监听事件\n\n```typescript\n/**\n * 监听事件\n * add monitor to a event\n * @param event 事件名称\n * @param listener 事件回调\n */\non(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;\n```\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### prependListener\n监听事件，会在其他回调函数之前执行\n\n```typescript\n/**\n * 监听事件，会在其他回调函数之前执行\n * @param event 事件名称\n * @param listener 事件回调\n */\nprependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;\n```\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### off\n取消监听事件\n\n```typescript\n/**\n * 取消监听事件\n * cancel a monitor from a event\n * @param event 事件名称\n * @param listener 事件回调\n */\noff(event: string, listener: (...args: any[]) => void): void;\n```\n\n### emit\n触发事件\n\n```typescript\n/**\n * 触发事件\n * emit a message for a event\n * @param event 事件名称\n * @param args 事件参数\n * @returns\n */\nemit(event: string, ...args: any[]): void;\n```\n\n## 使用示例\n### 事件触发和监听\n\n```typescript\nconst eventName = 'eventName';\n\n// 事件监听\n// 插件中发出的事件，默认以 `common` 为前缀，监听时需要注意下\nevent.on(`common:${eventName}`);\n\n// 触发事件\nevent.emit(eventName);\n```\n\n### setter 和 setter/plugin 之间的联动\n在 A setter 中进行事件注册：\n```typescript\nimport { event } from '@alilc/lowcode-engine';\n\nconst SETTER_NAME = 'SetterA';\n\nclass SetterA extends React.Component {\n  componentDidMount() {\n    // 这里由于面板上会有多个 setter，使用 field.id 来标记 setter 名\n    this.emitEventName = `${SETTER_NAME}-${this.props.field.id}`;\n    event.on(`common:${this.emitEventName}.bindEvent`, this.bindEvent)\n  }\n\n  bindEvent = (eventName) => {\n    // do someting\n  }\n\n  componentWillUnmount() {\n  \t// setter 是以实例为单位的，每个 setter 注销的时候需要把事件也注销掉，避免事件池过多\n    event.off(`common:${this.emitEventName}.bindEvent`, this.bindEvent)\n  }\n}\n```\n在 B setter 中触发事件，来完成通信：\n```typescript\nimport { event } from '@alilc/lowcode-engine';\n\nclass SetterB extends React.Component {\n  bindFunction = () => {\n    const { field, value } = this.props;\n    // 这里展示的和插件进行通信，事件规则是插件名 + 方法\n    event.emit('eventBindDialog.openDialog', field.name, this.emitEventName);\n  }\n}\n```\n"
  },
  {
    "path": "docs/docs/api/hotkey.md",
    "content": "---\ntitle:  hotkey - 快捷键 API\nsidebar_position: 10\n---\n\n> **@types** [IPublicApiHotkey](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/hotkey.ts)<br/>\n> **@since** v1.0.0\n\n## 模块简介\n绑定快捷键 API，可以自定义项目快捷键使用。\n\n## 方法\n### bind\n绑定快捷键\n\n```typescript\n/**\n * 绑定快捷键\n * bind hotkey/hotkeys,\n * @param combos 快捷键，格式如：['command + s'] 、['ctrl + shift + s'] 等\n * @param callback 回调函数\n * @param action\n * @returns\n */\nbind(\n    combos: string[] | string,\n    callback: IPublicTypeHotkeyCallback,\n    action?: string,\n  ): IPublicTypeDisposable;\n```\n相关 types\n- [IPublicTypeHotkeyCallback](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/hotkey-callback.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n\n## 使用示例\n### 基础示例\n```typescript\nhotkey.bind('command+s', (e) => {\n  e.preventDefault();\n  // command+s 快捷键按下时需要执行的逻辑\n});\n```\n\n### 同时绑定多个快捷键\n```typescript\nhotkey.bind(['command+s', 'command+c'], (e) => {\n  e.preventDefault();\n  // command+s 或者 command+c 快捷键按下时需要执行的逻辑\n});\n```\n\n### 保存快捷键配置\n```typescript\nimport {\n  hotkey,\n} from '@alilc/lowcode-engine';\n\nfunction saveSchema(schema) {\n  // 保存 schema 相关操作\n}\n\nconst saveSampleHotKey = (ctx: IPublicModelPluginContext) => {\n  return {\n    name: 'saveSample',\n    async init() {\n      hotkey.bind('command+s', (e) => {\n        e.preventDefault();\n        saveSchema();\n      });\n    },\n  };\n}\n\nsaveSampleHotKey.pluginName = 'saveSampleHotKey';\nplugins.register(saveSampleHotKey);\n```\n"
  },
  {
    "path": "docs/docs/api/index.md",
    "content": "---\ntitle: API 总览\nsidebar_position: 0\n---\n\n引擎提供的公开 API 分为`命名空间`和`模型`两类，其中`命名空间`用于聚合一大类的 API，`模型`为各 API 涉及到的对象模型。\n\n## 命名空间\n\n引擎直接提供以下几大类 API\n\n- skeleton 面板 API\n- material 物料 API\n- project 模型 API\n- simulator-host 模拟器 API\n- hotkey 快捷键 API\n- setters 设置器 API\n- event 事件 API\n- config 配置 API\n- common 通用 API\n- logger 日志 API\n- init 初始化 API\n\n## 模型\n以下模型通过前面的 API 以返回值等形式间接透出。\n\n- document-model 文档\n- node 节点\n- node-children 节点孩子\n- props 属性集\n- prop 属性\n- setting-field 设置属性\n- setting-top-entry 设置属性集\n- component-meta 物料元数据\n- selection 画布选中\n- detecting 画布 hover\n- history 操作历史\n- window 低代码设计器窗口模型\n- detecting 画布节点悬停模型\n- modal-nodes-manager 模态节点管理器模型\n- plugin-instance 插件实例\n- drop-location 拖拽放置位置模型\n\n\n## API 设计约定\n一些 API 设计约定：\n\n1. 所有 API 命名空间都按照 variables / functions / events 来组织\n2. 事件（events）的命名格式为：on[Will|Did]VerbNoun?，参考 [https://code.visualstudio.com/api/references/vscode-api#events](https://code.visualstudio.com/api/references/vscode-api#events)\n3. 基于 Disposable 模式，对于事件的绑定、快捷键的绑定函数，返回值则是解绑函数\n4. 对于属性的导出，统一用 .xxx 的 getter 模式，（尽量）不使用 .getXxx()\n\n## experimental\n\n说明此模块处于公测阶段, API 可能会发生改变."
  },
  {
    "path": "docs/docs/api/init.md",
    "content": "---\ntitle: init - 初始化 API\nsidebar_position: 0\n---\n\n> **@since** v1.0.0\n\n\n## 模块简介\n提供 init 等方法\n## 方法\n#### init\n初始化引擎\n\n**方法定义**\n```typescript\nfunction init(container?: Element, options?: IPublicTypeEngineOptions): void\n```\n\n[**初始化引擎配置参数列表**](./configOptions)\n\n\n## 使用示例\n```typescript\nimport { init } from '@alilc/lowcode-engine';\n\ninit(document.getElementById('engine'), {\n  enableCondition: false,\n});\n```\n\n### 默认打开移动端画布\n```typescript\nimport { init } from '@alilc/lowcode-engine';\n\ninit({\n  device: 'mobile',\n});\n```\n\n### 使用 utils 第三方工具扩展\n```json\nimport { init } from '@alilc/lowcode-engine';\n\ninit({\n  device: 'mobile',\n  appHelper: {\n    utils: {\n      xxx: () => {console.log('123')},\n    }\n  }\n});\n```\n\n在引擎中即可这样使用。\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01FWvu051OxAEYrHBy5_!!6000000001771-2-tps-3584-1796.png)\n"
  },
  {
    "path": "docs/docs/api/logger.md",
    "content": "---\ntitle: logger - 日志 API\nsidebar_position: 10\n---\n\n> **@types** [IPublicApiLogger](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/logger.ts)<br/>\n> **@since** v1.0.0\n\n\n## 模块简介\n引擎日志模块，可以按照 **日志级别 **和** 业务类型 **两个维度来定制日志。\n> 注：日志级别可以通过 url query 动态调整，详见下方[查看示例](#查看示例)。<br/>\n> 参考 [zen-logger](https://web.npm.alibaba-inc.com/package/zen-logger) 实现进行封装\n\n## 方法\n\n日志记录方法\n\n```typescript\n/**\n * debug info\n */\ndebug(...args: any | any[]): void;\n\n/**\n * normal info output\n */\ninfo(...args: any | any[]): void;\n\n/**\n * warning info output\n */\nwarn(...args: any | any[]): void;\n\n/**\n * error info output\n */\nerror(...args: any | any[]): void;\n\n/**\n * log info output\n */\nlog(...args: any | any[]): void;\n```\n\n## 输出示例\n\n```typescript\nimport { Logger } from '@alilc/lowcode-utils';\nconst logger = new Logger({ level: 'warn', bizName: 'myPlugin:moduleA' });\nlogger.log('Awesome Low-Code Engine');\n```\n\n## 查看示例\n\n开启查看方式：\n\n- 方式 1：所有 logger 创建时会有默认输出的 level, 默认为 warn , 即只展示 warn , error\n- 方式 2：url 上追加 __logConf__进行开启，示例如下\n\n```\nhttps://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn\n// 开启所有 bizName的 warn 和 error\n\nhttps://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=debug\n// 开启所有 bizName的 debug, log, info, warn 和 error\n\nhttps://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=log\n// 开启所有 bizName的 log, info, warn 和 error\n\nhttps://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn|*\n// 同 __logConf__=warn\n\nhttps://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn|bizName\n// 开启 bizName 的 debug, log, info, warn 和 error\n\nhttps://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn|partOfBizName\n// 开启 bizName like '%partOfBizName%' 的 debug, log, info, warn 和 error\n\n```\n"
  },
  {
    "path": "docs/docs/api/material.md",
    "content": "---\ntitle: material - 物料 API\nsidebar_position: 10\n---\n\n> **@types** [IPublicApiMaterial](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/material.ts)<br/>\n> **@since** v1.0.0\n\n\n## 模块简介\n负责物料相关的 API，包括资产包、设计器辅助层、物料元数据和物料元数据管道函数。\n\n## 变量\n### componentsMap\n获取组件 map 结构\n```typescript\n/**\n  * 获取组件 map 结构\n  * get map of components\n  */\nget componentsMap(): { [key: string]: IPublicTypeNpmInfo | ComponentType<any> | object } ;\n```\n相关类型：[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts)\n\n## 方法\n\n### 资产包\n#### setAssets\n设置「[资产包](/site/docs/specs/lowcode-spec#2-协议结构)」结构\n\n```typescript\n/**\n * 设置「资产包」结构\n * set data for Assets\n * @returns void\n */\nsetAssets(assets: IPublicTypeAssetsJson): void;\n```\n相关类型：[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts)\n\n\n**示例**\n直接在项目中引用 npm 包\n```javascript\nimport { material } from '@alilc/lowcode-engine';\nimport assets from '@alilc/mc-assets-<siteId>/assets.json';\n\nmaterial.setAssets(assets);\n```\n\n通过接口动态引入资产包\n```typescript\nimport { material, plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\n// 动态加载 assets\nplugins.register((ctx: IPublicModelPluginContext) => {\n  return {\n    name: 'ext-assets',\n    async init() {\n      try {\n        // 将下述链接替换为您的物料描述地址即可。\n        const res = await window.fetch('https://fusion.alicdn.com/assets/default@0.1.95/assets.json');\n        const assets = await res.text();\n        material.setAssets(assets);\n      } catch (err) {\n        console.error(err);\n      };\n    },\n  };\n}).catch(err => console.error(err));\n```\n\n#### getAssets\n获取「资产包」结构\n\n```typescript\n/**\n * 获取「资产包」结构\n * get AssetsJson data\n * @returns IPublicTypeAssetsJson\n */\ngetAssets(): IPublicTypeAssetsJson;\n```\n相关类型：[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts)\n\n\n**示例**\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n\nmaterial.getAssets();\n```\n\n#### loadIncrementalAssets\n加载增量的「资产包」结构，该增量包会与原有的合并\n\n```typescript\n/**\n * 加载增量的「资产包」结构，该增量包会与原有的合并\n * load Assets incrementally, and will merge this with exiting assets\n * @param incrementalAssets\n * @returns\n */\nloadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise<void>;\n```\n相关类型：[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts)\n\n**示例**\n```typescript\nimport { material } from '@alilc/lowcode-engine';\nimport assets1 from '@alilc/mc-assets-<siteId>/assets.json';\nimport assets2 from '@alilc/mc-assets-<siteId>/assets.json';\n\nmaterial.setAssets(assets1);\nmaterial.loadIncrementalAssets(assets2);\n```\n\n更新特定物料的描述文件\n\n```typescript\nimport { material } from '@alilc/lowcode-engine';\nmaterial.loadIncrementalAssets({\n  version: '',\n  components: [\n      {\n          \"componentName\": 'Button',\n          \"props\": [{ name: 'new', title: 'new', propType: 'string' }]\n      }\n  ],\n})\n```\n\n### 设计器辅助层\n#### addBuiltinComponentAction\n在设计器辅助层增加一个扩展 action\n\n```typescript\n/**\n * 在设计器辅助层增加一个扩展 action\n * add an action button in canvas context menu area\n * @param action\n */\naddBuiltinComponentAction(action: IPublicTypeComponentAction): void;\n```\n相关类型：[IPublicTypeComponentAction](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/component-action.ts)\n\n\n**示例**\n新增设计扩展位，并绑定事件\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n\nmaterial.addBuiltinComponentAction({\n  name: 'myIconName',\n  content: {\n      icon: () => 'x',\n      title: 'hover title',\n      action(node) {\n          console.log('myIconName 扩展位被点击');\n      }\n  },\n  important: true,\n  condition: true,\n});\n```\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01jDbN7B1KfWVzJ16tw_!!6000000001191-2-tps-230-198.png)\n\n#### removeBuiltinComponentAction\n移除设计器辅助层的指定 action\n\n```typescript\n/**\n * 移除设计器辅助层的指定 action\n * remove a builtin action button from canvas context menu area\n * @param name\n */\nremoveBuiltinComponentAction(name: string): void;\n```\n\n##### 内置设计器辅助 name\n\n- remove：删除\n- hide：隐藏\n- copy：复制\n- lock：锁定，不可编辑\n- unlock：解锁，可编辑\n\n**示例**\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n\nmaterial.removeBuiltinComponentAction('myIconName');\n```\n\n\n#### modifyBuiltinComponentAction\n修改已有的设计器辅助层的指定 action\n\n```typescript\n/**\n * 修改已有的设计器辅助层的指定 action\n * modify a builtin action button in canvas context menu area\n * @param actionName\n * @param handle\n */\nmodifyBuiltinComponentAction(\n    actionName: string,\n    handle: (action: IPublicTypeComponentAction) => void,\n  ): void;\n```\n相关类型：[IPublicTypeComponentAction](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/component-action.ts)\n\n\n##### 内置设计器辅助 name\n\n- remove：删除\n- hide：隐藏\n- copy：复制\n- lock：锁定，不可编辑\n- unlock：解锁，可编辑\n\n\n\n**示例**\n给原始的 remove 扩展时间添加执行前后的日志\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n\nmaterial.modifyBuiltinComponentAction('remove', (action) => {\n  const originAction = action.content.action;\n  action.content.action = (node) => {\n  \tconsole.log('before reomve!');\n    originAction(node);\n    console.log('after remove!');\n  }\n});\n```\n\n### 右键菜单项\n#### addContextMenuOption\n\n添加右键菜单项\n\n```typescript\n/**\n * 添加右键菜单项\n * @param action\n */\naddContextMenuOption(action: IPublicTypeContextMenuAction): void;\n```\n\n示例\n\n```typescript\nimport { IPublicEnumContextMenuType } from '@alilc/lowcode-types';\n\nmaterial.addContextMenuOption({\n  name: 'parentItem',\n  title: 'Parent Item',\n  condition: (nodes) => true,\n  items: [\n    {\n      name: 'childItem1',\n      title: 'Child Item 1',\n      action: (nodes) => console.log('Child Item 1 clicked', nodes),\n      condition: (nodes) => true\n    },\n    // 分割线\n    {\n      type: IPublicEnumContextMenuType.SEPARATOR\n      name: 'separator.1'\n    }\n    // 更多子菜单项...\n  ]\n});\n\n```\n\n#### removeContextMenuOption\n\n删除特定右键菜单项\n\n```typescript\n/**\n * 删除特定右键菜单项\n * @param name\n */\nremoveContextMenuOption(name: string): void;\n```\n\n#### adjustContextMenuLayout\n\n调整右键菜单项布局，每次调用都会覆盖之前注册的调整函数，只有最后注册的函数会被应用。\n\n```typescript\n/**\n * 调整右键菜单项布局\n * @param actions\n */\nadjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void;\n```\n\n**示例**\n\n通过 adjustContextMenuLayout 补充分割线\n\n```typescript\nmaterial.adjustContextMenuLayout((actions: IPublicTypeContextMenuAction) => {\n  const names = ['a', 'b'];\n  const newActions = [];\n  actions.forEach(d => {\n    newActions.push(d);\n    if (names.include(d.name)) {\n      newActions.push({ type: 'separator' })\n    }\n  });\n  return newActions\n})\n```\n\n### 物料元数据\n\n#### getComponentMeta\n获取指定名称的物料元数据\n\n```typescript\n/**\n * 获取指定名称的物料元数据\n * get component meta by component name\n * @param componentName\n * @returns\n */\ngetComponentMeta(componentName: string): IPublicModelComponentMeta | null;\n```\n相关类型：[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)\n\n**示例**\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n\nmaterial.getComponentMeta('Input');\n```\n\n#### getComponentMetasMap\n\n获取所有已注册的物料元数据\n\n```typescript\n  /**\n   * 获取所有已注册的物料元数据\n   * get map of all component metas\n   * @returns\n   */\n  getComponentMetasMap(): Map<string, IPublicModelComponentMeta>;\n```\n相关类型：[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)\n\n**示例**\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n\nmaterial.getComponentMetasMap();\n```\n\n#### refreshComponentMetasMap\n\n刷新 componentMetasMap，可触发模拟器里的 components 重新构建\n\n**@since v1.1.7**\n\n```typescript\n  refreshComponentMetasMap(): void;\n```\n\n### 物料元数据管道函数\n#### registerMetadataTransducer\n注册物料元数据管道函数，在物料信息初始化时执行。\n\n```typescript\n/**\n * 注册物料元数据管道函数，在物料信息初始化时执行。\n * register transducer to process component meta, which will be\n * excuted during component meta`s initialization\n * @param transducer\n * @param level\n * @param id\n */\nregisterMetadataTransducer(\n  transducer: IPublicTypeMetadataTransducer,\n  level?: number,\n  id?: string | undefined\n): void;\n```\n\n**示例**\n给每一个组件的配置添加高级配置面板，其中有一个是否渲染配置项\n```typescript\nimport { material } from '@alilc/lowcode-engine'\n\nfunction addonCombine(metadata: TransformedComponentMetadata) {\n  const { componentName, configure = {} } = metadata;\n  const advanceGroup = [];\n  const combined: FieldConfig[] = [];\n\n  advanceGroup.push({\n    name: getConvertedExtraKey('condition'),\n    title: { type: 'i18n', 'zh-CN': '是否渲染', 'en-US': 'Condition' },\n    defaultValue: true,\n    setter: [\n      {\n        componentName: 'BoolSetter',\n      },\n      {\n        componentName: 'VariableSetter',\n      },\n    ],\n    extraProps: {\n      display: 'block',\n    },\n  });\n\n  combined.push({\n    name: '#advanced',\n    title: { type: 'i18n', 'zh-CN': '高级', 'en-US': 'Advanced' },\n    items: advanceGroup,\n  });\n\n  return {\n    ...metadata,\n    configure: {\n      ...configure,\n      combined,\n    },\n  };\n}\n\nmaterial.registerMetadataTransducer(addonCombine, 1, 'parse-func');\n```\n\n删除高级 Tab\n\n```typescript\nimport { material } from '@alilc/lowcode-engine';\nimport { IPublicTypeFieldConfig } from '@alilc/lowcode-types';\n\nmaterial.registerMetadataTransducer((transducer) => {\n  const combined: IPublicTypeFieldConfig[] = [];\n\n  transducer.configure.combined?.forEach(d => {\n    if (d.name !== '#advanced') {\n      combined.push(d);\n    }\n  });\n\n  return {\n    ...transducer,\n    configure: {\n      ...transducer.configure,\n      combined,\n    }\n  };\n}, 111, 'parse-func');\n```\n\n#### getRegisteredMetadataTransducers\n获取所有物料元数据管道函数\n\n```typescript\n/**\n * 获取所有物料元数据管道函数\n * get all registered metadata transducers\n * @returns {IPublicTypeMetadataTransducer[]}\n */\ngetRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[];\n```\n\n**示例**\n```typescript\nimport { material } from '@alilc/lowcode-engine'\n\nmaterial.getRegisteredMetadataTransducers();\n```\n## 事件\n### onChangeAssets\n监听 assets 变化的事件\n\n```typescript\n/**\n * 监听 assets 变化的事件\n * add callback for assets changed event\n * @param fn\n */\nonChangeAssets(fn: () => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n**示例**\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n\nmaterial.onChangeAssets(() => {\n  console.log('asset changed');\n});\n```\n"
  },
  {
    "path": "docs/docs/api/model/_category_.json",
    "content": "{\n  \"label\": \"模型定义 Models\",\n  \"position\": 100,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/api/model/clipboard.md",
    "content": "---\ntitle: Clipboard\nsidebar_position: 14\n---\n\n> **@types** [IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)<br/>\n> **@since** v1.1.0\n\n## 方法\n\n### setData\n\n给剪贴板赋值\n\n```typescript\n/**\n * 给剪贴板赋值\n * set data to clipboard\n *\n * @param {*} data\n * @since v1.1.0\n */\nsetData(data: any): void;\n```\n\n### waitPasteData\n\n设置剪贴板数据设置的回调\n\n```typescript\n/**\n * 设置剪贴板数据设置的回调\n * set callback for clipboard provide paste data\n *\n * @param {KeyboardEvent} keyboardEvent\n * @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb\n * @since v1.1.0\n */\nwaitPasteData(\n    keyboardEvent: KeyboardEvent,\n    cb: (data: any, clipboardEvent: ClipboardEvent) => void,\n  ): void;\n```"
  },
  {
    "path": "docs/docs/api/model/component-meta.md",
    "content": "---\ntitle: ComponentMeta\nsidebar_position: 15\n---\n\n> **@types** [IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n组件元数据信息模型\n\n## 属性\n\n### componentName\n\n组件名\n\n`@type {string}`\n\n### isContainer\n\n是否是「容器型」组件\n\n`@type {boolean}`\n\n### isMinimalRenderUnit\n是否是最小渲染单元\n\n当组件需要重新渲染时：\n- 若为最小渲染单元，则只渲染当前组件，\n- 若不为最小渲染单元，则寻找到上层最近的最小渲染单元进行重新渲染，直至根节点。\n\n`@type {boolean}`\n\n### isModal\n\n是否为「模态框」组件\n\n`@type {boolean}`\n\n### configure\n\n获取用于设置面板显示用的配置\n\n`@type {IPublicTypeFieldConfig[]}`\n\n相关类型：[IPublicTypeFieldConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/field-config.ts)\n\n### title\n\n标题\n\n`@type {string | IPublicTypeI18nData | ReactElement}`\n\n相关类型：[IPublicTypeI18nData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/i18n-data.ts)\n\n### icon\n\n图标\n\n`@type {IPublicTypeIconType}`\n\n相关类型：[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/icon-type.ts)\n\n### npm\n\n组件 npm 信息\n\n`@type {IPublicTypeNpmInfo}`\n\n相关类型：[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts)\n\n### availableActions\n\n获取元数据\n\n`@type {IPublicTypeTransformedComponentMetadata}`\n\n相关类型：[IPublicTypeTransformedComponentMetadata](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/transformed-component-metadata.ts)\n\n### advanced\n\n组件元数据中高级配置部分\n\n`@type {IPublicTypeAdvanced}`\n\n相关类型：[IPublicTypeAdvanced](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/advanced.ts)\n\n## 方法\n\n### setNpm\n\n设置 npm 信息\n\n```typescript\n/**\n * 设置 npm 信息\n * set method for npm inforamtion\n * @param npm\n */\nsetNpm(npm: IPublicTypeNpmInfo): void;\n```\n\n相关类型：[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts)\n\n### getMetadata\n\n获取元数据\n\n```typescript\n/**\n * 获取元数据\n * get component metadata\n */\ngetMetadata(): IPublicTypeTransformedComponentMetadata;\n```\n\n相关类型：[IPublicTypeTransformedComponentMetadata](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/transformed-component-metadata.ts)\n\n### checkNestingUp\n\n检测当前对应节点是否可被放置在父节点中\n\n```typescript\n/**\n * 检测当前对应节点是否可被放置在父节点中\n * check if the current node could be placed in parent node\n * @param my 当前节点\n * @param parent 父节点\n */\ncheckNestingUp(my: IPublicModelNode | IPublicTypeNodeData, parent: any): boolean;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)\n\n\n### checkNestingDown\n\n检测目标节点是否可被放置在父节点中\n\n```typescript\n/**\n * 检测目标节点是否可被放置在父节点中\n * check if the target node(s) could be placed in current node\n * @param my 当前节点\n * @param parent 父节点\n */\ncheckNestingDown(\n    my: IPublicModelNode | IPublicTypeNodeData,\n    target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[],\n  ): boolean;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)\n- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n\n### refreshMetadata\n\n刷新元数据，会触发元数据的重新解析和刷新\n\n```typescript\n/**\n * 刷新元数据，会触发元数据的重新解析和刷新\n * refresh metadata\n */\nrefreshMetadata(): void;\n```\n"
  },
  {
    "path": "docs/docs/api/model/detecting.md",
    "content": "---\ntitle: Detecting\nsidebar_position: 6\n---\n> **@types** [IPublicModelDetecting](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/detecting.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n画布节点悬停模型\n\n## 属性\n\n### current\n\n当前 hover 的节点\n\n`@type {IPublicModelNode | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n**@since v1.0.16**\n\n### enable\n\n是否启用\n\n`@type {boolean}`\n\n\n## 方法\n### capture\n\nhover 指定节点\n\n```typescript\n/**\n * hover 指定节点\n * capture node with nodeId\n * @param id 节点 id\n */\ncapture(id: string): void;\n```\n\n### release\n\nhover 离开指定节点\n\n```typescript\n/**\n * hover 离开指定节点\n * release node with nodeId\n * @param id 节点 id\n */\nrelease(id: string): void;\n```\n\n### leave\n\n清空 hover 态\n\n```typescript\n/**\n * 清空 hover 态\n * clear all hover state\n */\nleave(): void;\n```\n\n## 事件\n### onDetectingChange\nhover 节点变化事件\n\n```typescript\n/**\n * hover 节点变化事件\n * set callback which will be called when hovering object changed.\n * @since v1.1.0\n */\nonDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n**@since v1.1.0**"
  },
  {
    "path": "docs/docs/api/model/document-model.md",
    "content": "---\ntitle: DocumentModel\nsidebar_position: 0\n---\n> **@types** [IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n文档模型\n\n## 属性\n\n### id\n\n唯一 ID\n\n`@type {string}`\n\n### selection\n\n画布节点选中区模型实例\n\n`@type {IPublicModelSelection}`\n\n相关章节：[节点选中区模型](./selection)\n\n相关类型：[IPublicModelSelection](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/selection.ts)\n\n### detecting\n\n画布节点 hover 区模型实例\n\n`@type {IPublicModelDetecting}`\n\n相关章节：[画布节点悬停模型](./detecting)\n\n相关类型：[IPublicModelDetecting](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/detecting.ts)\n\n### history\n\n操作历史模型实例\n\n`@type {IPublicModelHistory}`\n\n相关章节：[操作历史模型](./history)\n\n相关类型：[IPublicModelHistory](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/history.ts)\n\n### project\n\n获取当前文档模型所属的 project\n\n`@type {IPublicApiProject}`\n\n相关类型：[IPublicApiProject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/project.ts)\n\n### root\n\n获取文档的根节点\n\n`@type {IPublicModelNode | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### nodesMap\n\n获取文档下所有节点 Map, key 为 nodeId\n\n`@type {Map<string, IPublicModelNode>} `\n\n\n相关章节：[节点模型](./node)\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### modalNodesManager\n\n模态节点管理器\n\n`@type {IPublicModelModalNodesManager | null}`\n\n相关章节：[模态节点管理](./modal-nodes-manager)\n\n相关类型：[IPublicModelModalNodesManager](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/modal-nodes-manager.ts)\n\n### dropLocation\n\n文档的 dropLocation\n\n`@type {IPublicModelDropLocation | null}`\n\n\n相关类型：[IPublicModelDropLocation](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/drop-location.ts)\n\n**@since v1.1.0**\n\n## 方法\n### getNodeById\n\n根据 nodeId 返回 [Node](./node) 实例\n\n```typescript\n/**\n * 根据 nodeId 返回 Node 实例\n * get node by nodeId\n * @param nodeId\n * @returns\n */\ngetNodeById(nodeId: string): IPublicModelNode | null;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### importSchema\n\n导入 schema\n\n```typescript\n/**\n * 导入 schema\n * import schema data\n * @param schema\n */\nimportSchema(schema: IPublicTypeRootSchema): void;\n```\n\n相关类型：[IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)\n\n\n### exportSchema\n导出 schema\n\n```typescript\n/**\n * 导出 schema\n * export schema\n * @param stage\n * @returns\n */\nexportSchema(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined;\n```\n\n相关类型：\n- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)\n- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)\n\n### insertNode\n\n插入节点\n\n```typescript\n/**\n * 插入节点\n * insert a node\n */\ninsertNode(\n  parent: IPublicModelNode,\n  thing: IPublicModelNode,\n  at?: number | null | undefined,\n  copy?: boolean | undefined\n): IPublicModelNode | null;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### createNode\n\n创建一个节点\n\n```typescript\n/**\n * 创建一个节点\n * create a node\n * @param data\n * @returns\n */\ncreateNode(data: any): IPublicModelNode | null;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### removeNode\n\n移除指定节点/节点id\n\n```typescript\n/**\n * 移除指定节点/节点id\n * remove a node by node instance or nodeId\n * @param idOrNode\n */\nremoveNode(idOrNode: string | IPublicModelNode): void;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### checkNesting\n检查拖拽放置的目标节点是否可以放置该拖拽对象\n\n```typescript\n/**\n * 检查拖拽放置的目标节点是否可以放置该拖拽对象\n * check if dragOjbect can be put in this dragTarget\n * @param dropTarget 拖拽放置的目标节点\n * @param dragObject 拖拽的对象\n * @returns boolean 是否可以放置\n * @since v1.0.16\n */\ncheckNesting(\n  dropTarget: IPublicModelNode,\n  dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject\n): boolean;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeDragNodeObject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/drag-node-object.ts)\n- [IPublicTypeDragNodeDataObject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/drag-node-object-data.ts)\n\n**@since v1.0.16**\n\n### isDetectingNode\n判断是否当前节点处于被探测状态\n\n```typescript\n/**\n * 判断是否当前节点处于被探测状态\n * check is node being detected\n * @param node\n * @since v1.1.0\n */\nisDetectingNode(node: IPublicModelNode): boolean;\n```\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n**@since v1.1.0**\n\n\n## 事件\n### onAddNode\n\n当前 document 新增节点事件\n\n```typescript\n/**\n * 当前 document 新增节点事件\n * set callback for event on node is created for a document\n */\nonAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onMountNode\n\n当前 document 新增节点事件，此时节点已经挂载到 document 上\n\n```typescript\n/**\n * 当前 document 新增节点事件，此时节点已经挂载到 document 上\n * set callback for event on node is mounted to canvas\n */\nonMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onRemoveNode\n当前 document 删除节点事件\n\n```typescript\n/**\n * 当前 document 删除节点事件\n * set callback for event on node is removed\n */\nonRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n\n### onChangeDetecting\n\n当前 document 的 hover 变更事件\n\n```typescript\n/**\n * 当前 document 的 hover 变更事件\n *\n * set callback for event on detecting changed\n */\nonChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onChangeSelection\n\n当前 document 的选中变更事件\n\n```typescript\n/**\n * 当前 document 的选中变更事件\n * set callback for event on selection changed\n */\nonChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onChangeNodeVisible\n\n当前 document 的节点显隐状态变更事件\n\n```typescript\n/**\n * 当前 document 的节点显隐状态变更事件\n * set callback for event on visibility changed for certain node\n * @param fn\n */\nonChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable;\n```\n\n- 相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- 相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onChangeNodeChildren\n\n当前 document 的节点 children 变更事件\n\n```typescript\nonChangeNodeChildren(fn: (info?: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onChangeNodeProp\n当前 document 节点属性修改事件\n\n```typescript\nonChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onImportSchema\n当前 document 导入新的 schema 事件\n```typescript\n/**\n * import schema event\n * @param fn\n * @since v1.0.15\n */\nonImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable;\n```\n相关类型：\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)\n\n**@since v1.0.15**\n\n### onFocusNodeChanged\n设置聚焦节点变化的回调\n\n```typescript\n/**\n * 设置聚焦节点变化的回调\n * triggered focused node is set mannually from plugin\n * @param fn\n * @since v1.1.0\n */\nonFocusNodeChanged(\n  fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void,\n): IPublicTypeDisposable;\n```\n相关类型：\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n**@since v1.1.0**\n\n### onDropLocationChanged\n设置 DropLocation 变化的回调\n\n```typescript\n/**\n * 设置 DropLocation 变化的回调\n * triggered when drop location changed\n * @param fn\n * @since v1.1.0\n */\nonDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n**@since v1.1.0**"
  },
  {
    "path": "docs/docs/api/model/dragon.md",
    "content": "---\ntitle: Dragon\nsidebar_position: 99\n---\n> **@types** [IPublicModelDragon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/dragon.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n拖拽对象\n\n### 对应接口\n```typescript\nimport { IPublicModelDragon } from '@alilc/lowcode-types';\n```\n\n### 支持版本\n\n**@since** v1.1.0\n\n## 属性\n\n### dragging\n\n是否正在拖动\n\n```typescript\n/**\n * is dragging or not\n */\nget dragging(): boolean;\n```\n\n## 方法\n\n### onDragstart\n\n绑定 dragstart 事件\n\n```typescript\n/**\n * 绑定 dragstart 事件\n * bind a callback function which will be called on dragging start\n * @param func\n * @returns\n */\nonDragstart(func: (e: IPublicModelLocateEvent) => any): () => void;\n```\n\n### onDrag\n\n绑定 drag 事件\n```typescript\n/**\n * 绑定 drag 事件\n * bind a callback function which will be called on dragging\n * @param func\n * @returns\n */\nonDrag(func: (e: IPublicModelLocateEvent) => any): () => void;\n```\n\n### onDragend\n\n绑定 dragend 事件\n\n```typescript\n/**\n * 绑定 dragend 事件\n * bind a callback function which will be called on dragging end\n * @param func\n * @returns\n */\nonDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): () => void;\n```\n\n### from\n\n设置拖拽监听的区域 shell，以及自定义拖拽转换函数 boost\n\n```typescript\n/**\n * 设置拖拽监听的区域 shell，以及自定义拖拽转换函数 boost\n* set a html element as shell to dragon as monitoring target, and\n* set boost function which is used to transform a MouseEvent to type\n* IPublicTypeDragNodeDataObject.\n * @param shell 拖拽监听的区域\n * @param boost 拖拽转换函数\n */\nfrom(shell: Element, boost: (e: MouseEvent) => IPublicTypeDragNodeDataObject | null): any;\n```\n\n### boost\n\n发射拖拽对象\n```typescript\n/**\n * 发射拖拽对象\n * boost your dragObject for dragging(flying)\n *\n * @param dragObject 拖拽对象\n * @param boostEvent 拖拽初始时事件\n */\nboost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode): void;\n```\n\n### addSensor\n\n添加投放感应区\n\n```typescript\n/**\n * 添加投放感应区\n * add sensor area\n */\naddSensor(sensor: any): void;\n```\n\n### removeSensor\n\n移除投放感应\n\n```typescript\n/**\n * 移除投放感应\n * remove sensor area\n */\nremoveSensor(sensor: any): void;\n```"
  },
  {
    "path": "docs/docs/api/model/drop-location.md",
    "content": "---\ntitle: DropLocation\nsidebar_position: 13\n---\n\n> **@types** [IPublicModelDropLocation](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/drop-location.ts)<br/>\n> **@since** v1.1.0\n\n\n## 基本介绍\n\n拖拽放置位置模型\n\n## 属性\n\n### target\n\n拖拽放置位置目标\n\n`@type {IPublicModelNode | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### detail\n\n拖拽放置位置详情\n\n`@type {IPublicTypeLocationDetail}`\n\n相关类型：[IPublicTypeLocationDetail](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/location-detail.ts)\n\n### event\n\n拖拽放置位置对应的事件\n\n`@type {IPublicTypeLocationDetail}`\n\n相关类型：[IPublicModelLocateEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/location-event.ts)\n\n## 方法\n\n### clone\n\n获取一份当前对象的克隆\n\n```typescript\n/**\n * 获取一份当前对象的克隆\n * get a clone object of current dropLocation\n */\nclone(event: IPublicModelLocateEvent): IPublicModelDropLocation;\n```\n\n相关类型：[IPublicModelLocateEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/location-event.ts)"
  },
  {
    "path": "docs/docs/api/model/editor-view.md",
    "content": "---\ntitle: EditorView\nsidebar_position: 12\n---\n\n> **[@experimental](./#experimental)**<br/>\n> **@types** [IPublicModelEditorView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/editor-view.ts)<br/>\n> **@since** v1.1.7\n\n窗口编辑视图\n\n## 类型定义\n\n```\nimport { IPublicModelPluginContext } from \"./plugin-context\";\n\nexport interface IPublicModelEditorView extends IPublicModelPluginContext {};\n\n```\n\n相关类型定义: [IPublicModelPluginContext](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-context.ts)\n"
  },
  {
    "path": "docs/docs/api/model/history.md",
    "content": "---\ntitle: History\nsidebar_position: 5\n---\n> **@types** [IPublicModelHistory](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/history.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n操作历史记录模型\n\n## 方法\n### go\n\n历史记录跳转到指定位置\n\n```typescript\n/**\n * 历史记录跳转到指定位置\n * go to a specific history\n * @param cursor\n */\ngo(cursor: number): void;\n```\n\n### back\n\n历史记录后退\n\n```typescript\n/**\n * 历史记录后退\n * go backward in history\n */\nback(): void;\n```\n\n### forward\n\nforward()\n\n历史记录前进\n\n```typescript\n/**\n * 历史记录前进\n * go forward in history\n */\nforward(): void;\n```\n\n### savePoint\n\n保存当前状态\n\n```typescript\n/**\n * 保存当前状态\n * do save current change as a record in history\n */\nsavePoint(): void;\n```\n\n### isSavePoint\n\n当前是否是「保存点」，即是否有状态变更但未保存\n\n```typescript\n/**\n * 当前是否是「保存点」，即是否有状态变更但未保存\n * check if there is unsaved change for history\n */\nisSavePoint(): boolean;\n```\n\n### getState\n\n获取 state，判断当前是否为「可回退」、「可前进」的状态\n\n```typescript\n/**\n * 获取 state，判断当前是否为「可回退」、「可前进」的状态\n * get flags in number which indicat current change state\n *\n *  |    1     |     1    |    1     |\n *  | -------- | -------- | -------- |\n *  | modified | redoable | undoable |\n * eg:\n *  7 means : modified && redoable && undoable\n *  5 means : modified && undoable\n */\ngetState(): number;\n```\n\n## 事件\n### onChangeState\n\n监听 state 变更事件\n\n```typescript\n/**\n * 监听 state 变更事件\n * monitor on stateChange event\n * @param func\n */\nonChangeState(func: () => any): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onChangeCursor\n\n监听历史记录游标位置变更事件\n\n```typescript\n/**\n * 监听历史记录游标位置变更事件\n * monitor on cursorChange event\n * @param func\n */\nonChangeCursor(func: () => any): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)"
  },
  {
    "path": "docs/docs/api/model/modal-nodes-manager.md",
    "content": "---\ntitle: ModalNodesManager\nsidebar_position: 7\n---\n> **@types** [IPublicModelModalNodesManager](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/modal-nodes-manager.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n模态节点管理器模型\n\n## 方法\n\n### setNodes\n\n设置模态节点，触发内部事件\n\n```typescript\n/**\n * 设置模态节点，触发内部事件\n * set modal nodes, trigger internal events\n */\nsetNodes(): void;\n```\n\n### getModalNodes\n\n获取模态节点（们）\n\n```typescript\n/**\n * 获取模态节点（们）\n * get modal nodes\n */\ngetModalNodes(): IPublicModelNode[];\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### getVisibleModalNode\n\n获取当前可见的模态节点\n\n```typescript\n/**\n * 获取当前可见的模态节点\n * get current visible modal node\n */\ngetVisibleModalNode(): IPublicModelNode | null;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### hideModalNodes\n\n隐藏模态节点（们）\n\n```typescript\n/**\n * 隐藏模态节点（们）\n * hide modal nodes\n */\nhideModalNodes(): void;\n```\n\n### setVisible\n\n设置指定节点为可见态\n\n```typescript\n/**\n * 设置指定节点为可见态\n * set specific model node as visible\n * @param node IPublicModelNode\n */\nsetVisible(node: IPublicModelNode): void;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### setInvisible\n\n设置指定节点为不可见态\n\n```typescript\n/**\n * 设置指定节点为不可见态\n * set specific model node as invisible\n * @param node IPublicModelNode\n */\nsetInvisible(node: IPublicModelNode): void;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n"
  },
  {
    "path": "docs/docs/api/model/node-children.md",
    "content": "---\ntitle: NodeChildren\nsidebar_position: 2\n---\n> **@types** [IPublicModelNodeChildren](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node-children.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n节点孩子模型\n\n## 属性\n### owner\n\n返回当前 children 实例所属的节点实例\n\n`@type {IPublicModelNode | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### size\n\nchildren 内的节点实例数\n\n`@type {number}`\n\n\n### isEmptyNode\n\n是否为空\n\n`@type {boolean}`\n\n**@since v1.1.0**\n> v1.1.0 之前请使用 `isEmpty`\n\n### notEmptyNode\n\n是否不为空\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n## 方法\n### delete\n删除指定节点\n\n```typescript\n/**\n * 删除指定节点\n * delete the node\n * @param node\n */\ndelete(node: IPublicModelNode): boolean;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### insert\n\n插入一个节点\n\n```typescript\n/**\n * 插入一个节点\n * insert the node\n * @param node\n */\ninsert(node: IPublicModelNode): boolean;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### indexOf\n\n返回指定节点的下标\n\n```typescript\n/**\n * 返回指定节点的下标\n * get index of node in current children\n * @param node\n * @returns\n */\nindexOf(node: IPublicModelNode): number;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### splice\n\n类似数组 splice 操作\n\n```typescript\n/**\n * 类似数组 splice 操作\n * provide the same function with {Array.prototype.splice}\n * @param start\n * @param deleteCount\n * @param node\n */\nsplice(start: number, deleteCount: number, node?: IPublicModelNode): any;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### get\n\n返回指定下标的节点\n\n```typescript\n/**\n * 返回指定下标的节点\n * get node with index\n * @param index\n * @returns\n */\nget(index: number): IPublicModelNode | null;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### has\n\n是否包含指定节点\n\n```typescript\n/**\n * 是否包含指定节点\n * check if node exists in current children\n * @param node\n * @returns\n */\nhas(node: IPublicModelNode): boolean;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### forEach\n\n类似数组的 forEach\n\n```typescript\n/**\n * 类似数组的 forEach\n * provide the same function with {Array.prototype.forEach}\n * @param fn\n */\nforEach(fn: (node: IPublicModelNode, index: number) => void): void;\n\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### reverse\n\n类似数组的 reverse\n\n```typescript\n/**\n * 类似数组的 reverse\n * provide the same function with {Array.prototype.reverse}\n */\nreverse(): IPublicModelNode[];\n\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### map\n\n类似数组的 map\n\n```typescript\n/**\n * 类似数组的 map\n * provide the same function with {Array.prototype.map}\n * @param fn\n */\nmap<T>(fn: (node: IPublicModelNode, index: number) => T[]): any[] | null;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### every\n\n类似数组的 every\n\n```typescript\n/**\n * 类似数组的 every\n * provide the same function with {Array.prototype.every}\n * @param fn\n */\nevery(fn: (node: IPublicModelNode, index: number) => boolean): boolean;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### some\n\n类似数组的 some\n\n```typescript\n/**\n * 类似数组的 some\n * provide the same function with {Array.prototype.some}\n * @param fn\n */\nsome(fn: (node: IPublicModelNode, index: number) => boolean): boolean;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### filter\n\n类似数组的 filter\n\n```typescript\n/**\n * 类似数组的 filter\n * provide the same function with {Array.prototype.filter}\n * @param fn\n */\nfilter(fn: (node: IPublicModelNode, index: number) => boolean): any;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### find\n\n类似数组的 find\n\n```typescript\n/**\n * 类似数组的 find\n * provide the same function with {Array.prototype.find}\n * @param fn\n */\nfind(fn: (node: IPublicModelNode, index: number) => boolean): IPublicModelNode | null;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### reduce\n\n类似数组的 reduce\n\n```typescript\n/**\n * 类似数组的 reduce\n * provide the same function with {Array.prototype.reduce}\n * @param fn\n */\nreduce(fn: (acc: any, cur: IPublicModelNode) => any, initialValue: any): void;\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n### importSchema\n\n导入 schema\n\n```typescript\n/**\n * 导入 schema\n * import schema\n * @param data\n */\nimportSchema(data?: IPublicTypeNodeData | IPublicTypeNodeData[]): void;\n```\n\n相关类型：[IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)\n\n\n### exportSchema\n导出 schema\n\n```typescript\n/**\n * 导出 schema\n * export schema\n * @param stage\n */\nexportSchema(stage: IPublicEnumTransformStage): IPublicTypeNodeSchema;\n```\n\n相关类型：\n- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)\n- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n\n### mergeChildren\n\n执行新增、删除、排序等操作\n\n```typescript\n/**\n * 执行新增、删除、排序等操作\n * excute remove/add/sort operations\n * @param remover\n * @param adder\n * @param sorter\n */\nmergeChildren(\n  remover: (node: IPublicModelNode, idx: number) => boolean,\n  adder: (children: IPublicModelNode[]) => IPublicTypeNodeData[] | null,\n  sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number\n): any;\n```\n\n相关类型：\n- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)\n"
  },
  {
    "path": "docs/docs/api/model/node.md",
    "content": "---\ntitle: Node\nsidebar_position: 1\n---\n> **@types** [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n节点模型\n\n## 属性\n### id\n\n节点 id\n\n`@type {string}`\n\n### title\n\n节点标题\n\n`@type {string | IPublicTypeI18nData | ReactElement}`\n\n相关类型：[IPublicTypeI18nData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/i18n-data.ts)\n\n### isContainerNode\n\n是否为「容器型」节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n> v1.1.0 之前请使用 `isContainer`\n\n### isRootNode\n\n是否为根节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isRoot`\n\n### isEmptyNode\n\n是否为空节点（无 children 或者 children 为空）\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isEmpty`\n\n### isPageNode\n\n是否为 Page 节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isPage`\n\n### isComponentNode\n\n是否为 Component 节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isComponent`\n\n### isModalNode\n\n是否为「模态框」节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isModal`\n\n### isSlotNode\n\n是否为插槽节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isSlot`\n\n### isParentalNode\n\n是否为父类/分支节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isParental`\n\n### isLeafNode\n\n是否为叶子节点\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.1.0 之前请使用 `isLeaf`\n\n### isLocked\n\n获取当前节点的锁定状态\n\n**@since v1.0.16**\n\n### isRGLContainerNode\n设置为磁贴布局节点，使用方式可参考：[磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw)\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n> v1.0.16 - v1.1.0 请使用 `isRGLContainer`\n\n### index\n\n下标\n\n`@type {number}`\n\n### icon\n\n图标\n\n`@type {IPublicTypeIconType}`\n\n相关类型：[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/icon-type.ts)\n\n### zLevel\n\n节点所在树的层级深度，根节点深度为 0\n\n`@type {number}`\n\n### componentName\n\n节点 componentName\n\n`@type {string}`\n\n### componentMeta\n\n节点的物料元数据\n\n`@type {IPublicModelComponentMeta | null}`\n\n相关类型：[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)\n\n\n### document\n\n获取节点所属的[文档模型](./document-model)对象\n\n`@type {IPublicModelDocumentModel | null}`\n\n相关类型：[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)\n\n### prevSibling\n\n获取当前节点的前一个兄弟节点\n\n`@type {IPublicModelNode | null}`\n\n### nextSibling\n\n获取当前节点的后一个兄弟节点\n\n`@type {IPublicModelNode | null}`\n\n### parent\n\n获取当前节点的父亲节点\n\n`@type {IPublicModelNode | null}`\n\n### children\n\n获取当前节点的孩子节点模型\n\n`@type {IPublicModelNodeChildren | null}`\n\n相关类型：[IPublicModelNodeChildren](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node-children.ts)\n\n### slots\n\n节点上挂载的插槽节点们\n\n`@type {IPublicModelNode[]}`\n\n### slotFor\n\n当前节点为插槽节点时，返回节点对应的属性实例\n\n`@type {IPublicModelProp | null}`\n\n相关类型：[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)\n\n### props\n\n返回节点的属性集\n\n`@type {IPublicModelProps | null}`\n\n相关类型：[IPublicModelProps](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/props.ts)\n\n\n### propsData\n\n返回节点的属性集值\n\n`@type {IPublicTypePropsMap | IPublicTypePropsList | null}`\n\n相关类型：\n- [IPublicTypePropsMap](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-map.ts)\n- [IPublicTypePropsList](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-list.ts)\n\n### conditionGroup\n\n获取条件组\n\n`@type {IPublicModelExclusiveGroup | null}`\n\n相关类型：[IPublicModelExclusiveGroup](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/exclusive-group.ts)\n\n**@since v1.1.0**\n\n### schema\n\n获取符合搭建协议 - 节点 schema 结构\n\n`@type {IPublicTypeNodeSchema | null}`\n\n相关类型：[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n### settingEntry\n\n获取对应的 setting entry\n\n`@type {IPublicModelSettingTopEntry}`\n\n相关章节：[设置器顶层操作对象](./setting-top-entry)\n\n相关类型：[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)\n\n### visible\n当前节点是否可见\n\n`@type {boolean}`\n\n**@since v1.1.0**\n\n## 方法\n\n### getRect\n\n返回节点的尺寸、位置信息\n\n```typescript\n/**\n * 返回节点的尺寸、位置信息\n * get rect information for this node\n */\ngetRect(): DOMRect | null;\n```\n\n### hasSlots\n\n是否有挂载插槽节点\n\n```typescript\n/**\n * 是否有挂载插槽节点\n * check if current node has slots\n */\nhasSlots(): boolean;\n```\n\n### hasCondition\n\n是否设定了渲染条件\n\n```typescript\n/**\n * 是否设定了渲染条件\n * check if current node has condition value set\n */\nhasCondition(): boolean;\n```\n\n### hasLoop\n\n是否设定了循环数据\n\n```typescript\n/**\n * 是否设定了循环数据\n * check if loop is set for this node\n */\nhasLoop(): boolean;\n```\n\n### getProp\n\n获取指定 path 的属性模型实例\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例\n * get prop by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n */\ngetProp(path: string, createIfNone: boolean): IPublicModelProp | null;\n```\n\n相关类型：[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)\n\n### getPropValue\n\n获取指定 path 的属性模型实例值\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例值\n * get prop value by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n */\ngetPropValue(path: string): any;\n```\n\n### getExtraProp\n\n获取指定 path 的属性模型实例，注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例，\n *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n *\n * get extra prop by path, an extra prop means a prop not exists in the `props`\n * but as siblint of the `props`\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n * @param createIfNone 当没有属性的时候，是否创建一个属性\n */\ngetExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null;\n```\n\n相关类型：[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)\n\n### getExtraPropValue\n\n获取指定 path 的属性模型实例，注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例，\n *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n *\n * get extra prop value by path, an extra prop means a prop not exists in the `props`\n * but as siblint of the `props`\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n * @returns\n */\ngetExtraPropValue(path: string): any;\n```\n\n### setPropValue\n\nsetPropValue(path: string, value: CompositeValue)\n\n设置指定 path 的属性模型实例值\n\n```typescript\n/**\n * 设置指定 path 的属性模型实例值\n * set value for prop with path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n * @param value 值\n */\nsetPropValue(path: string, value: IPublicTypeCompositeValue): void;\n```\n\n相关类型：[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)\n\n\n### setExtraPropValue\n\n设置指定 path 的属性模型实例值\n\n```typescript\n/**\n * 设置指定 path 的属性模型实例值\n * set value for extra prop with path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n * @param value 值\n */\nsetExtraPropValue(path: string, value: IPublicTypeCompositeValue): void;\n```\n\n相关类型：[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)\n\n### importSchema\n\n导入节点数据\n\n```typescript\n/**\n * 导入节点数据\n * import node schema\n * @param data\n */\nimportSchema(data: IPublicTypeNodeSchema): void;\n```\n\n相关类型：[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n### exportSchema\n\n导出节点数据\n\n```typescript\n/**\n * 导出节点数据\n * export schema from this node\n * @param stage\n * @param options\n */\nexportSchema(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema;\n```\n\n相关类型：\n- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)\n- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n### insertBefore\n\n在指定位置之前插入一个节点\n\n```typescript\n/**\n * 在指定位置之前插入一个节点\n * insert a node befor current node\n * @param node\n * @param ref\n * @param useMutator\n */\ninsertBefore(\n    node: IPublicModelNode,\n    ref?: IPublicModelNode | undefined,\n    useMutator?: boolean,\n  ): void;\n```\n\n### insertAfter\n\n在指定位置之后插入一个节点\n\n```typescript\n/**\n * 在指定位置之后插入一个节点\n * insert a node after this node\n * @param node\n * @param ref\n * @param useMutator\n */\ninsertAfter(\n    node: IPublicModelNode,\n    ref?: IPublicModelNode | undefined,\n    useMutator?: boolean,\n  ): void;\n```\n\n### replaceChild\n\n替换指定子节点\n\n```typescript\n/**\n * 替换指定子节点\n * replace a child node with data provided\n * @param node 待替换的子节点\n * @param data 用作替换的节点对象或者节点描述\n * @returns\n */\nreplaceChild(node: IPublicModelNode, data: any): IPublicModelNode | null;\n```\n\n### replaceWith\n\n将当前节点替换成指定节点描述\n\n```typescript\n/**\n * 将当前节点替换成指定节点描述\n * replace current node with a new node schema\n * @param schema\n */\nreplaceWith(schema: IPublicTypeNodeSchema): any;\n```\n\n相关类型：[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n### select\n\n选中当前节点实例\n\n```typescript\n/**\n * 选中当前节点实例\n * select current node\n */\nselect(): void;\n```\n\n### hover\n\n设置悬停态\n\n```typescript\n/**\n * 设置悬停态\n * set hover value for current node\n * @param flag\n */\nhover(flag: boolean): void;\n```\n\n### lock\n设置节点锁定状态\n\n```typescript\n/**\n * 设置节点锁定状态\n * set lock value for current node\n * @param flag\n * @since v1.0.16\n */\nlock(flag?: boolean): void;\n```\n\n**@since v1.0.16**\n\n### remove\n\n删除当前节点实例\n\n```typescript\n/**\n * 删除当前节点实例\n * remove current node\n */\nremove(): void;\n```\n\n### mergeChildren\n\n执行新增、删除、排序等操作\n\n```typescript\n/**\n * 执行新增、删除、排序等操作\n * excute remove/add/sort operations on node`s children\n *\n * @since v1.1.0\n */\nmergeChildren(\n  remover: (node: IPublicModelNode, idx: number) => boolean,\n  adder: (children: IPublicModelNode[]) => any,\n  sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number\n): any;\n```\n\n**@since v1.1.0**\n\n### contains\n\n当前节点是否包含某子节点\n\n```typescript\n/**\n * 当前节点是否包含某子节点\n * check if current node contains another node as a child\n * @param node\n * @since v1.1.0\n */\ncontains(node: IPublicModelNode): boolean;\n```\n\n**@since v1.1.0**\n\n### canPerformAction\n\n是否可执行某 action\n\n```typescript\n/**\n * 是否可执行某 action\n * check if current node can perform certain aciton with actionName\n * @param actionName action 名字\n * @since v1.1.0\n */\ncanPerformAction(actionName: string): boolean;\n```\n\n**@since v1.1.0**\n\n### isConditionalVisible\n\n获取该节点的 ConditionalVisible 值\n\n```typescript\n/**\n * 获取该节点的 ConditionalVisible 值\n * check if current node ConditionalVisible\n * @since v1.1.0\n */\nisConditionalVisible(): boolean | undefined;\n```\n\n**@since v1.1.0**\n\n### setConditionalVisible\n设置该节点的 ConditionalVisible 为 true\n\n```typescript\n/**\n * 设置该节点的 ConditionalVisible 为 true\n * make this node as conditionalVisible === true\n * @since v1.1.0\n */\nsetConditionalVisible(): void;\n```\n\n**@since v1.1.0**\n\n### getDOMNode\n获取节点实例对应的 dom 节点\n\n```typescript\n/**\n * 获取节点实例对应的 dom 节点\n */\ngetDOMNode(): HTMLElement;\n\n```\n\n### getRGL\n\n获取磁贴相关信息\n\n```typescript\n/**\n * 获取磁贴相关信息\n */\ngetRGL(): {\n  isContainerNode: boolean;\n  isEmptyNode: boolean;\n  isRGLContainerNode: boolean;\n  isRGLNode: boolean;\n  isRGL: boolean;\n  rglNode: IPublicModelNode | null;\n}\n```"
  },
  {
    "path": "docs/docs/api/model/plugin-instance.md",
    "content": "---\ntitle: PluginInstance\nsidebar_position: 12\n---\n\n> **@types** [IPublicModelPluginInstance](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-instance.ts)<br/>\n> **@since** v1.1.0\n\n\n## 基本介绍\n\n插件实例\n\n## 属性\n\n### pluginName\n\n插件名字\n\n`@type {string}`\n\n### dep\n\n插件依赖\n\n`@type {string[]}`\n\n### disabled\n\n插件是否禁用\n\n`@type {boolean}`\n\n### meta\n\n插件 meta 信息\n\n`@type {IPublicTypePluginMeta}`\n\n相关类型：[IPublicTypePluginMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-meta.ts)\n"
  },
  {
    "path": "docs/docs/api/model/prop.md",
    "content": "---\ntitle: Prop\nsidebar_position: 3\n---\n> **@types** [IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n属性模型\n\n## 属性\n\n### id\n\nid\n\n`@type {string}`\n\n### key\n\nkey 值\n\n`@type {string | number | undefined}`\n\n### path\n\n返回当前 prop 的路径\n\n`@type {string[]}`\n\n### node\n\n返回所属的节点实例\n\n`@type {IPublicModelNode | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### slotNode\n\n当本 prop 代表一个 Slot 时，返回对应的 slotNode\n\n`@type {IPublicModelNode | undefined | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n\n## 方法\n\n### setValue\n\n设置值\n\n```typescript\n/**\n * 设置值\n * set value for this prop\n * @param val\n */\nsetValue(val: IPublicTypeCompositeValue): void;\n```\n\n相关类型：[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)\n\n### getValue\n\n获取值\n\n```typescript\n/**\n * 获取值\n * get value of this prop\n */\ngetValue(): any;\n```\n\n### remove\n\n移除值\n\n```typescript\n/**\n * 移除值\n * remove value of this prop\n * @since v1.0.16\n */\nremove(): void;\n```\n\n**@since v1.0.16**\n\n### exportSchema\n\n导出值\n\n```typescript\n/**\n * 导出值\n * export schema\n * @param stage\n */\nexportSchema(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue;\n```\n\n相关类型：\n- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)\n- [IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)"
  },
  {
    "path": "docs/docs/api/model/props.md",
    "content": "---\ntitle: Props\nsidebar_position: 4\n---\n> **@types** [IPublicModelProps](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/props.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n属性集模型\n\n## 属性\n### id\n\nid\n\n`@type {string}`\n\n\n### path\n\n返回当前 props 的路径\n\n`@type {string[]}`\n\n\n### node\n\n返回当前属性集所属的节点实例\n\n`@type {IPublicModelNode | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n## 方法\n### getProp\n\n获取指定 path 的属性模型实例\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例\n * get prop by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n */\ngetProp(path: string): IPublicModelProp | null;\n```\n\n相关类型：[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)\n\n### getPropValue\n\n获取指定 path 的属性模型实例值\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例值\n * get value of prop by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n */\ngetPropValue(path: string): any;\n```\n\n### getExtraProp\n\n获取指定 path 的属性模型实例，注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例，\n *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n * get extra prop by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n */\ngetExtraProp(path: string): IPublicModelProp | null;\n```\n\n相关类型：[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)\n\n### getExtraPropValue\n\n获取指定 path 的属性模型实例值，注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n\n```typescript\n/**\n * 获取指定 path 的属性模型实例值\n *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n * get value of extra prop by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n */\ngetExtraPropValue(path: string): any;\n```\n\n### setPropValue\n\n设置指定 path 的属性模型实例值\n\n```typescript\n/**\n * 设置指定 path 的属性模型实例值\n * set value of prop by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n * @param value 值\n */\nsetPropValue(path: string, value: IPublicTypeCompositeValue): void;\n```\n\n相关类型：[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)\n\n### setExtraPropValue\n\n设置指定 path 的属性模型实例值\n\n```typescript\n/**\n * 设置指定 path 的属性模型实例值\n * set value of extra prop by path\n * @param path 属性路径，支持 a / a.b / a.0 等格式\n * @param value 值\n */\nsetExtraPropValue(path: string, value: IPublicTypeCompositeValue): void;\n```\n\n相关类型：[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)\n\n\n### has\n\n当前 props 是否包含某 prop\n\n```typescript\n/**\n * 当前 props 是否包含某 prop\n * check if the specified key is existing or not.\n * @param key\n * @since v1.1.0\n */\nhas(key: string): boolean;\n```\n\n**@since v1.1.0**\n\n### add\n\n添加一个 prop\n\n```typescript\n/**\n * 添加一个 prop\n * add a key with given value\n * @param value\n * @param key\n * @since v1.1.0\n */\nadd(value: IPublicTypeCompositeValue, key?: string | number | undefined): any;\n```\n\n相关类型：[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)\n\n**@since v1.1.0**"
  },
  {
    "path": "docs/docs/api/model/resource.md",
    "content": "---\ntitle: Resource\nsidebar_position: 13\n---\n\n> **[@experimental](./#experimental)**<br/>\n> **@types** [IPublicModelResource](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource.ts)<br/>\n> **@since** v1.1.0\n\n## 属性\n\n### title\n\n资源标题\n\n`@type {string}`\n\n### id\n\n资源 id\n\n`@type {string}`\n\n### name\n\n资源名字\n\n`@type {string}`\n\n### type\n\n资源类型\n\n`@type {string}`\n\n### category\n\n资源分类\n\n`@type {string}`\n\n### icon\n\n资源 icon\n\n`@type {ReactElement}`\n\n### options\n\n资源配置信息\n\n`@type {Object}`\n\n### config\n\n资源配置信息\n\n`@type {Object}`"
  },
  {
    "path": "docs/docs/api/model/selection.md",
    "content": "---\ntitle: Selection\nsidebar_position: 6\n---\n> **@types** [IPublicModelSelection](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/selection.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n画布节点选中模型\n\n## 属性\n### selected\n\n返回选中的节点 id\n\n`@type {string[]}`\n\n### node\n返回选中的节点（如多个节点只返回第一个）\n\n`@type {IPublicModelNode | null}`\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n**@since v1.1.0**\n\n## 方法\n### select\n\n选中指定节点（覆盖方式）\n\n```typescript\n/**\n* 选中指定节点（覆盖方式）\n* select node with id, this will override current selection\n* @param id\n*/\nselect(id: string): void;\n```\n\n### selectAll\n\n批量选中指定节点们\n\n```typescript\n/**\n* 批量选中指定节点们\n* select node with ids, this will override current selection\n*\n* @param ids\n*/\nselectAll(ids: string[]): void;\n```\n\n### remove\n\n**取消选中**选中的指定节点，不会删除组件\n\n```typescript\n/**\n* 移除选中的指定节点\n* remove node from selection with node id\n* @param id\n*/\nremove(id: string): void;\n```\n\n### clear\n\n**取消选中**所有选中节点，不会删除组件\n\n```typescript\n/**\n* 清除所有选中节点\n* clear current selection\n*/\nclear(): void;\n```\n\n### has\n\n判断是否选中了指定节点\n\n```typescript\n/**\n* 判断是否选中了指定节点\n* check if node with specific id is selected\n* @param id\n*/\nhas(id: string): boolean;\n```\n\n### add\n\n选中指定节点（增量方式）\n\n```typescript\n/**\n* 选中指定节点（增量方式）\n* add node with specific id to selection\n* @param id\n*/\nadd(id: string): void;\n```\n\n### getNodes\n\n获取选中的节点实例\n\n```typescript\n/**\n* 获取选中的节点实例\n* get selected nodes\n*/\ngetNodes(): IPublicModelNode[];\n```\n\n相关类型：[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)\n\n### getTopNodes\n获取选区的顶层节点\n例如选中的节点为：\n\n- DivA\n   - ChildrenA\n- DivB\n\ngetNodes 返回的是 [DivA、ChildrenA、DivB]，getTopNodes 返回的是 [DivA、DivB]，其中 ChildrenA 由于是二层节点，getTopNodes 不会返回\n\n```typescript\n/**\n* 获取选区的顶层节点\n* get seleted top nodes\n* for example:\n*  getNodes() returns [A, subA, B], then\n*  getTopNodes() will return [A, B], subA will be removed\n* @since v1.0.16\n*/\ngetTopNodes(includeRoot?: boolean): IPublicModelNode[];\n```\n\n**@since v1.0.16**\n\n## 事件\n### onSelectionChange\n\n注册 selection 变化事件回调\n\n```typescript\n/**\n* 注册 selection 变化事件回调\n* set callback which will be called when selection is changed\n* @since v1.1.0\n*/\nonSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n**@since v1.1.0**"
  },
  {
    "path": "docs/docs/api/model/setting-field.md",
    "content": "---\ntitle: SettingField\nsidebar_position: 6\n---\n> **@types** [IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)<br/>\n\n## 基本介绍\n\nsetter 设置器操作对象\n\n## 属性\n\n#### isGroup\n\n获取设置属性的 isGroup\n\n`@type {boolean}`\n\n\n#### id\n\n获取设置属性的 id\n\n`@type {string}`\n\n#### name\n\n获取设置属性的 name\n\n`@type {string | number | undefined}`\n\n#### key\n\n获取设置属性的 key\n\n`@type {string | number | undefined}`\n\n#### path\n\n获取设置属性的 path\n\n`@type {(string | number)[]}`\n\n#### title\n\n获取设置属性的 title\n\n`@type {string}`\n\n#### setter\n\n获取设置属性的 setter\n\n`@type {IPublicTypeSetterType | null}`\n\n#### expanded\n\n获取设置属性的 expanded\n\n`@type {boolean}`\n\n#### extraProps\n\n获取设置属性的 extraProps\n\n`@type {IPublicTypeFieldExtraProps}`\n\n#### props\n\n`@type {IPublicModelSettingTopEntry}`\n\n相关章节：[设置器顶层操作对象](./setting-top-entry)\n\n相关类型：[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)\n\n#### node\n\n获取设置属性对应的节点实例\n\n`@type {IPublicModelNode | null}`\n\n\n#### parent\n\n获取设置属性的父设置属性\n\n`@type {IPublicModelSettingTopEntry | IPublicModelSettingField}`\n\n相关章节：[设置器顶层操作对象](./setting-top-entry)\n\n相关类型：[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)\n\n#### top\n\n获取顶级设置属性\n\n`@type {IPublicModelSettingTopEntry}`\n\n相关章节：[设置器顶层操作对象](./setting-top-entry)\n\n相关类型：[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)\n\n#### isSettingField\n\n是否是 SettingField 实例\n\n`@type {boolean}`\n\n#### componentMeta\n\n`@type {IPublicModelComponentMeta}`\n\n相关类型：[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)\n\n#### items\n\n获取设置属性的 items\n\n`@type {Array<IPublicModelSettingField | IPublicTypeCustomView>}`\n\n相关类型：[IPublicTypeCustomView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/custom-view.ts)\n\n## 方法\n\n#### setKey\n\n设置 key 值\n\n```\n/**\n  * 设置 key 值\n  * @param key\n  */\nsetKey(key: string | number): void;\n```\n\n#### setValue\n\n设置值\n\n```\n/**\n  * 设置值\n  * @param val 值\n  */\nsetValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void;\n```\n\n相关类型：\n- [IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)\n- [IPublicTypeSetValueOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/set-value-options.ts)\n\n#### setPropValue\n\n设置子级属性值\n\n```\n/**\n  * 设置子级属性值\n  * @param propName 子属性名\n  * @param value 值\n  */\nsetPropValue(propName: string | number, value: any): void;\n```\n\n#### clearPropValue\n\n清空指定属性值\n\n```\n/**\n  * 清空指定属性值\n  * @param propName\n  */\nclearPropValue(propName: string | number): void;\n```\n\n#### getDefaultValue\n\n获取配置的默认值\n\n```\n/**\n  * 获取配置的默认值\n  * @returns\n  */\ngetDefaultValue(): any;\n```\n\n#### getValue\n\n获取值\n\n```\n/**\n  * 获取值\n  * @returns\n  */\ngetValue(): any;\n```\n\n#### getPropValue\n\n获取子级属性值\n\n```\n/**\n  * 获取子级属性值\n  * @param propName 子属性名\n  * @returns\n  */\ngetPropValue(propName: string | number): any;\n```\n\n#### getExtraPropValue\n\n获取顶层附属属性值\n\n```\n/**\n  * 获取顶层附属属性值\n  */\ngetExtraPropValue(propName: string): any;\n```\n\n#### setExtraPropValue\n\n设置顶层附属属性值\n\n```\n/**\n  * 设置顶层附属属性值\n  */\nsetExtraPropValue(propName: string, value: any): void;\n```\n\n#### getProps\n\n获取设置属性集\n\n```\n/**\n  * 获取设置属性集\n  * @returns\n  */\ngetProps(): IPublicModelSettingTopEntry;\n```\n\n相关章节：[设置器顶层操作对象](./setting-top-entry)\n\n相关类型：[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)\n\n#### isUseVariable\n\n是否绑定了变量\n\n```\n/**\n  * 是否绑定了变量\n  * @returns\n  */\nisUseVariable(): boolean;\n```\n\n#### setUseVariable\n\n设置绑定变量\n\n```\n/**\n  * 设置绑定变量\n  * @param flag\n  */\nsetUseVariable(flag: boolean): void;\n```\n\n#### createField\n\n创建一个设置 field 实例\n\n```\n/**\n  * 创建一个设置 field 实例\n  * @param config\n  * @returns\n  */\ncreateField(config: IPublicTypeFieldConfig): IPublicModelSettingField;\n```\n\n相关类型：[IPublicTypeFieldConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/field-config.ts)\n\n#### getMockOrValue\n\n获取值，当为变量时，返回 mock\n\n```\n/**\n  * 获取值，当为变量时，返回 mock\n  * @returns\n  */\ngetMockOrValue(): any;\n\n```\n\n#### purge\n\n销毁当前 field 实例\n\n```\n/**\n  * 销毁当前 field 实例\n  */\npurge(): void;\n```\n\n#### remove\n\n移除当前 field 实例\n\n```\n/**\n  * 移除当前 field 实例\n  */\nremove(): void;\n```\n\n## 事件\n\n#### onEffect\n\n设置 autorun\n\n```\n/**\n  * 设置 autorun\n  * @param action\n  * @returns\n  */\nonEffect(action: () => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)"
  },
  {
    "path": "docs/docs/api/model/setting-top-entry.md",
    "content": "---\ntitle: SettingTopEntry\nsidebar_position: 6\n---\n> **@types** [IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)<br/>\n\n## 基本介绍\n\nsetter 设置器顶层操作对象\n\n## 属性\n\n#### node\n\n返回所属的节点实例\n\n`@type {IPublicModelNode | null}`\n\n## 方法\n\n#### get\n\n获取子级属性对象\n\n```\n/**\n  * 获取子级属性对象\n  * @param propName\n  * @returns\n  */\nget(propName: string | number): IPublicModelSettingField | null;\n```\n相关章节：[设置器操作对象](./setting-field)\n\n相关类型：[IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)\n\n\n#### getPropValue\n\n获取指定 propName 的值\n\n```\n/**\n  * 获取指定 propName 的值\n  * @param propName\n  * @returns\n  */\ngetPropValue(propName: string | number): any;\n```\n\n#### setPropValue\n\n设置指定 propName 的值\n\n```\n/**\n  * 设置指定 propName 的值\n  * @param propName\n  * @param value\n  */\nsetPropValue(propName: string | number, value: any): void;\n```\n\n#### clearPropValue\n\n清除指定 propName 的值\n\n```\n/**\n  * 清除指定 propName 的值\n  * @param propName\n  */\nclearPropValue(propName: string | number): void;\n```"
  },
  {
    "path": "docs/docs/api/model/simulatorRender.md",
    "content": "---\ntitle: SimulatorRender\nsidebar_position: 6\n---\n> **@types** [IPublicModelSimulatorRender](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/simulator-render.ts)<br/>\n> **@since** v1.0.0\n\n## 基本介绍\n\n画布节点选中模型\n\n## 属性\n### components\n\n画布组件列表\n\n```typescript\n/**\n  * 画布组件列表\n  */\ncomponents: {\n  [key: string]: any;\n}\n```\n\n## 方法\n\n### rerender\n\n触发画布重新渲染\n\n```typescript\n/**\n * 触发画布重新渲染\n */\nrerender: () => void;\n```\n\n"
  },
  {
    "path": "docs/docs/api/model/window.md",
    "content": "---\ntitle: Window\nsidebar_position: 12\n---\n\n> **[@experimental](./#experimental)**<br/>\n> **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/window.ts)<br/>\n> **@since** v1.1.0\n\n\n## 基本介绍\n\n低代码设计器窗口模型\n\n## 属性\n\n### id\n\n窗口唯一 id\n\n`@type {string}`\n\n### title\n\n窗口标题\n\n`@type {string}`\n\n### icon\n\n`@type {ReactElement}`\n\n### resource\n\n窗口对应资源\n\n`@type {IPublicModelResource}`\n\n关联模型 [IPublicModelResource](./resource)\n\n### currentEditorView\n窗口当前视图\n\n`@type {IPublicModelEditorView}`\n\n关联模型 [IPublicModelEditorView](./editor-view)\n\n**@since v1.1.7**\n\n### editorViews\n\n窗口所有视图\n\n`@type {IPublicModelEditorView[]}`\n\n关联模型 [IPublicModelEditorView](./editor-view)\n\n**@since v1.1.7**\n\n## 方法\n\n### importSchema\n当前窗口导入 schema, 会调用当前窗口对应资源的 import 钩子\n\n```typescript\nfunction importSchema(schema: IPublicTypeNodeSchema): void\n```\n\n相关类型：[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)\n\n### changeViewType\n修改当前窗口视图类型\n\n```typescript\nfunction changeViewType(viewName: string): void\n```\n\n### save\n当前窗口的保存方法，会调用当前窗口对应资源的 save 钩子\n\n```typescript\nfunction save(): Promise(void)\n```\n\n## 事件\n\n### onChangeViewType\n\n窗口视图变更事件\n\n```\nonChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onSave\n\n窗口视图保存事件\n\n```\nonSave(fn: () => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n**@since v1.1.7**\n"
  },
  {
    "path": "docs/docs/api/plugins.md",
    "content": "---\ntitle: plugins - 插件 API\nsidebar_position: 2\n---\n> **@types** [IPublicApiPlugins](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/plugins.ts)<br/>\n> **@since** v1.0.0\n\n## 模块简介\n插件管理器，提供编排模块中管理插件的能力。\n\n## 方法\n### register\n注册插件\n\n```typescript\nasync function register(\n  plugin: IPublicTypePlugin,\n  options?: IPublicTypePluginRegisterOptions,\n): Promise<void>\n```\n相关 types:\n- [IPublicTypePlugin](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin.ts)\n- [IPublicTypePluginRegisterOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-register-options.ts)\n\n其中第一个参数 plugin 通过低代码工具链的插件脚手架生成编写模板，开发者可以参考[这个章节](/site/docs/guide/expand/editor/cli)进行创建\n\n\n#### 简单示例\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst builtinPluginRegistry = (ctx: IPublicModelPluginContext) => {\n  return {\n    async init() {\n      const { skeleton } = ctx;\n\n      // 注册组件面板\n      const componentsPane = skeleton.add({\n        area: 'leftArea',\n        type: 'PanelDock',\n        name: 'componentsPane',\n        content: ComponentsPane,\n        contentProps: {},\n        props: {\n          align: 'top',\n          icon: 'zujianku',\n          description: '组件库',\n        },\n      });\n      componentsPane?.disable?.();\n      project.onSimulatorRendererReady(() => {\n        componentsPane?.enable?.();\n      })\n    },\n  };\n}\nbuiltinPluginRegistry.pluginName = 'builtinPluginRegistry';\nawait plugins.register(builtinPluginRegistry);\n```\n#### 使用 exports 示例\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst PluginA = (ctx: IPublicModelPluginContext) => {\n  return {\n    async init() {},\n    exports() { return { x: 1, } },\n  };\n}\nPluginA.pluginName = 'PluginA';\n\nconst PluginB = (ctx: IPublicModelPluginContext) => {\n  return {\n    async init() {\n      // 获取 pluginA 的导出值\n      console.log(ctx.plugins.PluginA.x); // => 1\n    },\n  };\n}\nPluginA.pluginName = 'pluginA';\nPluginB.pluginName = 'PluginB';\nPluginB.meta = {\n  dependencies: ['PluginA'],\n}\nawait plugins.register(PluginA);\nawait plugins.register(PluginB);\n```\n> 注：ctx 是在插件中获取引擎 API 的唯一渠道，具体定义参见 [IPublicModelPluginContext](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-context.ts)\n\n\n#### 设置兼容引擎版本示例\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst BuiltinPluginRegistry = (ctx: IPublicModelPluginContext) => {\n  return {\n    async init() {\n      ...\n    },\n  };\n}\nBuiltinPluginRegistry.pluginName = 'BuiltinPluginRegistry';\nBuiltinPluginRegistry.meta = {\n  engines: {\n    lowcodeEngine: '^1.0.0', // 插件需要配合 ^1.0.0 的引擎才可运行\n  },\n}\nawait plugins.register(BuiltinPluginRegistry);\n```\n#### 设置插件参数版本示例\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst BuiltinPluginRegistry = (ctx: IPublicModelPluginContext, options: any) => {\n  return {\n    async init() {\n      // 直接传值方式：\n      //   通过 register(xxx, options) 传入\n      //   通过 options 取出\n\n      // 引擎初始化时也可以设置某插件的全局配置项：\n      //   通过 engine.init(..., preference) 传入\n      //   通过 ctx.preference.getValue() 取出\n    },\n  };\n}\nBuiltinPluginRegistry.pluginName = 'BuiltinPluginRegistry';\nBuiltinPluginRegistry.meta = {\n  preferenceDeclaration: {\n    title: 'pluginA 的参数定义',\n    properties: [\n      {\n        key: 'key1',\n        type: 'string',\n        description: 'this is description for key1',\n      },\n      {\n        key: 'key2',\n        type: 'boolean',\n        description: 'this is description for key2',\n      },\n      {\n        key: 'key3',\n        type: 'number',\n        description: 'this is description for key3',\n      },\n      {\n        key: 'key4',\n        type: 'string',\n        description: 'this is description for key4',\n      },\n    ],\n  },\n}\n\nawait plugins.register(BuiltinPluginRegistry, { key1: 'abc', key5: 'willNotPassToPlugin' });\n```\n\n### get\n\n获取指定插件\n\n```typescript\n/**\n * 获取指定插件\n * get plugin instance by name\n */\nget(pluginName: string): IPublicModelPluginInstance | null;\n```\n\n关联模型 [IPublicModelPluginInstance](./model/plugin-instance)\n\n### getAll\n\n获取所有的插件实例\n\n```typescript\n/**\n * 获取所有的插件实例\n * get all plugin instances\n */\ngetAll(): IPublicModelPluginInstance[];\n```\n\n关联模型 [IPublicModelPluginInstance](./model/plugin-instance)\n\n### has\n\n判断是否有指定插件\n\n```typescript\n/**\n * 判断是否有指定插件\n * check if plugin with certain name exists\n */\nhas(pluginName: string): boolean;\n```\n\n### delete\n\n删除指定插件\n\n```typescript\n/**\n * 删除指定插件\n * delete plugin instance by name\n */\ndelete(pluginName: string): void;\n```\n\n### getPluginPreference\n\n引擎初始化时可以提供全局配置给到各插件，通过这个方法可以获得本插件对应的配置\n\n```typescript\n/**\n * 引擎初始化时可以提供全局配置给到各插件，通过这个方法可以获得本插件对应的配置\n * use this to get preference config for this plugin when engine.init() called\n */\ngetPluginPreference(\n    pluginName: string,\n  ): Record<string, IPublicTypePreferenceValueType> | null | undefined;\n```\n\n## 相关类型定义\n\n- [IPublicModelPluginContext](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-context.ts)\n- [IPublicTypePluginConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-config.ts)\n- [IPublicModelPluginInstance](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-instance.ts)\n\n## 插件元数据工程转化示例\nyour-plugin/package.json\n```json\n{\n\t\"name\": \"@alilc/lowcode-plugin-debug\",\n  \"lcMeta\": {\n    \"pluginName\": \"debug\",\n    \"meta\": {\n      \"engines\": {\n        \"lowcodeEgnine\": \"^1.0.0\"\n      },\n      \"preferenceDeclaration\": { ... }\n    }\n  }\n}\n```\n转换后的结构：\n```typescript\nconst debug = (ctx: IPublicModelPluginContext, options: any) => {\n\treturn {};\n}\n\ndebug.pluginName = 'debug';\ndebug.meta = {\n  engines: {\n    lowcodeEgnine: '^1.51.0',\n\t},\n  preferenceDeclaration: { ... }\n};\n```\n"
  },
  {
    "path": "docs/docs/api/project.md",
    "content": "---\ntitle: project - 模型 API\nsidebar_position: 10\n---\n## 模块简介\n\n引擎编排模块中包含多种模型，包括：\n- [文档模型 DocumentModel](./model/document-model)\n- [节点模型 Node](./model/node)\n- [节点孩子模型 NodeChildren](./model/node-children)\n- [属性模型 Prop](./model/prop)\n- [属性集模型 Props](./model/props)\n\n他们的依赖关系如下图：\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01B1bAZi1asNU3KaSUJ_!!6000000003385-2-tps-1650-1352.png)\n\n在文档模型内部，又有一些引申模型，比如：\n- [历史操作 History）](./model/history)\n- [画布节点选中 Selection）](./model/selection)\n- [画布节点悬停 Detecting）](./model/detecting)\n- [模态节点管理器 ModalNodesManager](./model/modal-nodes-manager)\n\n整个模型系统，以 project API 为入口，所有模型实例均需要通过 project 来获得，比如 project.currentDocument 来获取当前的文档模型，project.currentDocument.nodesMap 来获取当前文档模型里所有的节点列表。\n\n下面来看看 project API 的具体介绍\n\n## 变量\n### currentDocument\n\n获取当前的 document 实例\n\n```typescript\n/**\n * 获取当前的 document\n * get current document\n */\nget currentDocument(): IPublicModelDocumentModel | null;\n```\n\n相关类型：[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)\n\n### documents\n\n获取当前 project 下所有 documents\n\n```typescript\n/**\n * 获取当前 project 下所有 documents\n * get all documents of this project\n * @returns\n */\nget documents(): IPublicModelDocumentModel[];\n```\n\n相关类型：[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)\n\n### simulatorHost\n\n获取模拟器的 host\n\n```typescript\n/**\n * 获取模拟器的 host\n * get simulator host\n */\nget simulatorHost(): IPublicApiSimulatorHost | null;\n```\n\n相关类型：[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)\n\n\n## 方法\n### openDocument\n\n打开一个 document\n\n```typescript\n/**\n * 打开一个 document\n * @param doc\n * @returns\n */\nopenDocument(doc?: string | IPublicTypeRootSchema | undefined): IPublicModelDocumentModel | null;\n```\n\n相关类型：\n- [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)\n- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)\n\n### createDocument\n\n创建一个 document\n\n```typescript\n/**\n * 创建一个 document\n * create a document\n * @param data\n * @returns\n */\ncreateDocument(data?: IPublicTypeRootSchema): IPublicModelDocumentModel | null;\n```\n\n相关类型：\n- [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)\n- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)\n\n### removeDocument\n\n删除一个 document\n\n```typescript\n/**\n * 删除一个 document\n * remove a document\n * @param doc\n */\nremoveDocument(doc: IPublicModelDocumentModel): void;\n```\n\n相关类型：[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)\n\n### getDocumentByFileName\n\n根据 fileName 获取 document\n```typescript\n/**\n * 根据 fileName 获取 document\n * get a document by filename\n * @param fileName\n * @returns\n */\ngetDocumentByFileName(fileName: string): IPublicModelDocumentModel | null;\n```\n\n相关类型：[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)\n\n### getDocumentById\n\n根据 id 获取 document\n\n```typescript\n/**\n * 根据 id 获取 document\n * get a document by id\n * @param id\n * @returns\n */\ngetDocumentById(id: string): IPublicModelDocumentModel | null;\n```\n\n相关类型：[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)\n\n### exportSchema\n\n导出 project schema\n\n```typescript\n/**\n * 导出 project\n * export project to schema\n * @returns\n */\nexportSchema(stage: IPublicEnumTransformStage): IPublicTypeProjectSchema;\n```\n\n相关类型：\n- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)\n- [IPublicTypeProjectSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/project-schema.ts)\n\n### importSchema\n\n导入 project\n\n```typescript\n/**\n * 导入 project schema\n * import schema to project\n * @param schema 待导入的 project 数据\n */\nimportSchema(schema?: IPublicTypeProjectSchema): void;\n```\n相关类型：[IPublicTypeProjectSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/project-schema.ts)\n\n### addPropsTransducer\n增加一个属性的管道处理函数\n\n```typescript\n/**\n * 增加一个属性的管道处理函数\n * add a transducer to process prop\n * @param transducer\n * @param stage\n */\naddPropsTransducer(\n    transducer: IPublicTypePropsTransducer,\n    stage: IPublicEnumTransformStage,\n  ): void;\n```\n相关类型：\n- [IPublicTypePropsTransducer](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-transducer.ts)\n- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)\n\n**示例**\n在保存的时候删除每一个组件的 props.hidden\n```typescript\nimport { project } from '@alilc/lowcode-engine';\nimport { IPublicTypeCompositeObject, IPublicEnumTransformStage, IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nexport const DeleteHiddenTransducer = (ctx: IPublicModelPluginContext) => {\n  return {\n    async init() {\n      const { project } = ctx;\n      project.addPropsTransducer((props: IPublicTypeCompositeObject): IPublicTypeCompositeObject => {\n        delete props.hidden;\n        return props;\n      }, IPublicEnumTransformStage.Save);\n    },\n  };\n}\n\nDeleteHiddenTransducer.pluginName = 'DeleteHiddenTransducer';\n```\n\n### setI18n\n设置多语言语料\n\n```typescript\n/**\n * 设置多语言语料\n * 数据格式参考 https://github.com/alibaba/lowcode-engine/blob/main/specs/lowcode-spec.md#2434%E5%9B%BD%E9%99%85%E5%8C%96%E5%A4%9A%E8%AF%AD%E8%A8%80%E7%B1%BB%E5%9E%8Baa\n *\n * set I18n data for this project\n * @param value object\n * @since v1.0.17\n */\nsetI18n(value: object): void;\n```\n\n**@since v1.0.17**\n\n### setConfig\n设置当前项目配置\n\n```typescript\n/**\n * 设置当前项目配置\n * set config for this project\n * @param value object\n * @since v1.1.4\n */\n  setConfig(value: IPublicTypeAppConfig): void;\n  setConfig<T extends keyof IPublicTypeAppConfig>(key: T, value: IPublicTypeAppConfig[T]): void;\n```\n\n**@since v1.1.4**\n\n#### 如何扩展项目配置\n\n```typescript\n// shims.d.ts\ndeclare module '@alilc/lowcode-types' {\n  export interface IPublicTypeAppConfig {\n    customProp: CustomPropType\n  }\n}\n\nexport {};\n```\n\n\n## 事件\n\n### onRemoveDocument\n绑定删除文档事件\n\n```typescript\n/**\n * 绑定删除文档事件\n * set callback for event onDocumentRemoved\n * @param fn\n * @since v1.0.16\n */\nonRemoveDocument(fn: (data: { id: string }) => void): IPublicTypeDisposable;\n```\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n**@since v1.0.16**\n\n### onChangeDocument\n\n当前 project 内的 document 变更事件\n\n```typescript\n/**\n * 当前 project 内的 document 变更事件\n * set callback for event onDocumentChanged\n */\nonChangeDocument(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable;\n```\n\n相关类型：\n- [IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onSimulatorHostReady\n\n当前 project 的模拟器 ready 事件\n\n```typescript\n/**\n * 当前 project 的模拟器 ready 事件\n * set callback for event onSimulatorHostReady\n */\nonSimulatorHostReady(fn: (host: IPublicApiSimulatorHost) => void): IPublicTypeDisposable;\n```\n相关类型：\n- [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)\n- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onSimulatorRendererReady\n\n当前 project 的渲染器 ready 事件\n\n```typescript\n/**\n * 当前 project 的渲染器 ready 事件\n * set callback for event onSimulatorRendererReady\n */\nonSimulatorRendererReady(fn: () => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n"
  },
  {
    "path": "docs/docs/api/setters.md",
    "content": "---\ntitle: setters - 设置器 API\nsidebar_position: 10\n---\n> **@types** [IPublicApiSetters](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/setters.ts)<br/>\n> **@since** v1.0.0\n\n## 模块简介\n负责注册设置器、管理设置器的 API。注册自定义设置器之后可以在物料中进行使用。\n\n## 方法\n### getSetter\n获取指定 setter\n\n```typescript\n/**\n * 获取指定 setter\n * get setter by type\n * @param type\n * @returns\n */\ngetSetter(type: string): IPublicTypeRegisteredSetter | null;\n```\n相关类型：[IPublicTypeRegisteredSetter](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/registerd-setter.ts)\n\n### getSettersMap\n获取已注册的所有 settersMap\n\n```typescript\n/**\n * 获取已注册的所有 settersMap\n * get map of all registered setters\n * @returns\n */\ngetSettersMap(): Map<string, IPublicTypeRegisteredSetter & {\n  type: string;\n}>;\n```\n\n相关类型：[IPublicTypeRegisteredSetter](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/registerd-setter.ts)\n\n### registerSetter\n注册一个 setter\n\n```typescript\n/**\n * 注册一个 setter\n * register a setter\n * @param typeOrMaps\n * @param setter\n * @returns\n */\nregisterSetter(\n  typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter },\n  setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter | undefined\n): void;\n```\n\n相关类型：\n- [IPublicTypeRegisteredSetter](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/registerd-setter.ts)\n- [IPublicTypeCustomView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/custom-view.ts)\n\n## 使用示例\n### 注册官方内置 Setter 到设计器中\n```typescript\nimport { setters, skeleton } from '@alilc/lowcode-engine';\nimport { setterMap, pluginMap } from '@alilc/lowcode-engine-ext';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst SetterRegistry = (ctx: IPublicModelPluginContext) => {\n  return {\n    name: 'ext-setters-registry',\n    async init() {\n      // 注册 setterMap\n      setters.registerSetter(setterMap);\n      // 注册插件\n      // 注册事件绑定面板\n      skeleton.add({\n        area: 'centerArea',\n        type: 'Widget',\n        content: pluginMap.EventBindDialog,\n        name: 'eventBindDialog',\n        props: {},\n      });\n\n      // 注册变量绑定面板\n      skeleton.add({\n        area: 'centerArea',\n        type: 'Widget',\n        content: pluginMap.VariableBindDialog,\n        name: 'variableBindDialog',\n        props: {},\n      });\n    },\n  };\n}\n\nSetterRegistry.pluginName = 'SetterRegistry';\nawait plugins.register(SetterRegistry);\n```\n\n### 开发自定义 Setter\nAltStringSetter 代码如下：\n```typescript\nimport * as React from \"react\";\nimport { Input } from \"@alifd/next\";\n\nimport \"./index.scss\";\ninterface AltStringSetterProps {\n  // 当前值\n  value: string;\n  // 默认值\n  initialValue: string;\n  // setter 唯一输出\n  onChange: (val: string) => void;\n  // AltStringSetter 特殊配置\n  placeholder: string;\n}\nexport default class AltStringSetter extends React.PureComponent<AltStringSetterProps> {\n  componentDidMount() {\n    const { onChange, value, defaultValue } = this.props;\n    if (value == undefined && defaultValue) {\n      onChange(defaultValue);\n    }\n  }\n\n  // 声明 Setter 的 title\n \tstatic displayName = 'AltStringSetter';\n\n  render() {\n    const { onChange, value, placeholder } = this.props;\n    return (\n      <Input\n        value={value}\n        placeholder={placeholder || \"\"}\n        onChange={(val: any) => onChange(val)}\n      ></Input>\n    );\n  }\n}\n```\n\n开发完毕之后，注册 AltStringSetter 到设计器中：\n\n```typescript\nimport AltStringSetter from './AltStringSetter';\nimport { setters } from '@alilc/lowcode-engine';\nconst { registerSetter } = setters;\nregisterSetter('AltStringSetter', AltStringSetter);\n```\n注册之后，我们就可以在物料中使用了，其中核心配置如下：\n```typescript\n{\n  \"props\": {\n    \"isExtends\": true,\n    \"override\": [\n      {\n        \"name\": \"type\",\n        \"setter\": \"AltStringSetter\"\n      }\n    ]\n  }\n}\n```\n完整配置如下：\n```typescript\n{\n  \"componentName\": \"Message\",\n  \"title\": \"Message\",\n  \"props\": [\n    {\n      \"name\": \"title\",\n      \"propType\": \"string\",\n      \"description\": \"标题\",\n      \"defaultValue\": \"标题\"\n    },\n    {\n      \"name\": \"type\",\n      \"propType\": {\n        \"type\": \"oneOf\",\n        \"value\": [\n          \"success\",\n          \"warning\",\n          \"error\",\n          \"notice\",\n          \"help\",\n          \"loading\"\n        ]\n      },\n      \"description\": \"反馈类型\",\n      \"defaultValue\": \"success\"\n    }\n  ],\n  \"configure\": {\n    \"props\": {\n      \"isExtends\": true,\n      \"override\": [\n        {\n          \"name\": \"type\",\n          \"setter\": \"AltStringSetter\"\n        }\n      ]\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/docs/api/simulatorHost.md",
    "content": "---\ntitle: simulatorHost - 模拟器 API\nsidebar_position: 10\n---\n> **@types** [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)<br/>\n> **@since** v1.0.0\n\n## 模块简介\n负责模拟器相关的 API，包括画布尺寸、语言等。\n\n## 方法\n### set\n设置 host 配置值\n```typescript\n/**\n * 设置若干用于画布渲染的变量，比如画布大小、locale 等。\n * set config for simulator host, eg. device locale and so on.\n * @param key\n * @param value\n */\nset(key: string, value: any): void;\n```\n**示例**\n设置若干用于画布渲染的变量，比如画布大小、locale 等。\n\n以设置画布大小为例：\n目前支持 3 种定制方式：\n```typescript\n\n// 直接使用内置设备类型\nproject.simulatorHost.set('device', 'mobile' / 'iphonex' / 'iphone6' / 'default');\n// 定制 canvas 的样式类\nproject.simulatorHost.set('deviceClassName', 'my-canvas-class');\n// 最灵活的方式，直接设置 canvas / viewport 的样式（canvas 是外框，viewport 是内框，可以在 canvas 设置手机 / 平板背景图）\nproject.simulatorHost.set('deviceStyle', { canvas: { width: '300px', backgroundColor: 'red' }, viewport: { width: '280px' } });\n```\n\n### get\n获取模拟器中设置的变量，比如画布大小、locale 等。\n\n```typescript\n/**\n * 获取模拟器中设置的变量，比如画布大小、locale 等。\n * set config value by key\n * @param key\n * @returns\n */\nget(key: string): any;\n\n```\n\n### rerender\n触发组件构建，并刷新渲染画布\n\n```typescript\n/**\n * 触发组件构建，并刷新渲染画布\n * make simulator render again\n */\nrerender(): void;\n```\n\n### scrollToNode\n滚动到指定节点\n\n```typescript\n/**\n * 滚动到指定节点\n * scroll to specific node\n * @param node\n * @since v1.1.0\n */\nscrollToNode(node: IPublicModelNode): void;\n```\n**@since v1.1.0**\n"
  },
  {
    "path": "docs/docs/api/skeleton.md",
    "content": "---\ntitle: skeleton - 面板 API\nsidebar_position: 10\n---\n> **@types** [IPublicApiSkeleton](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/skeleton.ts)<br/>\n> **@since** v1.0.0\n\n\n## 模块简介\n面板 API 提供了面板扩展和管理的能力，如下图蓝色内容都是扩展出来的。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01eVA0U41xYRP3e5zo0_!!6000000006455-2-tps-1780-996.png)\n\n页面上可以扩展的区域共 5 个，具体如下：\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN014d2AcS1D5c9TshEiQ_!!6000000000165-2-tps-1892-974.png)\n### 基本概念\n#### 扩展区域位置 (area)\n##### topArea\n\n展示在设计器的顶部区域，常见的相关区域的插件主要是：\n1. 注册设计器 Logo；\n2. 设计器操作回退和撤销按钮；\n3. 全局操作按钮，例如：保存、预览等；\n##### leftArea\n\n左侧区域的展示形式大多数是 Icon 和对应的面板，通过点击 Icon 可以展示对应的面板并隐藏其他的面板。\n\n该区域相关插件的主要有：\n1. 大纲树展示，展示该设计器设计页面的大纲。\n2. 组件库，展示注册到设计器中的组件，点击之后，可以从组件库面板中拖拽到设计器的画布中。\n3. 数据源面板\n4. JS 等代码面板。\n\n可以发现，这个区域的面板大多数操作时是不需要同时并存的，且交互比较复杂的，需要一个更整块的区域来进行操作。\n\n##### centerArea\n\n画布区域，由于画布大多数是展示作用，所以一般扩展的种类比较少。常见的扩展有：\n1. 画布大小修改\n2. 物料选中扩展区域修改\n##### rightArea\n\n右侧区域，常用于组件的配置。常见的扩展有：统一处理组件的配置项，例如统一删除某一个配置项，统一添加某一个配置项的。\n##### toolbar\n\n跟 topArea 类似，按需放置面板插件~\n#### 展示类型 (type)\n\n展示类型用于区分插件在设计器内可操作的几种不同界面类型。主要的几种类型为 PanelDock、Widget、Dock，另有 Panel 类型目前不推荐使用。\n##### PanelDock\n\nPanelDock 是以面板的形式展示在设计器的左侧区域的。其中主要有两个部分组成，一个是图标，一个是面板。当点击图标时可以控制面板的显示和隐藏。\n\n下图是组件库插件的展示效果。\n\n![Feb-08-2022 19-44-15.gif](https://img.alicdn.com/imgextra/i2/O1CN01i66G5O27bK37nlpxV_!!6000000007815-1-tps-1536-790.gif)\n\n其中右上角可以进行固定，可以对弹出的宽度做设定\n\n接入可以参考代码\n```javascript\nimport { skeleton } from \"@alilc/lowcode-engine\";\n\nskeleton.add({\n  area: \"leftArea\", // 插件区域\n  type: \"PanelDock\", // 插件类型，弹出面板\n  name: \"sourceEditor\",\n  content: SourceEditor, // 插件组件实例\n  props: {\n    align: \"left\",\n    icon: \"wenjian\",\n    title: '标题', // 图标下方展示的标题\n    description: \"JS 面板\",\n  },\n  panelProps: {\n    floatable: true, // 是否可浮动\n    height: 300,\n    hideTitleBar: false,\n    maxHeight: 800,\n    maxWidth: 1200,\n    title: \"JS 面板\",\n    width: 600,\n  },\n});\n```\n##### Widget\nWidget 形式是直接渲染在当前编辑器的对应位置上。如 demo 中在设计器顶部的所有组件都是这种展现形式。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01IRQIZp1m5AJPwBKDv_!!6000000004902-2-tps-1988-94.png)\n\n接入可以参考代码：\n\n```javascript\nimport { skeleton } from \"@alilc/lowcode-engine\";\n// 注册 logo 面板\nskeleton.add({\n  area: \"topArea\",\n  type: \"Widget\",\n  name: \"logo\",\n  content: Logo,  // Widget 组件实例\n  contentProps: { // Widget 插件 props\n    logo:\n    \"https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png\",\n    href: \"/\",\n  },\n  props: {\n    align: \"left\",\n    width: 100,\n  },\n});\n```\n##### Dock\n\n一个图标的表现形式，可以用于语言切换、跳转到外部链接、打开一个 widget 等场景。\n\n```javascript\nimport { skeleton } from \"@alilc/lowcode-engine\";\n\nskeleton.add({\n  area: \"leftArea\",\n  type: \"Dock\",\n  name: \"opener\",\n  props: {\n    icon: Icon, // Icon 组件实例\n    align: \"bottom\",\n    onClick: function () {\n      // 打开外部链接\n      window.open('https://lowcode-engine.cn');\n      // 显示 widget\n      skeleton.showWidget('xxx');\n    }\n  }\n});\n```\n\n## 方法\n\n### add\n\n往指定扩展区加入一块面板\n\n```typescript\n/**\n * 增加一个面板实例\n * add a new panel\n * @param config\n * @param extraConfig\n * @returns\n */\nadd(config: IPublicTypeWidgetBaseConfig, extraConfig?: Record<string, any>): any;\n```\n\n\nIWidgetBaseConfig 定义如下：\n\n| 属性名 | 含义 | 备注 |\n| --- | --- | --- |\n| name | 面板名称 |  |\n| area | 扩展区位置，可选值：'topArea' &#124; 'leftArea' &#124; 'rightArea' &#124; 'toolbar' &#124; 'bottomArea' &#124; 'mainArea' |  |\n| type | 面板类型，可选值：'Widget' &#124; 'PanelDock' &#124; 'Panel' &#124; Dock | 详见前文中对**展示类型**的描述 |\n| content | 面板的实现类/节点，类型是 ReactClass &#124; ReactElement |  |\n| props | 面板属性 | align: 'top' &#124; 'bottom' &#124; 'left' &#124; 'center' &#124; 'right'; // 指定面板 icon 位置区域<br />icon: string &#124; ReactElement;  // icon 为字符串时，请确定当前 fusion 主题包中包含该 icon<br />description: string;<br />condition: Function; // 指定当前面板的显影状态 |\n| contentProps | 面板的实现类/节点的参数 |  |\n| panelProps | 假如 type: 'Panel' &#124; 'PanelDock' 时有效，传给 Panel 类的参数 | keepVisibleWhileDragging: boolean; // 当有元素在当前 panel 拖拽时，是否保持 panel 为展开状态，默认值：false<br />area: 'leftFloatArea' &#124; 'leftFixedArea' // 指定 panel 位于浮动面板还是钉住面板 |\n| index | 面板的位置，不传默认按插件注册顺序 |  |\n\n\n### remove\n\n移除一个面板实例\n\n```typescript\n/**\n * 移除一个面板实例\n * remove a panel\n * @param config\n * @returns\n */\nremove(config: IPublicTypeWidgetBaseConfig): number | undefined;\n```\n\n### getPanel\n\n获取面板实例\n\n```typescript\n/**\n * 获取面板实例\n * @param name 面板名称\n */\ngetPanel(name: string): IPublicModelSkeletonItem | undefined;\n```\n\n相关类型：[IPublicModelSkeletonItem](https://github.com/alibaba/lowcode-engine/blob/main/packages/shell/src/model/skeleton-item.ts)\n\n@since v1.1.10\n\n### showPanel\n\n展示指定 Panel 实例\n\n```typescript\n/**\n * 展示指定 Panel 实例\n * show panel by name\n * @param name\n */\nshowPanel(name: string): void;\n```\n\n### hidePanel\n隐藏面板\n\n```typescript\n/**\n * 隐藏面板\n * hide panel by name\n * @param name\n */\nhidePanel(name: string): void;\n```\n\n### showWidget\n\n展示指定 Widget 实例\n\n```typescript\n/**\n * 展示指定 Widget 实例\n * show widget by name\n * @param name\n */\nshowWidget(name: string): void;\n```\n\n### enableWidget\n将 widget 启用。\n```typescript\n/**\n * 将 widget 启用\n * enable widget\n * @param name\n */\nenableWidget(name: string): void;\n```\n\n### hideWidget\n\n隐藏指定 widget 实例。\n\n```typescript\n/**\n * 隐藏指定 widget 实例\n * hide widget by name\n * @param name\n */\nhideWidget(name: string): void;\n```\n\n### disableWidget\n\n将 widget 禁用掉，禁用后，所有鼠标事件都会被禁止掉。\n\n适用场景：在该面板还在进行初始化构造时，可以先禁止掉，防止用户点击报错，待初始化完成，重新启用。\n\n```typescript\n/**\n * 将 widget 禁用掉，禁用后，所有鼠标事件都会被禁止掉。\n * disable widget，and make it not responding any click event.\n * @param name\n */\ndisableWidget(name: string): void;\n```\n\n### showArea\n显示某个 Area\n\n```typescript\n/**\n * 显示某个 Area\n * show area\n * @param areaName name of area\n */\nshowArea(areaName: string): void;\n```\n\n\n### hideArea\n隐藏某个 Area\n\n```typescript\n/**\n * 隐藏某个 Area\n * hide area\n * @param areaName name of area\n */\nhideArea(areaName: string): void;\n```\n\n### getAreaItems\n\n获取某个区域下的所有面板实例\n\n```typescript\n/**\n  * 获取某个区域下的所有面板实例\n  * @param areaName IPublicTypeWidgetConfigArea\n  */\ngetAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] | undefined;\n```\n\n相关类型：[IPublicModelSkeletonItem](https://github.com/alibaba/lowcode-engine/blob/main/packages/shell/src/model/skeleton-item.ts)\n\n\n\n### registerConfigTransducer\n\n注册一个面板的配置转换器（transducer）。\n\n```typescript\n/**\n * 注册一个面板的配置转换器（transducer）。\n * Registers a configuration transducer for a panel.\n * @param {IPublicTypeConfigTransducer} transducer \n *   - 要注册的转换器函数。该函数接受一个配置对象（类型为 IPublicTypeSkeletonConfig）作为输入，并返回修改后的配置对象。\n *   - The transducer function to be registered. This function takes a configuration object \n * \n * @param {number} level \n *   - 转换器的优先级。优先级较高的转换器会先执行。\n *   - The priority level of the transducer. Transducers with higher priority levels are executed first.\n * \n * @param {string} [id] \n *   - （可选）转换器的唯一标识符。用于在需要时引用或操作特定的转换器。\n *   - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed.\n */\nregisterConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void;\n```\n\n使用示例\n\n```typescript\nimport { IPublicModelPluginContext, IPublicTypeSkeletonConfig } from '@alilc/lowcode-types';\n\nfunction updatePanelWidth(config: IPublicTypeSkeletonConfig) {\n  if (config.type === 'PanelDock') {\n    return {\n      ...config,\n      panelProps: {\n        ...(config.panelProps || {}),\n        width: 240,\n      },\n    }\n  }\n\n  return config;\n}\n\nconst controlPanelWidthPlugin = (ctx: IPublicModelPluginContext) => {\n  const { skeleton } = ctx;\n  (skeleton as any).registerConfigTransducer?.(updatePanelWidth, 1, 'update-panel-width');\n\n  return {\n    init() {},\n  };\n};\n\ncontrolPanelWidthPlugin.pluginName = 'controlPanelWidthPlugin';\ncontrolPanelWidthPlugin.meta = {\n  dependencies: [],\n  engines: {\n    lowcodeEngine: '^1.2.3', // 插件需要配合 ^1.0.0 的引擎才可运行\n  },\n};\n\nexport default controlPanelWidthPlugin;\n```\n\n## 事件\n### onShowPanel\n\n监听 Panel 实例显示事件\n\n```typescript\n/**\n * 监听 panel 显示事件\n * set callback for panel shown event\n * @param listener\n * @returns\n */\nonShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onHidePanel\n\n监听 Panel 实例隐藏事件\n\n```typescript\n/**\n * 监听 Panel 实例隐藏事件\n * set callback for panel hidden event\n * @param listener\n * @returns\n */\nonHidePanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onDisableWidget\n\n监听 Widget 实例 Disable 事件\n\n```typescript\n/**\n * 监听 Widget 实例 Disable 事件\n * @param listener\n */\nonDisableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onEnableWidget\n\n监听 Widget 实例 Enable 事件\n\n```typescript\n/**\n * 监听 Widget 实例 Enable 事件\n * @param listener\n */\nonEnableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onShowWidget\n\n监听 Widget 实例显示事件\n\n```typescript\n/**\n * 监听 Widget 显示事件\n * set callback for widget shown event\n * @param listener\n * @returns\n */\nonShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onHideWidget\n\n监听 Widget 实例隐藏事件\n\n```typescript\n/**\n * 监听 Widget 隐藏事件\n * set callback for widget hidden event\n * @param listener\n * @returns\n */\nonHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n## 使用示例\n\n```typescript\nimport { skeleton } from '@alilc/lowcode-engine';\n\nskeleton.add({\n\tname: 'logo',\n  area: 'topArea',\n  type: 'Widget',\n  contentProps: {},\n  content: LogoContent,\n});\n\nskeleton.add({\n  name: 'sourceEditor',\n  type: 'PanelDock',\n  area: 'leftArea',\n  props: {\n    align: 'top',\n    icon: 'wenjian',\n    description: 'JS 面板',\n  },\n  panelProps: {\n    floatable: true,\n    height: 300,\n    help: undefined,\n    hideTitleBar: false,\n    maxHeight: 800,\n    maxWidth: 1200,\n    title: 'JS 面板',\n    width: 600,\n  },\n  content: SourceEditor,\n});\n\n// 显隐 panel\nskeleton.showPanel('sourceEditor');\nskeleton.hidePanel('sourceEditor');\n\n\n// 创建一个浮动的 widget\nskeleton.add({\n  name: 'floatingWidget',\n  type: 'Widget',\n  area: 'mainArea',\n  props: {},\n  content: React.createElement('div', {}, 'haha'),\n  contentProps: {\n    style: {\n      position: 'fixed',\n      top: '200px',\n      bottom: 0,\n      width: 'calc(100% - 46px)',\n      'background-color': 'lightblue'\n    }\n  }\n});\n\n// 显隐 widget\nskeleton.showWidget('floatingWidget');\nskeleton.hideWidget('floatingWidget');\n\n// 控制 widget 的可点击态\nskeleton.enableWidget('sourceEditor');\nskeleton.disableWidget('sourceEditor');\n```\n### bottomArea 示例\n```typescript\nimport { skeleton } from '@alilc/lowcode-engine';\n\nskeleton.add({\n  name: 'bottomAreaPanelName',\n  area: 'bottomArea',\n  type: 'Panel',\n  content: () => 'demoText',\n});\n\n\nskeleton.showPanel('bottomAreaPanelName');\n```\n### widget 示例\n```typescript\n// 注册 logo 面板\nskeleton.add({\n  area: 'topArea',\n  type: 'Widget',\n  name: 'logo',\n  content: Logo,\n  contentProps: {\n    logo: 'https://img.alicdn.com/imgextra/i4/O1CN013w2bmQ25WAIha4Hx9_!!6000000007533-55-tps-137-26.svg',\n    href: 'https://lowcode-engine.cn',\n  },\n  props: {\n    align: 'left',\n  },\n});\n```\n"
  },
  {
    "path": "docs/docs/api/workspace.md",
    "content": "---\ntitle: workspace - 应用级 API\nsidebar_position: 10\n---\n\n> **[@experimental](./#experimental)**<br/>\n> **@types** [IPublicApiWorkspace](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/workspace.ts)<br/>\n> **@since** v1.1.0\n\n## 模块简介\n\n通过该模块可以开发应用级低代码设计器。\n\n## 变量\n\n### isActive\n\n是否启用 workspace 模式\n\n### window\n\n当前设计器窗口模型\n\n```typescript\nget window(): IPublicModelWindow\n```\n\n关联模型 [IPublicModelWindow](./model/window)\n\n### plugins\n\n应用级别的插件注册\n\n```typescript\nget plugins(): IPublicApiPlugins\n```\n\n关联模型 [IPublicApiPlugins](./plugins)\n\n### skeleton\n\n应用级别的面板管理\n\n```typescript\nget skeleton(): IPublicApiSkeleton\n```\n\n关联模型 [IPublicApiSkeleton](./skeleton)\n\n### windows\n\n当前设计器的编辑窗口\n\n```typescript\nget window(): IPublicModelWindow[]\n```\n\n关联模型 [IPublicModelWindow](./model/window)\n\n### resourceList\n\n当前设计器的资源列表数据\n\n```\nget resourceList(): IPublicModelResource;\n```\n\n关联模型 [IPublicModelResource](./model/resource)\n\n## 方法\n\n### registerResourceType\n注册资源\n\n```typescript\n/** 注册资源 */\nregisterResourceType(resourceTypeModel: IPublicTypeResourceType): void;\n```\n\n相关类型：[IPublicTypeResourceType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-type.ts)\n\n### setResourceList\n\n设置设计器资源列表数据\n\n```typescript\nsetResourceList(resourceList: IPublicResourceList) {}\n```\n\n相关类型：[IPublicResourceData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-list.ts)\n\n### openEditorWindow\n\n打开视图窗口\n\n```typescript\n/**\n * 打开视图窗口\n * @deprecated\n */\nopenEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>;\n\n/** 打开视图窗口 */\nopenEditorWindow(resource: Resource, sleep?: boolean): Promise<void>;\n```\n\n### openEditorWindowById\n\n通过视图 id 打开窗口\n\n```typescript\nopenEditorWindowById(id: string): void;\n```\n\n### removeEditorWindow\n\n移除视图窗口\n\n```typescript\n/**\n * 移除视图窗口\n * @deprecated\n */\nremoveEditorWindow(resourceName: string, id: string): void;\n\n/**\n * 移除视图窗口\n */\nremoveEditorWindow(resource: Resource): void;\n```\n\n### removeEditorWindowById\n\n通过视图 id 移除窗口\n\n```typescript\nremoveEditorWindowById(id: string): void;\n```\n\n## 事件\n\n### onChangeWindows\n\n窗口新增/删除的事件\n\n```typescript\nfunction onChangeWindows(fn: () => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n### onChangeActiveWindow\n\nactive 窗口变更事件\n\n```typescript\nfunction onChangeActiveWindow(fn: () => void): IPublicTypeDisposable;\n```\n\n相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n\n\n### onResourceListChange\n\n设计器资源列表数据变更事件\n\n```typescript\nonResourceListChange(fn: (resourceList: IPublicResourceList): void): (): IPublicTypeDisposable;\n```\n\n- 相关类型：[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts)\n- 相关类型：[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)\n"
  },
  {
    "path": "docs/docs/article/index.md",
    "content": "# 官方文章\n- [2023/11/09 UIPaaS | 基于 LowCodeEngine 的低代码平台孵化器](https://mp.weixin.qq.com/s/mKuv3_Wvgt5T3AGErUGBQQ)\n- [2023/04/04 什么？低代码引擎可以开发应用了](https://mp.weixin.qq.com/s/dwi40gJjGBHW9MVpag5Oxg)\n- [2023/03/23 低代码引擎 LowCodeEngine 茁壮成长的一年](https://mp.weixin.qq.com/s/DDt4LQLFUBQ2-F5ehZGBKg)\n- [2023/02/21 基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw)\n- [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q)\n- [2022/11/24 低代码引擎半岁啦，来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409)\n- [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ)\n- [2022/08/23 基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w)\n- [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA)\n- [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig)\n- [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw)\n- [2022/03/23 阿里低代码引擎 LowCodeEngine 正式开源！](https://mp.weixin.qq.com/s/T66LghtWLz2Oh048XqaniA)\n- [2022/01/10 阿里低代码引擎和生态建设实战及思考](https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA)\n- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw)\n"
  },
  {
    "path": "docs/docs/demoUsage/advanced/_category_.json",
    "content": "{\n  \"label\": \"进阶功能\",\n  \"position\": 3,\n  \"collapsed\": false,\n  \"collapsible\": false\n}\n"
  },
  {
    "path": "docs/docs/demoUsage/advanced/hotkey.md",
    "content": "---\ntitle: 8. 编辑器快捷键\nsidebar_position: 0\n---\n- 任意时机：\n   - `⌘` `S` 保存\n   - `⌘` `P` 预览\n   - `⌘` `D` 查看 Diff\n   - `⌘` `Z` 撤销\n   - `⇧` `⌘` `Z` 重做\n- 选择任意组件后：\n   - `Backspace` 删除组件\n   - `⌘` `C` 复制组件\n   - `⌘` `V` 粘贴组件\n   - `⌘` `X` 剪切组件\n   - `⌥` `↑` 向外层移动组件\n   - `⌥` `↓` 向内层移动组件\n   - `⌥` `←` 同级向上移动组件\n   - `⌥` `→` 同级向下移动组件\n   - `↑` 向上选择组件\n   - `↓` 向下选择组件\n   - `←` 向左选择组件\n   - `→` 向右选择组件\n   - `Escape` 取消选择组件\n"
  },
  {
    "path": "docs/docs/demoUsage/appendix/_category_.json",
    "content": "{\n  \"label\": \"常见问题\",\n  \"position\": 4,\n  \"collapsed\": false,\n  \"collapsible\": false\n}\n"
  },
  {
    "path": "docs/docs/demoUsage/appendix/api.md",
    "content": "---\ntitle: demo 使用相关 API\nsidebar_position: 2\n---\n## 数据源相关\n### 请求数据源\n```javascript\n// 请求 userList（userList 在数据源面板中定义）\n\nthis.dataSourceMap['userList'].load({\n\tdata: {}\n}).then(res => {})\n  .catch(error => {});\n```\n\n### 获取数据源的值\n```javascript\nconst { userList } = this.state;\n```\n\n### 手动修改数据源值\n```javascript\n// 获取数据源面板中定义的值\nconst { user } = this.state;\n\n// 修改 state 值\nthis.setState({\n\tuser: {}\n});\n```\n"
  },
  {
    "path": "docs/docs/demoUsage/appendix/loop.md",
    "content": "---\ntitle: 如何使用循环值\nsidebar_position: 0\n---\n1.设置循环数据\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01Gw1kXO1qaXulQCWap_!!6000000005512-2-tps-3840-1900.png)\n\n2.给需要的变量绑定 this.item\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01RpP2Ev24lRxjqpHdY_!!6000000007431-2-tps-3840-1892.png)\n\n绑定之后的效果如下：\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN019qa1J31m7ugsXcnaA_!!6000000004908-2-tps-3840-1884.png)\n\n其中 this.item 的 item 是可以配置的。配置不同的 key 可以方便在多层循环中使用不同层级的循环 item 值。\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01XQfnYL1P4wxn01oXv_!!6000000001788-2-tps-3840-1896.png)\n\nthis.index 是当前循环的索引值。\n\n3.在事件绑定函数中使用\n\n在事件绑定函数中使用扩展参数设置\n![image](https://github.com/alibaba/lowcode-engine/assets/11935995/7274506e-decd-497a-b07f-c95941a706b4)\n\n绑定之后在函数中使用\n![image](https://github.com/alibaba/lowcode-engine/assets/11935995/9d52ee5c-9959-4991-91be-9391e639bb7e)\n\n按钮点击效果\n![image](https://github.com/alibaba/lowcode-engine/assets/11935995/6ca590c9-1f5f-4d48-94a5-439130a22e92)\n"
  },
  {
    "path": "docs/docs/demoUsage/intro.md",
    "content": "---\ntitle: 1. 试用低代码引擎 Demo\nsidebar_position: 0\n---\n低代码编辑器中的区块主要包含这些功能点：\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01aGQull1RVdGs7Pt6x_!!6000000002117-2-tps-3384-1784.png)\n\n## 分区块功能介绍\n### 左侧：面板与操作区\n#### 物料面板\n可以查找组件，并在此拖动组件到编辑器画布中\n![Dec-17-2021 19-12-46.gif](https://img.alicdn.com/imgextra/i1/O1CN01pEu7811SlwzxraLHG_!!6000000002288-1-tps-1468-754.gif)\n\n#### 大纲面板\n可以调整页面内的组件树结构：\n![Dec-17-2021 19-14-34.gif](https://img.alicdn.com/imgextra/i1/O1CN013DDLqt1GH0rAlajqi_!!6000000000596-1-tps-1468-754.gif)\n可以在这里打开或者关闭模态浮层的展现：\n![Dec-17-2021 19-19-18.gif](https://img.alicdn.com/imgextra/i2/O1CN01bQfS8W1JitokHRinC_!!6000000001063-1-tps-1468-754.gif)\n\n\n#### 源码面板\n可以编辑页面级别的 JavaScript 代码和 CSS 配置\n![Feb-11-2022 14-51-59.gif](https://img.alicdn.com/imgextra/i1/O1CN01d11kK71Q223eWvL5F_!!6000000001917-1-tps-1532-614.gif)\n\n#### Schema 编辑\n【开发者专属】可以编辑页面的底层 Schema 数据。\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01lcQOER23Q5sjA0Gn5_!!6000000007249-2-tps-3070-1648.png)\n搭配顶部操作区的“保存到本地”和“重置页面”功能，可以实验各种 schema 对低代码页面的改变。\n\n它们操作的数据关系是：\n\n- 页面中的 Schema 数据：保存在低代码引擎中的 Schema，点击 Schema 面板中的“保存 Schema”时将修改引擎中的值，此外低代码引擎中的所有操作都可能修改到 Schema\n- localStorage 数据：由“保存到本地”保存到 localStorage 中，页面初始化时将读取，预览页面时也会读取\n- 默认 Schema：保存在 Demo 项目中的默认 Schema（`public/schema.json`），初始化页面时如果不存在 localStorage 数据即会读取，点击“重置页面”时，也会读取\n\n#### 中英文切换\n可以切换编辑器的语言；注：需要组件配置配合。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN019ORknX1M5SYg7eSJ3_!!6000000001383-2-tps-3018-1512.png)\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01R7g7pW21rSJEHd2AI_!!6000000007038-2-tps-3016-1510.png)\n## 中部：可视化页面编辑画布区域\n\n点击组件在右侧面板中能够显示出对应组件的属性配置选项\n![Dec-17-2021 19-28-28.gif](https://img.alicdn.com/imgextra/i1/O1CN01uBU3lR1CuAFTTq4RS_!!6000000000140-1-tps-1468-754.gif)\n\n拖拽修改组件的排列顺序\n![Dec-17-2021 19-29-40.gif](https://img.alicdn.com/imgextra/i3/O1CN01DAAYKd1bycUq1C4JV_!!6000000003534-1-tps-1468-754.gif)\n\n将组件拖拽到容器类型的组件中，注意拖拽时会在右侧提示当前的组件树。\n![Dec-17-2021 19-31-30.gif](https://img.alicdn.com/imgextra/i2/O1CN01TzJosP1FIYZe6xIQ5_!!6000000000464-1-tps-1468-754.gif)\n\n## 右侧：组件级别配置\n\n### 选中的组件\n从页面开始一直到当前选中的组件位置，点击对应的名称可以切换到对应的组件上。\n![Dec-17-2021 19-35-25.gif](https://img.alicdn.com/imgextra/i4/O1CN01EbImy425R80OeblSD_!!6000000007522-1-tps-1468-754.gif)\n\n### 选中组件的配置\n当前组件的大类目选项，根据组件类型不同，包含如下子类目：\n\n#### 属性\n组件的基础属性值设置\n![Dec-17-2021 19-37-26.gif](https://img.alicdn.com/imgextra/i2/O1CN01ziBI9T1nQynFKqCp2_!!6000000005085-1-tps-1468-754.gif)\n\n#### 样式\n组件的样式配置，如文字：\n![Dec-17-2021 19-38-55.gif](https://img.alicdn.com/imgextra/i4/O1CN017DQv2R1OEjoawXmKJ_!!6000000001674-1-tps-1468-754.gif)\n\n#### 事件\n绑定组件对外暴露的事件。\n![Dec-17-2021 19-41-17.gif](https://img.alicdn.com/imgextra/i2/O1CN01mhVutF24I8cLde0zy_!!6000000007367-1-tps-1468-754.gif)\n\n#### 高级\n循环、条件渲染与 key 设置。\n![Dec-17-2021 19-46-26.gif](https://img.alicdn.com/imgextra/i4/O1CN01xTjXQX1jMcYwuTGKZ_!!6000000004534-1-tps-1468-754.gif)\n\n## 顶部：操作区\n\n### 撤回和重做\n![Dec-17-2021 19-52-23.gif](https://img.alicdn.com/imgextra/i3/O1CN019VWkbr1jsgHoGKf6g_!!6000000004604-1-tps-1468-754.gif)\n"
  },
  {
    "path": "docs/docs/demoUsage/makeStuff/_category_.json",
    "content": "{\n  \"label\": \"如何制作\",\n  \"position\": 1,\n  \"collapsed\": false,\n  \"collapsible\": false\n}\n"
  },
  {
    "path": "docs/docs/demoUsage/makeStuff/dialog.md",
    "content": "---\ntitle: 3. 如何通过按钮展示/隐藏弹窗\nsidebar_position: 1\n---\n> 说明：这个方式依赖低代码弹窗组件是否对外保留了相关的 API，不同的物料支持的方式不一样，这里只针对综合场景的弹窗物料。\n\n## 1.拖拽一个按钮\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01kLaWA31D6WwTui9VW_!!6000000000167-2-tps-3584-1812.png)\n## 2.拖拽一个弹窗\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01rfRzLa1quEwUyulPc_!!6000000005555-2-tps-3578-1622.png)\n\n## 3.查看弹窗 refId\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01rEgPnW1cSqdWpG0YE_!!6000000003600-2-tps-3574-1588.png)\n\n- 点击弹窗\n- 点击右侧面板中的高级\n- 找到 refId\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01MXMfqn1rj4uKzlOh2_!!6000000005666-2-tps-3584-1796.png)\n\n这里我们的 refId 是 \"pro-dialog-entryl32xgrus\"\n## 4.隐藏弹窗\n点击工具栏的隐藏小图标，将弹窗在画布中隐藏\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN017Kamt71HFvWkpeK8j_!!6000000000729-2-tps-3578-1568.png)\n\n## 5.按钮绑定事件\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01SwJ0xx1u3LfX2h8yt_!!6000000005981-2-tps-3584-1814.png)\n\n**通过下面的代码即可打开弹窗**\n\n```typescript\nthis.$('pro-dialog-entryl32xgrus').open();\n```\n####\n"
  },
  {
    "path": "docs/docs/demoUsage/makeStuff/table.md",
    "content": "---\ntitle: 2. 如何制作表格\nsidebar_position: 0\n---\n## 步骤详解\n### 拖入组件\n\n一个常见的表格页面会包含查询框、表格和分页按钮。这些都在 Fusion UI 中进行了相应的封装，我们可以在左侧组件面板处找到他们。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01UU8pVT26XN1A0ExVG_!!6000000007671-2-tps-3032-1648.png)\n\n将他们拖到画布之中：\n![Feb-16-2022 16-58-59.gif](https://img.alicdn.com/imgextra/i3/O1CN01UAsQ8124HgDptzPrn_!!6000000007366-1-tps-1534-792.gif)\n### 配置组件\n\n选中刚拖入的“查询筛选”组件，您可以配置此组件：\n![Feb-14-2022 17-59-47.gif](https://img.alicdn.com/imgextra/i2/O1CN01RiDUy31aufSeVk8IN_!!6000000003390-1-tps-1532-792.gif)\n\n对于形如 Array 的配置项目，我们可以增删项目、修改常用项、修改顺序。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01eWOK0d1fOfsF9PZu9_!!6000000003997-2-tps-3060-1476.png)\n\n掌握组件配置功能，我们就可以完成一个常用的查询框的配置：\n![Feb-21-2022 18-05-52.gif](https://img.alicdn.com/imgextra/i1/O1CN0138fb0P1CTbHKWDBeo_!!6000000000082-1-tps-1532-790.gif)\n\n### 绑定数据\n\n低代码场景下，我们需要绑定动态的数据。通过左侧的源码编辑面板，我们可以创建动态数据和它的相关处理函数：\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN015Bw2aQ1jaMRWoYzv5_!!6000000004564-2-tps-2976-1478.png)\n\n如图，我们配入如下自定义值进 state 里：\n```json\n    \"companies\": [\n      { company: '测试公司1', id: 1, createTime: +new Date() },\n      { company: '测试公司2', id: 2, createTime: +new Date() },\n      { company: '测试公司3', id: 3, createTime: +new Date() },\n    ]\n```\n定义动态数据以后，我们需要绑定它到组件的属性中，我们找到相关属性的配置：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN013Cu5OE1CXGRhyEmbJ_!!6000000000090-2-tps-3546-1792.png)\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01iaK15j1bgIeO65svI_!!6000000003494-2-tps-3428-1640.png)\n\n如图，输入表达式：\n\n```javascript\nthis.state.companies\n```\n\n再结合上一节的“配置组件”操作，我们已经可以把表格的主体配置出来了：\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01p8QJ5C1buxKDTS1cU_!!6000000003526-2-tps-3058-1640.png)\n\n### 动态请求\n\n我们进入代码区块，使用生命周期方法来完成动态数据的请求。假设提供数据的接口是：[http://rap2api.taobao.org/app/mock/250089/testCompanies](http://rap2api.taobao.org/app/mock/250089/testCompanies)，那么，我们可以在源码面板进行如下配置：\n\n```typescript\nclass LowcodeComponent extends Component {\n  state = {\n    \"text\": \"outer\",\n    \"isShowDialog\": false,\n    \"loading\": false,\n    \"companies\": [\n      { company: '测试公司 1', id: 1, createTime: +new Date() },\n      { company: '测试公司 2', id: 2, createTime: +new Date() },\n      { company: '测试公司 3', id: 3, createTime: +new Date() },\n    ]\n  }\n  componentDidMount() {\n    this.setState({ loading: true })\n    window.fetch('http://rap2api.taobao.org/app/mock/250089/testCompanies')\n      .then((res) => res.json())\n      .then((companies) => {\n        this.setState({\n          companies,\n        })\n      })\n      .catch(err => console.error(err))\n      .then(() => {\n        this.setState({ loading: false })\n      })\n  }\n}\n```\n\n在 `componentDidMount` 生命周期，将请求接口并设置 loading 和数据字段。\n\n点击保存或叉关闭源码面板后，我们可以看到代码已经生效了：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01lqjW8e1f39G8Zm7hQ_!!6000000003950-2-tps-3058-1634.png)\n\n### 配置插槽\n\n我们可以用绑定数据的方法把 loading 绑在加载指示上：\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01K3Pwjo1PKWQcoBl5K_!!6000000001822-2-tps-3170-1904.png)\n\n![Feb-16-2022 20-24-35.gif](https://img.alicdn.com/imgextra/i2/O1CN01VGlZPS1JitoljrFFY_!!6000000001063-1-tps-1532-792.gif)\n\n将 Loading 的“是否显示”字段绑定 `this.state.loading` 后，我们可以看到，这里暴露了一个插槽。插槽是可以任意扩展的预设部分，我们可以把其他的部分拖进插槽：\n\n![Feb-16-2022 20-27-03.gif](https://img.alicdn.com/imgextra/i2/O1CN01HSBncU1XWRfPdwlPK_!!6000000002931-1-tps-1528-792.gif)\n\n点击右上角的预览，我们能够看到完整的动态请求效果了：\n![Feb-16-2022 20-28-36.gif](https://img.alicdn.com/imgextra/i3/O1CN01o5THZf1fkesw2nZEC_!!6000000004045-1-tps-1534-792.gif)\n\n### 列挂钩浮层\n\n为了能够让表格里的操作挂钩浮层，我们先拖入一个浮层：\n![Feb-16-2022 20-32-09.gif](https://img.alicdn.com/imgextra/i2/O1CN01bX3SHk21Z8T4O6knp_!!6000000006998-1-tps-1532-792.gif)\n\n使用大纲树能够临时显示和隐藏此浮层：\n![Feb-16-2022 20-32-39.gif](https://img.alicdn.com/imgextra/i3/O1CN01ZtSp0P1LvNqYPeUHg_!!6000000001361-1-tps-1530-792.gif)\n\n我们给表格增加一个数据列：\n![Feb-16-2022 20-39-41.gif](https://img.alicdn.com/imgextra/i2/O1CN012K6qWI1hgCG6KwRF7_!!6000000004306-1-tps-1532-792.gif)\n\n然后配置它的行为为“弹窗”：\n![Feb-16-2022 20-40-05.gif](https://img.alicdn.com/imgextra/i2/O1CN016axZh61uc9ln0L3Rz_!!6000000006057-1-tps-1532-792.gif)\n\n实现的效果如下：\n![Feb-16-2022 20-42-51.gif](https://img.alicdn.com/imgextra/i4/O1CN018iana91j4l71QTmpE_!!6000000004495-1-tps-1534-792.gif)\n\n### 事件回调\n\n上述功能点中，我们是把操作行为绑定在数据列上的，这一节我们绑定到操作列中。在操作列按钮处，点击下方的“添加一项”：\n![Feb-23-2022 11-58-02.gif](https://img.alicdn.com/imgextra/i4/O1CN01DsBoHQ1tyli2rtoFR_!!6000000005971-1-tps-1534-790.gif)\n\n点击左侧的详情按钮，配置它的事件回调：\n![Feb-23-2022 12-00-18.gif](https://img.alicdn.com/imgextra/i2/O1CN017BuNLP1LPmW8zH7hx_!!6000000001292-1-tps-1534-790.gif)\n\n代码侧，我们配置这个回调函数：\n```javascript\nonClick_new(e, { rowKey, rowIndex, rowRecord }){\n  window.Next.Message.show(JSON.stringify({ rowKey, rowIndex, rowRecord }))\n}\n```\n保存。预览时我们可以看到效果了：\n![Feb-23-2022 12-05-25.gif](https://img.alicdn.com/imgextra/i3/O1CN01CXi1zJ1N302paKUre_!!6000000001513-1-tps-1532-790.gif)\n## 研究本例的 schema\n\n我们把本例的 schema 保存在云端，您可以自行下载研究：[https://mo.m.taobao.com/marquex/lowcode-showcase-table](https://mo.m.taobao.com/marquex/lowcode-showcase-table)\n\n您可以通过左下角的 Schema 面板直接导入本例子的 Schema。\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01z2LXgW1iFSklNRzTN_!!6000000004383-2-tps-3054-1620.png)\n"
  },
  {
    "path": "docs/docs/demoUsage/panels/_category_.json",
    "content": "{\n  \"label\": \"面板详解\",\n  \"position\": 2,\n  \"collapsed\": false,\n  \"collapsible\": false\n}\n"
  },
  {
    "path": "docs/docs/demoUsage/panels/canvas.md",
    "content": "---\ntitle: 5. 画布详解\nsidebar_position: 1\n---\n## 组件操作\n### 画布操作\n点击组件在右侧面板中能够显示出对应组件的属性配置选项\n![Dec-17-2021 19-28-28.gif](https://img.alicdn.com/imgextra/i1/O1CN01flb5tL1inM47Gdo3a_!!6000000004457-1-tps-1468-754.gif)\n\n拖拽修改组件的排列顺序\n![Dec-17-2021 19-29-40.gif](https://img.alicdn.com/imgextra/i3/O1CN01UJ1x731NBFB4eELV0_!!6000000001531-1-tps-1468-754.gif)\n\n拖拽时会在右侧提示当前的组件树。\n![Dec-17-2021 19-31-30.gif](https://img.alicdn.com/imgextra/i1/O1CN01jLUYQE1h4dmcfYhZB_!!6000000004224-1-tps-1468-754.gif)\n\n### 组件控制\n点击组件右上角的复制按钮，或者按下 `ctrl + c` 再按下 `ctrl + v`，可以将其复制；\n点击组件右上角的删除按钮，或者直接使用 `Delete` 键，可以将其删除。\n![Dec-17-2021 19-33-20.gif](https://img.alicdn.com/imgextra/i2/O1CN01QT1pq621gvCVpoOm6_!!6000000007015-1-tps-1468-754.gif)\n\n### 选择组件切换\n\n可以用键盘上的按键切换组件选择：\n\n- `↑` 向上选择组件\n- `↓` 向下选择组件\n- `←` 向左选择组件\n- `→` 向右选择组件\n\n可以 hover 到组件操作辅助区的第一项来选中组件的父级节点：\n![Feb-22-2022 14-42-30.gif](https://img.alicdn.com/imgextra/i4/O1CN01RWbgGJ1TM8HoOpQ7V_!!6000000002367-1-tps-1536-790.gif)\n\n### 可扩展项简述\n\n快捷键、操作辅助区均可扩展。\n\n## Slot 区块\n\nReact 中，可以定义一个 prop 选项为 `JSXElement` 或 `(...args) => JSXElement` 的形式，这个形式在低代码画布中，被定义为 Slot，允许往其内部拖入组件，进行符合直觉的操作。\n![Feb-22-2022 14-46-02.gif](https://img.alicdn.com/imgextra/i4/O1CN01geivkn1csUog5gZbm_!!6000000003656-1-tps-1534-790.gif)\n\n### 锁定 Slot\n\n您可以对 Slot 进行锁定操作，锁定后内部内容无法选中；\n![Feb-22-2022 14-50-03.gif](https://img.alicdn.com/imgextra/i3/O1CN01eBD3WY1rPNsZt8UVL_!!6000000005623-1-tps-1534-790.gif)\n\n在组件树可以解除操作。\n\n## 组件编辑态\n\n低代码引擎允许组件在编辑状态下表现得和渲染时不一样。Demo 中的布局组件就是用对应 API 完成布局的高级操作的。\n\n它背后的实现有两种方法：\n\n- 侵入型：组件编辑态下，会往组件内传入 `__designMode: 'design'`，可以在组件中进行相应处理；\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01Xh3o891gvTrNBMMy2_!!6000000004204-2-tps-3066-1642.png)\n\n- 双入口型：通过配置物料的 editUrls，加载专属于编辑态组件的物料。pro-layout 使用的是这种方式\n```json\n    {\n      \"package\": \"@alifd/pro-layout\",\n      \"version\": \"1.0.1-beta.6\",\n      \"library\": \"AlifdProLayout\",\n      \"urls\": [\n        \"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/dist/AlifdProLayout.js\",\n        \"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/dist/AlifdProLayout.css\"\n      ],\n      \"editUrls\": [\n        \"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/build/lowcode/view.js\",\n        \"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/build/lowcode/view.css\"\n      ]\n    }\n```\n"
  },
  {
    "path": "docs/docs/demoUsage/panels/code.md",
    "content": "---\ntitle: 7. 源码面板详解\nsidebar_position: 3\n---\n在源码面板中，您可以完成低代码中的代码部分编写。\n\n## 面板功能拆解\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01pRxmmD1agTBVwCO5x_!!6000000003359-2-tps-2502-1740.png)\n\n### 代码编辑面板\n\n代码编辑面板允许您书写 JavaScript 代码，并支持 JSX 语法。\n由于依赖了 Babel，所以书写的 JSX 和 Chrome 80+ 以后的新语法也会被自动编译：\n\n| 编译前 | 编译后 |\n| --- | --- |\n| ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01xI9RVX1yV46HbW02H_!!6000000006583-2-tps-670-190.png) | ![image.png](https://img.alicdn.com/imgextra/i1/O1CN012exYQL1y37wKM7VFT_!!6000000006522-2-tps-2094-110.png) |\n| ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01pK2rPi1lhLij4m3o7_!!6000000004850-2-tps-434-120.png) | ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01ti4n9m1ihOupktQow_!!6000000004444-2-tps-2536-120.png) |\n\n\n> 注：因为编译结果会被 `@babel/runtime` 干扰，目前面板不支持 `async await`或 `{ ...arr }` 形态的语法编译。如果您需要此类编译，您可以考虑在读取 schema 中的 `originCode` 之后自己手动通过 babel 编译。\n\n\n#### 全局变量引用\n\n在代码中，您可以通过 window 来引用全局变量。资产包中的 packages 都是通过 UMD 方式引入的对应内容，如果您引入了 Fusion Next（Demo 中默认引入），那么可以通过此方法直接唤起 Fusion Next 的内容，如弹窗提示：\n```typescript\nwindow.Next.Message.success('成功')\n```\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01Fxjd801p4eigEBpb6_!!6000000005307-2-tps-238-114.png)\n\n#### 局部变量引用\n\n您可以在成员函数中访问到如下变量：\n\n- `this.state`\n- `this.setState`\n- `this.context.appHelper.utils`\n- `this.context.appHelper.constants`\n- `this.context.appHelper.requestHandlerMap`\n- `this.context.components`\n\n#### 读、写与异常处理\n\n- 读取：每次打开面板时，都会尝试读取 schema 中的 originCode 字段，如果没有，则从 schema 上的字段还原代码；\n- 写入：在关闭代码编辑面板（主动点击叉或者点击非代码编辑区块的被动关闭都算）时，将自动写入到 schema 中；您也可以在编辑过程中点击“保存”按钮手动保存；\n\n| 源码面板中 | Schema 中 |\n| --- | --- |\n| 本地数据初始值设置：![image.png](https://img.alicdn.com/imgextra/i4/O1CN01V6iaTY1gVNHi7gQfK_!!6000000004147-2-tps-370-146.png) | ![image.png](https://img.alicdn.com/imgextra/i2/O1CN010rhIPa268BEfGmzO6_!!6000000007616-2-tps-2098-826.png) |\n| 生命周期方法：![image.png](https://img.alicdn.com/imgextra/i4/O1CN010Y1TxV1QOvrVLRUjD_!!6000000001967-2-tps-478-260.png) | ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01pbJzVQ1VSfAL7Lh8G_!!6000000002652-2-tps-2010-836.png) |\n| 自定义函数：![image.png](https://img.alicdn.com/imgextra/i4/O1CN01S2gjFk1CU3fm61eiD_!!6000000000083-2-tps-660-642.png) | ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01X35YxU1GUkjj1YWVj_!!6000000000626-2-tps-1862-822.png) |\n| 编译前全量代码：![image.png](https://img.alicdn.com/imgextra/i2/O1CN01sbiK9N1kc1Uxp1OHY_!!6000000004703-2-tps-762-1122.png) | ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01adKSg61QXAzRjQ4bm_!!6000000001985-2-tps-1906-796.png) |\n\n\n- 异常处理：如果代码解析失败，它将无法被正常保存到 schema 中，此时编辑器会弹层提示：\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01aSzh8o26rWRu6zXFE_!!6000000007715-2-tps-3068-1638.png)\n\n### 样式编辑面板\n\n您可以在这里书写 CSS 内容。它对应 schema 中的 css 字段：\n\n| 源码面板中 | Schema 中 |\n| --- | --- |\n| ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01cuWt4L27fRcW5WIP9_!!6000000007824-2-tps-634-388.png) | ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01Edu7Gy1MzKsb2iss8_!!6000000001505-2-tps-1646-582.png) |\n\n\n## 对接代码\n\n### 生命周期对接\n如果您书写了视图相关的声明周期方法，那么对应的方法会在视图的特定周期被调用。支持的生命周期函数在《阿里巴巴中后台前端搭建协议规范》中被定义，包含：\n```typescript\n{\n  componentDidMount(): void;\n  constructor(props: Record<string, any>, context: any);\n  render(): void;\n  componentDidUpdate(prevProps: Record<string, any>, prevState: Record<string, any>, snapshot: Record<string, any>): void;\n  componentWillUnmount(): void;\n  componentDidCatch(error: Error, info: any): void;\n}\n```\n\n### 设置器面板对接\n\n书写完了函数 / state 后，您可以在右侧的设置器面板中配置对代码的部分。\n\n通常书写代码是为了对接低代码配置中的“变量绑定”、“事件回调”、“条件判断”和“循环”部分的。\n\n#### 变量绑定\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01wcgwOI1wOXDtgfrgD_!!6000000006298-2-tps-2738-1464.png)\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01GYVAw41FlrvEyFcCO_!!6000000000528-2-tps-1528-1166.png)\n```json\n{\n  \"componentName\": \"NextBlockCell\",\n  \"id\": \"node_ockzmje8tf5\",\n  \"props\": {\n    \"bodyPadding\": {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.state.text\",\n      \"mock\": \"\"\n    }\n  }\n}\n```\n\n\n#### 事件回调\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01B0tvgw1O6x58dbbIb_!!6000000001657-2-tps-2734-1452.png)\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01sD9g2n1tQQ0OjQkcY_!!6000000005896-2-tps-1670-1162.png)\n```json\n{\n  \"componentName\": \"Filter\",\n  \"id\": \"node_ockzmj0cl11w\",\n  \"props\": {\n    \"__events\": {\n      \"eventDataList\": [\n        {\n          \"type\": \"componentEvent\",\n          \"name\": \"onSearch\",\n          \"relatedEventName\": \"closeDialog\"\n        }\n      ]\n    },\n    \"onSearch\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function(){this.onSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n    }\n  }\n}\n```\n\n#### 条件判断\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01zXqec823EBaCutOY2_!!6000000007223-2-tps-2738-1452.png)\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01Ze3snL24BGfuRIMCl_!!6000000007352-2-tps-1528-1166.png)\n```json\n{\n  \"componentName\": \"Filter\",\n  \"id\": \"node_ockzmj0cl11w\",\n  \"condition\": {\n    \"type\": \"JSExpression\",\n    \"value\": \"this.state.text\",\n    \"mock\": true\n  }\n}\n```\n\n#### 循环\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01Kbj6XP297fe0BvhKz_!!6000000008021-2-tps-2746-1460.png)\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN018Ogesd1qnN0IOKRDZ_!!6000000005540-2-tps-1528-1166.png)\n```json\n{\n  \"componentName\": \"Filter\",\n  \"id\": \"node_ockzmj0cl11w\",\n  \"loop\": {\n    \"type\": \"JSExpression\",\n    \"value\": \"this.state.text\",\n    \"mock\": true\n  }\n}\n```\n"
  },
  {
    "path": "docs/docs/demoUsage/panels/component.md",
    "content": "---\ntitle: 4. 组件面板详解\nsidebar_position: 0\n---\n## 概述\n组件面板顾名思义就是承载组件的面板，组件面板会获取并解析传入给低代码引擎的资产包数据 (数据结构[点此查看](https://lowcode-engine.cn/assets))，得到需要被展示的组件列表，并根据分类、排序规则对组件进行排列，同时也提供了搜索功能。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01a6xgwH1wCAWugmNvU_!!6000000006271-2-tps-3056-1672.png)\n## 组件信息\n组件面板承载的组件信息有：\n\n- 组件标题；\n- 组件截图；\n- 组件低代码 schema 片段；\n- 组件分组；\n- 组件分类；\n- 是否隐藏组件；\n- 关键词：关键词用于搜索，会聚合 name、title、description、keywords 等字段作为搜索匹配的目标；\n\n其中标题和截图是我们能够看到的，schema 片段则是拖拽到设计器时会自动插入页面 schema 中，面板会根据分组、分类来对组件进行排列；\n这些组件信息均通过资产包数据获取，字段对应关系如下图所示：\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN012ZUg6a289fl4z6WCm_!!6000000007890-2-tps-1326-1678.png)\n## 组件分组、分类排序\n组件面板会把相同分组的组件放在同一个 tab 下，相同分类的组件放在同一个 collapse 中，同时也支持对 tab 和 collapse 进行排序；\n由于是整体性的排序，组件自身的信息无法决定此排序，因此在资产包数据根节点新增了 sort 字段用于指定分组和分类的排序，具体定义在[《低代码引擎资产包协议规范》](https://lowcode-engine.cn/assets)2.4 sort 章节；\n\n| **根属性名称** | **类型** | **说明** | **变量支持** | **默认值** |\n| --- | --- | --- | --- | --- |\n| sort.groupList | String[] | 组件分组，用于组件面板 tab 展示 | - | ['精选组件', '原子组件'] |\n| sort.categoryList | String[] | 组件面板中同一个 tab 下的不同区间用 category 区分，category 的排序依照 categoryList 顺序排列 | - | ['通用', '数据展示', '表格类', '表单类'] |\n\n## 搜索\n组件面板会提取组件的 name、title、description、keywords 等字段作为搜索匹配的目标，因此除了能够通过组件名称、描述进行搜索外，还可以指定一些关键词-keywords，keywords 是数组也可以是字符串类型。\n"
  },
  {
    "path": "docs/docs/demoUsage/panels/datasource.md",
    "content": "---\ntitle: 8. 数据源面板详解\nsidebar_position: 4\n---\n## 🪚 概述\n数据源面板主要负责管理低代码中远程数据源内容，通过可视化编辑的方式操作低代码协议中的数据源 Schema，配合 [数据源引擎](/site/docs/guide/design/datasourceEngine) 即可实现低代码中数据源的生产和消费；\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN0170HeBg276B7fM9rqh_!!6000000007747-2-tps-2878-1642.png)\n\n数据源面板\n## ❓如何使用\n> 面板内包含了数据源创建、删除、编辑、排序、导入导出、复制以及搜索等能力，内置支持了 `fecth` & `JSONP`两种常用远程请求类型；\n\n### 三步创建一个数据源\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01bkgbqj1cOGfwQtEif_!!6000000003590-2-tps-2878-1638.png)\n三步创建数据源\n\n### 参数详解\n> TODO\n\n## ☠️ 更多介绍\n### 数据源顺序\n> 数据源为何支持排序功能，主要原因是数据源的加载存在先后顺序；接下来我们从协议层以及实现层看数据源之间的顺序关系；\n\nTODO\n### 如何定制数据源\n#### 定制数据源类型（设计态）\n#### 定制数据源请求实现（运行态）\n\n> 当出现以下两种情况的时，我们需要定制数据源请求实现，\n> - 当你默认提供的 `handler`无法满足你的需求\n> - 定制了数据源类型，比如 `GraphQL`，需要实现一个对应的 `handler`\n\n接下来我们来看一个例子，如何实现一个 `handler`\n\n```javascript\nimport { RuntimeOptionsConfig } from '@alilc/lowcode-datasource-types';\n\nimport request from 'universal-request';\nimport { RequestOptions, AsObject } from 'universal-request/lib/types';\n\nexport function createFetchHandler(config?: Record<string, unknown>) {\n  return async function(options: RuntimeOptionsConfig) {\n    const requestConfig: RequestOptions = {\n      ...options,\n      url: options.uri,\n      method: options.method as RequestOptions['method'],\n      data: options.params as AsObject,\n      headers: options.headers as AsObject,\n      ...config,\n    };\n    const response = await request(requestConfig);\n    return response;\n  };\n}\n```\n低代码 fetch-handler 默认实现\n\n以上代码是低代码内置的 fetch-handler 默认实现，内部使用了 `universal-request`，假如你们内部使用的 `axios`，你完全重新实现一个；\n```javascript\nimport axios from 'axios';\nexport function createAxiosFetchHandler(config?: Record<string, unknown>) {\n  return async function(options: RuntimeOptionsConfig) {\n    const requestConfig: RequestOptions = {\n      ...options,\n      url: options.uri,\n      method: options.method as RequestOptions['method'],\n      data: options.params,\n      headers: options.headers,\n      ...config,\n    };\n    const response = await axios(requestConfig);\n    return response;\n  };\n}\n```\n\n##### 注册到 render\n完成一个 Handler 后你可以通过以下方式接入到 render 或者出码中使用\n\n###### 渲染 Render\n```tsx\nimport React, { memo } from 'react';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\n\nconst SamplePreview = memo(() => {\n  return (\n    <ReactRenderer\n      className=\"lowcode-plugin-sample-preview-content\"\n      schema={schema}\n      components={components}\n      appHelper={{\n        requestHandlersMap: {\n          fetch: createAxiosFetchHandler()\n        }\n      }}\n    />\n  );\n});\n```\n###### 出码\n> 目前自定义只能通过重新定义类型来完成，接下来我们会给出码添加 requestHandlersMap 映射能力；如有需求请联系 荣彬 (github-id:xingmolu)\n\n\n###  设计态启用数据源引擎\n> 默认情况下设计态没有开启数据源引擎，我们可以在设计器 init 的时候来传递`requstHandlersMap`来开启；具体代码如下：\n\n```javascript\nimport { init, plugins } from '@alilc/lowcode-engine';\nimport { RequestHandlersMap } from '@alilc/lowcode-datasource-types';\n\nconst preference = new Map();\n\n(async function main() {\n  await plugins.register(scenarioSwitcher);\n  await registerPlugins();\n\n  init(document.getElementById('lce-container')!, {\n    // designMode: 'live',\n    // locale: 'zh-CN',\n    enableCondition: true,\n    enableCanvasLock: true,\n    // 默认绑定变量\n    supportVariableGlobally: true,\n    // simulatorUrl 在当 engine-core.js 同一个父路径下时是不需要配置的！！！\n    // 这里因为用的是 alifd cdn，在不同 npm 包，engine-core.js 和 react-simulator-renderer.js 是不同路径\n    simulatorUrl: [\n      'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@latest/dist/css/react-simulator-renderer.css',\n      'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@latest/dist/js/react-simulator-renderer.js'\n    ],\n    requestHandlersMap: {\n      fetch: createAxiosFetchHandler()\n    }\n  }, preference);\n})();\n\n```\n## 🥡 附录\n### 数据源协议\n| **参数** | **说明** | **类型** | **支持变量** | **默认值** | **备注** |\n| --- | --- | --- | --- | --- | --- |\n| id | 数据请求 ID 标识 | String | - | - |  |\n| isInit | 是否为初始数据 | Boolean | ✅ | true | 值为 true 时，将在组件初始化渲染时自动发送当前数据请求 |\n| isSync | 是否需要串行执行 | Boolean | ✅ | false | 值为 true 时，当前请求将被串行执行 |\n| type | 数据请求类型 | String | - | fetch | 支持四种类型：fetch/mtop/jsonp/custom |\n| shouldFetch | 本次请求是否可以正常请求 | (options: ComponentDataSourceItemOptions) => boolean | - | () => true | function 参数参考 [ComponentDataSourceItemOptions 对象描述](/site/docs/specs/lowcode-spec#2315-componentdatasourceitemoptions-对象描述) |\n| willFetch | 单个数据结果请求参数处理函数 | Function | - | options => options | 只接受一个参数（options），返回值作为请求的 options，当处理异常时，使用原 options。也可以返回一个 Promise，resolve 的值作为请求的 options，reject 时，使用原 options |\n| requestHandler | 自定义扩展的外部请求处理器 | Function | - | - | 仅 type=‘custom’时生效 |\n| dataHandler | request 成功后的回调函数 | Function | - | response => response.data | 参数：请求成功后 promise 的 value 值 |\n| errorHandler | request 失败后的回调函数 | Function | - | - | 参数：请求出错 promise 的 error 内容 |\n| options {} | 请求参数 | **ComponentDataSourceItemOptions**| - | - | 每种请求类型对应不同参数，详见见 [ComponentDataSourceItemOptions 对象描述](/site/docs/specs/lowcode-spec#2315-componentdatasourceitemoptions-对象描述) |\n\n### 运行时实现层：数据源引擎设计\n[数据源引擎设计](/site/docs/guide/design/datasourceEngine)\n"
  },
  {
    "path": "docs/docs/demoUsage/panels/settings.md",
    "content": "---\ntitle: 6. 设置面板详解\nsidebar_position: 2\n---\n# 设置器介绍\n## 展示区域\n设置器，又称为 Setter，主要展示在编辑器的右边区域，如下图：\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01jN0toi1OknXWrPuYt_!!6000000001744-2-tps-3836-1730.png)\n其中包含 属性、样式、事件、高级\n\n- 属性：展示该物料常规的属性\n- 样式：展示该物料样式的属性\n- 事件：如果该物料有声明事件，则会出现事件面板，用于绑定事件。\n- 高级：两个逻辑相关的属性，**条件渲染**和**循环**\n\n\n\n## 设置器\n上述区域中是有多项设置器的，对于一个组件来说，每一项配置都对应一个设置器，比如我们的配置是一个文本，我们需要的是文本设置器，我们需要配置的是数字，我们需要的就是数字设置器。\n下图中的标题和按钮类型配置就分别是文本设置器和下拉框设置器。\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01Bl2hgm1GiUcXD3TOO_!!6000000000656-2-tps-2120-1460.png)\n我们提供了常用的设置器作为内置设置器，也提供了定制能力帮助大家开发特定需求的设置器。\n# 内置设置器\n| **预置 Setter** | **用途** |\n| --- | --- |\n| StringSetter | 短文本型数据设置器，不可换行 |\n| NumberSetter | 数值型数据设置器， |\n| BoolSetter | 布尔型数据设置器， |\n| SelectSetter | 枚举型数据设置器，采用下拉的形式展现 |\n| VariableSetter | 变量型数据设置器， |\n| RadioGroupSetter | 枚举型数据设置器，采用 tab 选择的形式展现 |\n| TextAreaSetter | 长文本型数据设置器，可换行 |\n| DateSetter | 日期型数据设置器 |\n| TimePicker | 时间型数据设置器 |\n| DateYearSetter | 日期型 - 年数据设置器 |\n| DateMonthSetter | 日期型 - 月数据设置器 |\n| DateRangeSetter | 日期型数据设置器，可选择时间区间 |\n| EventsSetter | 事件绑定设置器 |\n| ColorSetter | 颜色设置器 |\n| JsonSetter | json 型数据设置器 |\n| StyleSetter | 样式设置器 |\n| ClassNameSetter | 样式名设置器 |\n| FunctionSetter | 函数型数据设置器 |\n| MixedSetter | 混合型数据设置器 |\n| SlotSetter | 节点型数据设置器 |\n| ArraySetter | 列表数组行数据设置器 |\n| ObjectSetter | 对象数据设置器，一般内嵌在 ArraySetter 中 |\n\n\n# 设置器定制\n## 编写 AltStringSetter\n我们编写一个简单的 Setter，这里我们编写的 Setter 是 AltStringSetter。代码如下：\n```javascript\nimport * as React from \"react\";\nimport { Input } from \"@alifd/next\";\n\nimport \"./index.scss\";\ninterface AltStringSetterProps {\n  // 当前值\n  value: string;\n  // 默认值\n  defaultValue: string;\n  // setter 唯一输出\n  onChange: (val: string) => void;\n  // AltStringSetter 特殊配置\n  placeholder: string;\n}\nexport default class AltStringSetter extends React.PureComponent<AltStringSetterProps> {\n  componentDidMount() {\n    const { onChange, value, defaultValue } = this.props;\n    if (value == undefined && defaultValue) {\n      onChange(defaultValue);\n    }\n  }\n\n  // 声明 Setter 的 title\n \tstatic displayName = 'AltStringSetter';\n\n  render() {\n    const { onChange, value, placeholder } = this.props;\n    return (\n      <Input\n        value={value}\n        placeholder={placeholder || \"\"}\n        onChange={(val: any) => onChange(val)}\n      ></Input>\n    );\n  }\n}\n```\n\n### setter 和 setter/plugin 之间的联动\n我们采用 emit 来进行相互之前的通信，首先我们在 A setter 中进行事件注册：\n```javascript\nimport { event } from '@ali/lowcode-engine';\n\ncomponentDidMount() {\n\t\t// 这里由于面板上会有多个 setter，这里我用 field.id 来标记 setter 名\n    this.emitEventName = `${SETTER_NAME}-${this.props.field.id}`;\n    event.on(`${this.emitEventName}.bindEvent`, this.bindEvent)\n}\n\nbindEvent = (eventName) => {\n  // do someting\n}\n\ncomponentWillUnmount() {\n  // setter 是以实例为单位的，每个 setter 注销的时候需要把事件也注销掉，避免事件池过多\n  event.off(`${this.emitEventName}.bindEvent`, this.bindEvent)\n}\n```\n在 B setter 中触发事件，来完成通信：\n```javascript\nimport { event } from '@ali/lowcode-engine';\n\nbindFunction = () => {\n  const { field, value } = this.props;\n  // 这里展示的和插件进行通信，事件规则是插件名 + 方法\n  event.emit('eventBindDialog.openDialog', field.name, this.emitEventName);\n}\n```\n### 修改同级 props 的其他属性值\nsetter 本身只影响其中一个 props 的值，如果需要影响其他组件的 props 的值，需要使用 field 的 props：\n```javascript\nbindFunction = () => {\n    const { field, value } = this.props;\n    const propsField = field.parent;\n\t\t// 获取同级其他属性 showJump 的值\n    const otherValue = propsField.getPropValue('showJump');\n    // set 同级其他属性 showJump 的值\n    propsField.setPropValue('showJump', false);\n}\n```\n## 注册 AltStringSetter\n我们需要在低代码引擎中注册 Setter，这样就可以通过 AltStringSetter 的名字在物料中使用了。\n```javascript\nimport AltStringSetter from './AltStringSetter';\nimport { setters } from '@alilc/lowcode-engine';\nsetters.registerSetter({\n\tAltStringSetter: {\n\t\tcomponent: AltStringSetter,\n\t}\n});\n```\n## 物料中使用\n我们需要将目标组件的属性值类型值配置到物料资源配置文件中，例如 `packages/demo/public/assets.json` \n其中核心配置如下：\n```json\n{\n  \"props\": {\n    \"isExtends\": true,\n    \"override\": [\n      {\n        \"name\": \"type\",\n        \"setter\": \"AltStringSetter\"\n      }\n    ]\n  }\n}\n```\n在物料中的完整配置如下：\n```json\n{\n  \"componentName\": \"Message\",\n  \"title\": \"Message\",\n  \"docUrl\": \"\",\n  \"screenshot\": \"\",\n  \"npm\": {\n    \"package\": \"@alifd/next\",\n    \"version\": \"1.19.18\",\n    \"exportName\": \"Message\",\n    \"main\": \"src/index.js\",\n    \"destructuring\": true,\n    \"subName\": \"\"\n  },\n  \"props\": [\n    {\n      \"name\": \"title\",\n      \"propType\": \"string\",\n      \"description\": \"标题\",\n      \"defaultValue\": \"标题\"\n    },\n    {\n      \"name\": \"type\",\n      \"propType\": {\n        \"type\": \"oneOf\",\n        \"value\": [\n          \"success\",\n          \"warning\",\n          \"error\",\n          \"notice\",\n          \"help\",\n          \"loading\"\n        ]\n      },\n      \"description\": \"反馈类型\",\n      \"defaultValue\": \"success\"\n    }\n\n  ],\n\n  \"configure\": {\n    \"props\": {\n      \"isExtends\": true,\n      \"override\": [\n        {\n          \"name\": \"type\",\n          \"setter\": \"AltStringSetter\"\n        }\n      ]\n    }\n  }\n}\n```\n###\n# 小结\n本章介绍了设置器是什么，我们有哪些内置的设置器。以及当不满足设置器诉求时，我们如何定制一个设置器。\n"
  },
  {
    "path": "docs/docs/faq/faq001.md",
    "content": "---\ntitle: build-scripts 的使用文档\nsidebar_position: 1\ntags: [FAQ]\n---\nbuild-scripts 是一个开源项目，详见 [https://github.com/ice-lab/build-scripts](https://github.com/ice-lab/build-scripts)\n"
  },
  {
    "path": "docs/docs/faq/faq002.md",
    "content": "---\ntitle: 渲染唯一标识（key）\nsidebar_position: 2\ntags: [FAQ]\n---\n渲染唯一标识（key）和 React 中组件的 key 属性的原理是一致的，都是为了在渲染场景或者组件切换的场景中唯一标识一个组件。\n\n你可以在组件右侧配置面板的「高级」中看到此配置项，该配置项一般配合「是否渲染」和「循环」功能使用。\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01wU7y30232jgLlfzRe_!!6000000007198-2-tps-560-696.png)\n\n## 以下场景必需设置「渲染唯一标识」\n#### 场景一：同类组件切换\n以下场景中，当「爱好」选择「游戏」时显示「最喜欢的游戏」，选择「运动」时显示「最喜欢的运动」\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN016qHhJB1XWRfUJsml7_!!6000000002931-2-tps-1560-588.png)\n\n配置方式如下：\n\n1. 增加变量数据源：hobby\n2. 「最喜欢的游戏」表单标识设置为 game，「是否渲染」绑定变量「state.hobby === '游戏'」\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01oOemw41d0HY3qpwum_!!6000000003673-2-tps-2164-738.png)\n\n3. 「最喜欢的运动」表单标识设置为 sport，「是否渲染」绑定变量「state.hobby === '运动'」\n4. 「爱好」设置 onChange 动作\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01oH4Giy1GTpwZwVSrO_!!6000000000624-2-tps-892-194.png)\n\n5. 「提交」按钮绑定 onClick 动作\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN016kkf3O1uj1i9ev7uy_!!6000000006072-2-tps-750-134.png)\n\n按以上配置（不配置渲染唯一标识），确实可以实现切换爱好时下方的文本框切换，但在提交数据时会发现，即使选择了「运动」，提交的时候 sport 字段是「最喜欢的游戏」的值。\n\n原因：在进行文本框组件切换时，由于没有设置 key，底层会「复用」切换之前的组件\n\n以上场景只需要给两个组件配置「渲染唯一标识」即可。\n"
  },
  {
    "path": "docs/docs/faq/faq003.md",
    "content": "---\ntitle: 点击事件如何添加参数\nsidebar_position: 3\ntags: [FAQ]\n---\n背景：\n\n- [Antd Table 下 button 点击事件怎么拿到行数据？](https://github.com/alibaba/lowcode-engine/issues/341)\n## 方式 1\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01i58EGG1bxFJBdlS6x_!!6000000003531-2-tps-3342-1126.png)\n\n参考 fusion protable，将操作列直接耦合 button 组件，因为 col.render 函数能拿到 行数据 record，那么 pro-table 组件封装的时候，就可以在渲染操作列按钮的时候，将 col.render 参数透传给 button 组件\n\n## 方式 2\nslot + 扩展参数\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01pQk2RC1WBXyxjNDif_!!6000000002750-2-tps-3284-1148.png)\n\n将扩展参数写成：\n```json\n{\n  record: this.record,\n  index: this.index\n}\n```\n\n那事件处理函数的第二个参数即可得到：\n```json\nonClick_new_new(...args){\n  console.log(args)\n}\n```\n"
  },
  {
    "path": "docs/docs/faq/faq004.md",
    "content": "---\ntitle: 最小渲染单元配置\nsidebar_position: 4\ntags: [FAQ]\n---\n## 背景\n在低代码引擎画布中，每一个节点的更新是**增量更新**机制。也就是通过 API 监听到组件的参数配置变化的时候，只更新该节点。\n\n一些场景下，父组件需要在子组件的属性变化，获取新的子组件的属性值，也就是从父组件开始渲染。\n例如：父组件需要强制修改 children props 值。示例代码如下：\n```\nReact.Children.forEach(children, (child: React.ReactElement) => {\n  // 子元素的参数只有 behavior，且 behavior 为 'READONLY';\n\tconst newChild = React.cloneElement(child, {\n  \tbehavior: 'READONLY'\n  });\n})\n```\n\n**对于这种场景，需要配置其为“最小渲染单元”****。**即：\n> **最小渲染单元下的组件渲染和更新都从单元的根节点开始渲染和更新。如果嵌套了多层最小渲染单元，渲染会从最外层的最小渲染单元开始渲染。**\n\n\n### 组件能力配置 component\n| **字段** | **用途** | **类型** |\n| --- | --- | --- |\n| isContainer(A) | 是否容器组件 | Boolean |\n| **isMinimalRenderUnit** | **默认值：false**\n**是否是最小渲染单元** | **Boolean** |\n| ... |  |  |\n\n#### 配置示例\n##### 标准配置文件\nconfigure.component.isMinimalRenderUnit\n```json\n{\n    \"componentName\": \"Table\",\n    \"title\": \"表格\",\n    \"category\": \"数据展示\",\n    \"props\": [],\n    \"configure\": {\n        \"supports\": {\n        },\n        \"props\": [],\n        \"component\": {\n            // 添加如下配置\n            \"isMinimalRenderUnit\": true\n        },\n        \"combined\": []\n    },\n    \"snippets\": [],\n    \"npm\": {}\n}\n```\n## 更新机制说明\n\n1. 没有任何组件被标识为**最小渲染单元**，则是每个组件都伴随自身属性变更而重新渲染；\n2. 将根组件标识为**最小渲染单元**，则是整个页面重新渲染；\n3. 组件树的分支节点被标识为**最小渲染单元**，则分支节点之下（包括自身）节点属性变更，触发分支节点整体的重新渲染；（若有多个**最小渲染单元**在同一条路径上，从最外层的**最小渲染单元**开始渲染）\n"
  },
  {
    "path": "docs/docs/faq/faq005.md",
    "content": "---\ntitle: 如何通过 this.utils 使用第三方工具扩展\nsidebar_position: 5\ntags: [FAQ]\n---\n## 设计器\n### 通过引擎 API 配置\n[API-init](/site/docs/api/init)\n\n### 通过资产包\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01WWJVSA1WutBvCzXnl_!!6000000002849-2-tps-806-788.png)\n\n就可以在引擎代码中访问到 moment\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01EEJ0Kp1nZgJm68nSG_!!6000000005104-2-tps-1248-252.png)\n\nPS：需要在 packages 中有相关的资源配置，例如：\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01bdiHVv206uRYvvAAr_!!6000000006801-2-tps-1322-420.png)\n\n否则在画布中可能会访问不到对应的资源。\n\n## 预览态\n[参考资料](/site/docs/guide/expand/runtime/renderer#apphelper)\n"
  },
  {
    "path": "docs/docs/faq/faq006.md",
    "content": "---\ntitle: 如何通过 API 手动调用数据源请求\nsidebar_position: 6\ntags: [FAQ]\n---\n参考：[DataSource API](/site/docs/demoUsage/appendix/api)"
  },
  {
    "path": "docs/docs/faq/faq007.md",
    "content": "---\ntitle: 设置面板中的高级 tab 如何配置\nsidebar_position: 7\ntags: [FAQ]\n---\n![93DC003C-D9A1-4F4F-98A1-F22C0A89EA92.png](https://img.alicdn.com/imgextra/i4/O1CN01lVutr6243wL6gOQAc_!!6000000007336-2-tps-960-1714.png)\n\n默认这个 tab 下的内容为引擎内置，如需要定制，可以使用以下 API\n[https://lowcode-engine.cn/site/docs/api/material#物料元数据管道函数](https://lowcode-engine.cn/site/docs/api/material#物料元数据管道函数)\n"
  },
  {
    "path": "docs/docs/faq/faq008.md",
    "content": "---\ntitle: 某某 npm 包对应的源码在哪里？\nsidebar_position: 8\ntags: [FAQ]\n---\n\n详见 [NPM 包对应源码位置汇总](/site/docs/guide/appendix/npms)"
  },
  {
    "path": "docs/docs/faq/faq009.md",
    "content": "---\ntitle: 物料出现 Component Not Found 相关报错\nsidebar_position: 9\ntags: [FAQ]\n---\n## 预览态，antd 资产包按顺序加载，但是没有按顺序执行\n资产包按顺序加载，但是没有按顺序执行，导致部分 js 执行的时候，依赖的资源没有准备好，报错了。\n传给  @alilc/lowcode-react-renderer 的 components 值为空。\n\n**解决方案**\nLowCodeEngine 升级到 1.0.8\n> 相关 PR：[https://github.com/alibaba/lowcode-engine/pull/383](https://github.com/alibaba/lowcode-engine/pull/383)\n\n\n## 编辑态，snippets 和注入组件不对应\n1.在控制台中输入\n```json\nAliLowCodeEngine.material.componentsMap\n```\n查看物料配置是否正常。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01bAsPoT1QOTSp7Fmz5_!!6000000001966-2-tps-1640-816.png)\n\n如果正常继续。\nLowCodeEngine 需要升级到 1.0.10\n```json\nAliLowCodeEngine.project.simulator.renderer.components\n```\n看看对应的物料是否存在，如果不存在，排查物料问题。\n\n如果不正常，查看资产包配置，其中资产包中的 `components` 和 `material.componentsMap` 生成有关系。\n\n例如，物料配置信息在 @alilc/lowcode-materials 包里面，即需要在 components 中加上下面的代码\n\n```javascript\n\"components\": [{\n  \"exportName\": \"AlilcLowcodeMaterialsMeta\",\n  \"npm\": {\n    \"package\": \"@alilc/lowcode-materials\"\n  },\n  \"url\": \"https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.7/build/lowcode/meta.js\",\n  \"urls\": {\n    \"default\": \"https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.7/build/lowcode/meta.js\",\n    \"design\": \"https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.7/build/lowcode/meta.design.js\"\n  }\n}]\n```\n\n`material.componentsMap` 不存在相关的组件信息，原因有两个：\n- 没有添加对应的物料到 components 字段中\n- components 配置不正确，需要查看 url 是否正常加载，查看 exportName 是否配置正确，即 `window.${exportName}` 是否存在。\n\n2.选中组件，在控制台中输入\n```json\nAliLowCodeEngine.project.currentDocument.selection.getNodes()[0].exportSchema('render')\n```\n查看 componentName 是否匹配。\n\n3.调用 rerender 方法\n```json\nAliLowCodeEngine.project.simulator.rerender()\n```\n看一下问题是否恢复。\n\n## 排查物料问题\n找到对应组件的资产包，比如下图的资产包。\n```json\n{\n  \"package\": \"@yingzhi8/lowcode-public-package\",\n  \"version\": \"0.1.2\",\n  \"library\": \"BizComps\",\n  \"urls\": [\n    \"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.js\",\n    \"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.css\"\n  ],\n  \"editUrls\": [\n    \"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/view.js\",\n    \"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/view.css\"\n  ],\n  \"advancedUrls\": {\n    \"default\": [\n      \"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.js\",\n      \"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.css\"\n    ]\n  },\n  \"advancedEditUrls\": {}\n}\n```\n\n### 查看 urls 是否加载\n通过查看控制台，看加载的 urls\n### library 配置是否正确\nlibrary 是可以在画布上访问到全局变量，确定  library 是否正确，在控制台输入：\n```json\nAliLowCodeEngine.project.simulator.contentWindow.${library}\n```\n"
  },
  {
    "path": "docs/docs/faq/faq010.md",
    "content": "---\ntitle: 插件面板如何调整位置\nsidebar_position: 10\ntags: [FAQ]\n---\n使用 index 配置来定义位置，内置的默认都是 0\n```json\nAliLowCodeEngine.skeleton.add({\n  area: 'leftArea',\n  type: 'PanelDock',\n  name: 'xxx',\n  content: () => 'xxx',\n  index: -1, // 使用 index 来定义位置，内置的默认都是 0\n  props: { icon: () => 'x' /* ReactElement 也可以 */ },\n});\n```\n这里设置 index 为负数，可以将其调整到第一的位置。\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01PTCH3r20fiXrrbcXe_!!6000000006877-2-tps-1614-1158.png)\n"
  },
  {
    "path": "docs/docs/faq/faq011.md",
    "content": "---\ntitle: 如何获取物料当前处于编辑态还是渲染态\nsidebar_position: 11\ntags: [FAQ]\n---\n## 简单场景\n可以利用 props.__designMode\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01btr66024FOEldBOr2_!!6000000007361-2-tps-1616-440.png)\n\n设计态中，__designMode 值为 \"design\"\n\n渲染态中，__designMode 没有设置值\n\n## 复杂场景\n在资产包里定义 editUrls\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01odal6P27Rhjn8NoJ6_!!6000000007794-2-tps-1590-538.png)\n\n### editUrls\n在 lowcode/xx/ 下新建一个 view.tsx\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01q0Bbn91Lrig7d0alA_!!6000000001353-2-tps-598-154.png)\n\n再执行\n```json\nnpm run lowcode:build\n```\n\n之后，build/lowcode 目录下既有 view.js，可作为 editUrls 配置在资产包中。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01dvIZ441alxwIlwexS_!!6000000003371-2-tps-1082-986.png)\n"
  },
  {
    "path": "docs/docs/faq/faq012.md",
    "content": "---\ntitle: Procode 物料如何调用数据源方法\nsidebar_position: 12\ntags: [FAQ]\n---\n## 解决方案\n给物料插入如下配置，可以默认给物料提供 reloadDataSource 的参数。\n```json\n{\n  title: {\n    label: {\n      type: 'i18n',\n      'en-US': 'reloadDataSource',\n      'zh-CN': 'reloadDataSource',\n    },\n  },\n  name: 'reloadDataSource',\n  setter: 'StringSetter',\n  initialValue: () => (\n    {\n      \"type\": \"JSFunction\",\n      \"value\": \"function(){ return this.reloadDataSource; }\"\n    }\n  ),\n},\n```\n\n在物料组件中，即可掉用如下代码来获取到相关方法。\n```json\nconst reloadDataSource = props.getReloadDataSource()\n```\n\n## FAQ\n### 希望该配置在配置面板中不展示\n在配置中加上\n```json\ncondition: () => false,\n```\n\n完整示例\n```json\n{\n  title: {\n    label: {\n      type: 'i18n',\n      'en-US': 'reloadDataSource',\n      'zh-CN': 'reloadDataSource',\n    },\n  },\n  name: 'reloadDataSource',\n  setter: 'StringSetter',\n  condition: () => false,\n  initialValue: () => (\n    {\n      \"type\": \"JSFunction\",\n      \"value\": \"function(){ return this.reloadDataSource; }\"\n    }\n  ),\n},\n```\n\n### 配置没有生效\n查看组件中的 schema，对应的配置是否已经正确设置。\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN015AGT4l1MwaVGGwgua_!!6000000001499-2-tps-1046-1154.png)\n\n没有正确设置上可能的原因是\n1.snippets 中没有默认值\n需要按照如下的代码中，加上默认的参数配置\n```json\nconst snippets: Snippet[] = [\n  {\n    title: 'Field',\n    screenshot: '',\n    schema: {\n      componentName: 'ProField',\n      props: {\n        type: 'textarea',\n        value: '我是测试',\n        getReloadDataSource: {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(){ return this.reloadDataSource; }\"\n        }\n      },\n    },\n  },\n];\n```\n\n### 如何全局生效\n通过 [registerMetadataTransducer API](/site/docs/api/material#registermetadatatransducer) 来修改元数据信息，注意如果有 snippets 相关配置也需要修改相关的配置。\n"
  },
  {
    "path": "docs/docs/faq/faq013.md",
    "content": "---\ntitle: Modal 类组件 hidden 属性被强制设置 true\nsidebar_position: 13\ntags: [FAQ]\n---\n## 注意\n弹窗的正确弹出方式请参考：[如何通过按钮展示/隐藏弹窗](/site/docs/demoUsage/makeStuff/dialog)\n## 问题原因\n由于 hidden 属性，导致 Modal 组件在预览的时候不渲染，也就无法获取到实例。\n## 处理方式\n### 【推荐】升级到 Engine Verison 1.0.11 以上\n### 新增 save propsReducer\n\n通过新增 Save 态的 propsReducer，将 hidden props 去掉。可以参考下面的代码：\n\n```typescript\nimport { project } from '@alilc/lowcode-engine';\nimport { IPublicEnumTransformStage } from '@alilc/lowcode-types';\n\nexport const deleteHiddenTransducer = (ctx: any) => {\n  return {\n    name: 'deleteHiddenTransducer',\n    async init() {\n      project.addPropsTransducer((props: any): any => {\n        delete props.hidden;\n        return props;\n      }, IPublicEnumTransformStage.Save);\n    },\n  };\n}\n\ndeleteHiddenTransducer.pluginName = 'deleteHiddenTransducer';\n\n```\n\n### 导出 schema 使用 Save 态\n```typescript\nimport { TransformStage } from '@alilc/lowcode-types';\n\nconst schema = project.exportSchema(TransformStage.Save)\n```\n"
  },
  {
    "path": "docs/docs/faq/faq014.md",
    "content": "---\ntitle: VERSION_PLACEHOLDER is not defined\nsidebar_position: 14\ntags: [FAQ]\n---\n# 问题原因\n由于 lowcode-engine 目前只提供 cdn 的使用方式。如果是自己创建的项目，遇到这个报错了，主要是因为将  npm 包打包进去了。\n\n# 解决方案\n\n## engine-demo 项目\n在项目的 externals 配置里加[一行配置](https://github.com/alibaba/lowcode-demo/blob/f8afad0df3190565caccc0a1dfd750dbf84c680f/build.json#L16)\n\n## 其他项目\n[相关文档](/site/docs/guide/create/useEditor#引入-umd-包资源)\n### webpack\n[https://webpack.docschina.org/configuration/externals/](https://webpack.docschina.org/configuration/externals/)\n\n### 使用文档\n待补充\n"
  },
  {
    "path": "docs/docs/faq/faq015.md",
    "content": "---\ntitle: 已有组件如何快速接入引擎\nsidebar_position: 15\ntags: [FAQ]\n---\n你可以通过在线工具「Parts 造物」生产物料描述协议，然后使用到你的项目中去。\n文档地址：[利用 Parts 造物快速使用 react 组件](/site/docs/guide/expand/editor/parts/partsIntro)\n"
  },
  {
    "path": "docs/docs/faq/faq016.md",
    "content": "---\ntitle: Cannot read property 'Icon' of Undefined\nsidebar_position: 16\ntags: [FAQ]\n---\n@alifd/next 是 React 画布下必须的资源，不能省略。\n需要在资产包中检查是否有下列代码：\n```typescript\n{\n  \"title\": \"fusion 组件库\",\n  \"package\": \"@alifd/next\",\n  \"version\": \"1.23.0\",\n  \"urls\": [\n    \"https://g.alicdn.com/code/lib/alifd__next/1.23.18/next.min.css\",\n    \"https://g.alicdn.com/code/lib/alifd__next/1.23.18/next-with-locales.min.js\"\n  ],\n  \"library\": \"Next\"\n},\n```\n"
  },
  {
    "path": "docs/docs/faq/faq017.md",
    "content": "---\ntitle: vue 画布支持说明\nsidebar_position: 17\ntags: [FAQ]\n---\n#### 低代码引擎官方是否支持 Vue 画布\n短期没有支持的计划\n\n#### 社区研发的 Vue 画布\n##### 肯耐珂萨团队实现的 Vue 画布\ngithub：[https://github.com/KNXCloud/lowcode-engine-vue](https://github.com/KNXCloud/lowcode-engine-vue)\n"
  },
  {
    "path": "docs/docs/faq/faq018.md",
    "content": "---\ntitle: 是否可以生成 Vue 页面代码？\nsidebar_position: 18\ntags: [FAQ]\n---\n低代码引擎在架构上是和具体语言无关的，通过一定的扩展和插件是可以生成 Vue 页面代码的。\n如果只是用现有的基于 React 的 fusion 物料来搭建，只是在最终出码的时候生成 Vue 页面代码，那您需要准备一套和 fusion 兼容的 vue 物料，并定制个出码方案，将[下面的一些出码插件](https://github.com/alibaba/lowcode-engine/blob/main/modules/code-generator/src/solutions/icejs.ts)替换成生成 Vue 框架的即可：\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01VxkwCL1l85DiDC2BO_!!6000000004773-2-tps-974-1368.png)\n详细定制方案可以参考下[《自定义出码》](/site/docs/guide/expand/runtime/codeGeneration#5自定义出码)。\n如果您希望在搭建的时候也使用 Vue 的物料，则还需要扩展定制入料、画布和渲染器等模块，详细方案请参考下[《扩展低代码编辑器》](/site/docs/guide/expand/editor/summary)\n"
  },
  {
    "path": "docs/docs/faq/faq019.md",
    "content": "---\ntitle: windows 下运行出现报错\nsidebar_position: 19\ntags: [FAQ]\n---\n由于阿里内部研发人员没有 windows 开发的诉求，windows 环境下相关的技术兼容短期内暂时没有支持计划。\n\n辛苦使用 [WSL](https://docs.microsoft.com/zh-cn/windows/wsl/install) 在 windows 下进行低代码引擎相关的开发。\n\n如果可以的话，欢迎大佬们提 PR 对 windows 开发环境进行兼容方面的支持。\n"
  },
  {
    "path": "docs/docs/faq/faq020.md",
    "content": "---\ntitle: Can't import the named export from non ECMAScript module\nsidebar_position: 20\ntags: [FAQ]\n---\n如果您是自己配置的引擎打包，那么可能会遇到这个问题。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN013xHmcz1WBXygt7VvC_!!6000000002750-2-tps-1912-984.png)\n\n问题的根源是 code-editor 插件运行时直接依赖了 babel 来完成 jsx 编译，babel 从 7.17.0 开始依赖了使用 ESM 编写的 @ampproject/remapping@2.1.0。如果打包工具无法正确处理 ESM，则可能报错。\n\n解决方案 1：锁定 babel 版本\n\n如果您使用了 yarn，那么可以在 package.json 中：\n\n```typescript\n\"resolutions\": {\n    \"@babel/core\": \"~7.16.7\",\n    \"@babel/parser\": \"~7.16.7\",\n    \"@babel/preset-env\": \"~7.16.7\",\n    \"@babel/preset-react\": \"~7.16.7\",\n    \"@babel/standalone\": \"~7.16.7\",\n    \"@babel/traverse\": \"~7.16.7\",\n    \"@babel/types\": \"~7.16.7\"\n}\n```\n\n解决方案 2：编译层面配置。本例使用 build-script 配置，您可以用类似方法来配置您的 webpack：\n\n```typescript\nmodule.exports = ({ onGetWebpackConfig }) => {\n  // see: https://github.com/ice-lab/build-scripts#%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91\n  onGetWebpackConfig((config) => {\n    config.module // fixes https://github.com/graphql/graphql-js/issues/1272\n      .rule('mjs$')\n      .test(/\\.mjs$/)\n      .include\n        .add(/node_modules/)\n        .end()\n      .type('javascript/auto');\n    return config;\n  });\n};\n```\n"
  },
  {
    "path": "docs/docs/faq/faq021.md",
    "content": "---\ntitle: 提交 PR 时，明明签署过 CLA，仍被提示需要签署\nsidebar_position: 21\ntags: [FAQ]\n---\n## 问题原因\n\n原因是：git commit 时，本地 git config 配置的 email 与 github 账号的 email 不一致，导致未被识别出来，检查方式\n\n```bash\ngit config user.email\n```\n\n## 解决办法\n\n如何配置，可参考 [is-it-possible-to-have-different-git-configuration-for-different-projects](https://stackoverflow.com/questions/8801729/is-it-possible-to-have-different-git-configuration-for-different-projects)\n\n配置好正确的 email 之后，已提交的代码需要以新的配置重新提交才可生效。"
  },
  {
    "path": "docs/docs/faq/faq022.md",
    "content": "---\ntitle: 节点无法拖拽到 Page 下\nsidebar_position: 22\ntags: [FAQ]\n---\n查看 Page 节点的 childWhitelist 配置，如果 Page 配置了 childWhitelist，且当前节点不在白名单下，是无法拖拽的。\n```typescript\nAliLowCodeEngine.material.getComponentMeta('Page').getMetadata().configure.component.nestingRule.childWhitelist\n```\n\n比如在 [demo](https://lowcode-engine.cn/demo/demo-general/index.html) 中 Page 组件的 childWhitelist 为：['NextPage', 'ProDialog', 'Dialog', 'Drawer']，则只有这些组件可以拖拽到 Page 的 children 下，其他组件均不可以。\n\n说明：1.0.15 之前 Page 组件的 childWhitelist 限制是失效的，在 1.0.16 版本进行了 bug 修复。\n\n### 解决办法\n**方法 1：直接修改 Page 组件的 childWhitelist，比如删除**。\n\n**方法 2：通过 **[**material.registerMetadataTransducer**](/site/docs/api/material#registermetadatatransducer)** 修改 Page 组件的 childWhitelist（适用于 Page 组件是其他人维护的）**\n"
  },
  {
    "path": "docs/docs/faq/faq023.md",
    "content": "---\ntitle: Slot组件渲染报错问题\nsidebar_position: 23\ntags: [FAQ]\n---\n\n## 问题描述\n在低代码引擎的页面渲染过程中，可能会遇到一个关于Slot组件的报错，提示“Slot找不到”。实际上，在渲染态时不应使用Slot组件。\n\n## 问题原因\n低代码引擎渲染分为两个状态：设计态和渲染态。\n- **设计态**：为了帮助插槽进行可视化设计，引入了Slot组件。\n- **渲染态**：在此状态下，不需要使用Slot组件。\n\n这个问题通常是因为在渲染态错误地使用了设计态的schema。\n\n## 解决方案\n1. **区分设计态和渲染态**：通过`project.exportSchema(TransformStage.Save)`的参数来区分。\n   - `TransformStage.Save`代表渲染态的schema，其中不包含Slot组件。\n   - 【默认值】`TransformStage.Render`代表设计态的schema，其中包含Slot组件。\n2. **使用正确的API和参数**：确保在渲染态使用正确的schema，避免引用设计态的Slot组件。\n3. **处理脏数据问题**：如果问题是由脏数据导致，清除数据并重新拖拽组件以恢复正常。\n\n## 注意事项\n- 确保在代码和配置中正确区分设计态和渲染态。\n- 如果遇到持续的问题，检查是否有脏数据或配置错误，并进行相应的清理和调整。\n\n## 相关链接\n- Issue链接：[Issue #1798](https://github.com/alibaba/lowcode-engine/issues/1798)\n\n---\n"
  },
  {
    "path": "docs/docs/faq/faq024.md",
    "content": "---\ntitle: workspace 模式常见问题\nsidebar_position: 23\ntags: [FAQ]\n---\n\n#### 如何判断是否开启了IDE模式？\n\n- **通过官方API判断**：您可以通过访问 [workspace.isActive](/site/docs/api/workspace#isactive) 来判断当前是否处于IDE模式。这是阿里低代码引擎提供的一个官方API，专门用于确认是否处于集成开发环境。\n\n\n\n#### 如何使用插件的ctx来做判断在哪个模式下？\n\n- **插件是否为应用级别**：可以通过 **ctx.isPluginRegisteredInWorkspace** 方法来判断一个插件是否是应用级别的插件。这有助于理解插件在阿里低代码引擎中的作用域和潜在的使用场景。\n- **插件的注册级别**：您可以使用 **ctx.registerLevel** 属性来判断插件处于哪个级别。插件级别的值包括：\n  - **Default**：默认级别。非 IDE 模式下的值\n  - **Workspace**：应用级别。\n  - **Resource**：资源级别。\n  - **EditorView**：编辑视图级别。 这些级别代表了插件可能的作用域和使用场景，有助于在开发和管理低代码应用时对插件进行更精确的控制和配置。\n\n\n\n#### 如何在IDE模式下设置资源列表？\n\n- **设置资源列表API**：在IDE模式下，可以通过访问 [workspace.setResourceList](/site/docs/api/workspace#setresourcelist) 来设置或更新IDE中的资源列表。这确保您在编辑器窗口中打开的资源是最新且可访问的。\n\n\n\n#### 如何打开视图窗口？\n\n- **使用推荐的方法**：使用 `openEditorWindow(resource: Resource, sleep?: boolean): Promise<void>;` 来打开视图窗口。这里的 **resource** 参数指的是您要打开的特定资源，可通过 [workspace.resourceList](/site/docs/api/workspace#resourcelist) 获取。\n- **不推荐使用的过时方法**：有一个过时的方法 `openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>;` 也用于打开视图窗口。虽然仍然可用，但官方不推荐使用此方法，并计划在后续版本中废弃，因为它在维护和可扩展性方面存在限制。\n\n\n\n#### 如何在全局插件中获取视图的上下文？\n\n- 在阿里低代码引擎的全局插件中获取视图的上下文，可以通过使用 **ProvideViewPluginContext** 函数实现。这个函数来自 **@alilc/lowcode-utils** 库，它使得您的 React 组件能够接收 **pluginContext** 作为 props，进而访问和操作当前视图的状态和属性。\n\n**步骤**\n\n**引入依赖**：首先，确保您的插件文件中已经引入了 **ProvideViewPluginContext** 以及其他必要的依赖。\n\n```\nimport { ProvideViewPluginContext } from '@alilc/lowcode-utils';\n```\n\n**定义 React 组件**：创建一个 React 组件，它将使用来自 **ProvideViewPluginContext** 的 **pluginContext**。\n\n```typescript\nconst MyComponent = (props) => {\n  const { pluginContext } = props;\n  // 组件逻辑\n  return <div>/* 组件内容 */</div>;\n};\n```\n\n**定义全局插件**：定义一个函数，这个函数会在插件被注册时调用。这个函数通常接受一个上下文对象 **ctx**，它提供了对引擎功能的访问。\n\n```javascript\nconst globalPlugin = (ctx) => {\n  const { skeleton } = ctx;\n\n  skeleton.add({\n    type: 'PanelDock',\n    name: 'datapool',\n    content: ProvideViewPluginContext((props) => {\n      // 组件内容\n      return (\n        <MyComponent {...props} />\n      )\n    }),\n    // 其他配置\n    contentProps: {\n      // 需要提供 pluginContext 作为参数\n      pluginContext: ctx,\n    }\n  });\n};\n```\n\n通过这些步骤，您的全局插件中的 React 组件就能够获取并使用视图的上下文了。这为您在插件中实现更复杂的功能和交互提供了基础。\n\n\n\n**注意事项**\n\n- **组件重渲染**：正常情况下，**pluginsContext** 是视图的上下文。当视图切换时，组件会重新渲染。如果需要在组件中处理视图切换导致的重新渲染，可以利用 React 的 **key** 属性。\n\n**示例代码**\n\n```typescript\nProvideViewPluginContext(props => {\n  return (\n    <DataPoolPane\n      {...props}\n      key={props.pluginContext?.editorWindow?.id}\n    );\n});\n```\n\n通过这种方式，当视图切换时，组件会根据视图的不同进行重新渲染，确保组件状态与当前视图的上下文保持一致。这对于在低代码平台上开发复杂插件和交互功能是非常有用的。\n\n\n\n#### 如何判断插件是否在 Workspace 模式下注册？\n\n**使用** **ctx.isPluginRegisteredInWorkspace()** **方法**:\n\n通过 **ctx.isPluginRegisteredInWorkspace()** 方法，可以判断一个插件是否在 Workspace 级别注册。以下是一个示例代码片段：\n\n```javascript\nif (ctx.isPluginRegisteredInWorkspace('pluginName')) {\n    console.log('插件已在 Workspace 模式下注册。');\n} else {\n    console.log('插件未在 Workspace 模式下注册。');\n}\n```\n\n注意：此方法目前在 beta 版本中，可能会有 TypeScript 提示显示已移除。\n\n**检查** **ctx.registerLevel** **的值**:\n\n可以通过比较 **ctx.registerLevel** 的值来判断插件的注册级别。示例代码如下：\n\n```javascript\nif (ctx.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace) {\n    console.log('插件未在 Workspace 模式下注册。');\n} else {\n    console.log('插件已在 Workspace 模式下注册。');\n}\n```\n"
  },
  {
    "path": "docs/docs/faq/index.md",
    "content": "---\ntitle: FAQ 概述\nsidebar_position: -1\ntags: [FAQ]\n---\n\n不定期将社区常见问题及答案维护到此处\n\n## Demo 使用\n- [渲染唯一标识（key）](/site/docs/faq/faq002)\n- [点击事件如何添加参数](/site/docs/faq/faq003)\n- [如何通过 API 手动调用数据源请求](/site/docs/faq/faq006)\n\n## 设计器定制\n- [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005)\n- [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007)\n- [插件面板如何调整位置](/site/docs/faq/faq010)\n- [workspace 模式常见问题](/site/docs/faq/faq024)\n\n## 源码和依赖\n- [某某 npm 包对应的源码在哪里？](/site/docs/faq/faq008)\n\n## 错误和报错\n- [物料出现 Component Not Found 相关报错](/site/docs/faq/faq009)\n- [VERSION_PLACEHOLDER is not defined](/site/docs/faq/faq014)\n- [Cannot read property 'Icon' of Undefined](/site/docs/faq/faq016)\n- [windows 下运行低代码引擎源码出现报错](/site/docs/faq/faq019)\n- [Can't import the named export from non ECMAScript module](/site/docs/faq/faq020)\n- [Slot组件渲染报错问题](/site/docs/faq/faq023)\n\n## 物料相关问题\n- [如何获取物料当前处于编辑态还是渲染态](/site/docs/faq/faq011)\n- [Procode 物料如何调用数据源方法](/site/docs/faq/faq012)\n- [已有组件如何快速接入引擎](/site/docs/faq/faq015)\n- [Modal 类组件 hidden 属性被强制设置 true](/site/docs/faq/faq013)\n- [最小渲染单元配置](/site/docs/faq/faq004)\n- [节点无法拖拽到 Page 下](/site/docs/faq/faq022)\n\n## 其他说明\n- [vue 画布支持说明](/site/docs/faq/faq017)\n- [是否可以生成 Vue 页面代码？](/site/docs/faq/faq018)\n\n## 参与贡献\n- [提交 PR 时，明明签署过 CLA，仍被提示需要签署](/site/docs/faq/faq021)\n\n## 相关依赖文档\n- [build-scripts 的使用文档](/site/docs/faq/faq001)\n"
  },
  {
    "path": "docs/docs/guide/appendix/_category_.json",
    "content": "{\n  \"label\": \"附录\",\n  \"position\": 5,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/guide/appendix/glossary.md",
    "content": "---\ntitle: 名词解释\nsidebar_position: 0\n---\n![glossary](https://img.alicdn.com/imgextra/i2/O1CN01vPZjCM1jT26YujpGk_!!6000000004548-0-tps-2284-4301.jpg)\n"
  },
  {
    "path": "docs/docs/guide/appendix/metaSpec.md",
    "content": "---\ntitle: 搭建组件协议结构\nsidebar_position: 1\n---\n完整协议[查看](/site/docs/specs/material-spec)\n\n![](https://img.alicdn.com/imgextra/i4/O1CN01hozDem1apAhnvdESN_!!6000000003378-0-tps-2474-4128.jpg)\n"
  },
  {
    "path": "docs/docs/guide/appendix/npms.md",
    "content": "---\ntitle: NPM 包对应源码位置汇总\nsidebar_position: 3\n---\n| 包名 | 仓库 | 路径 |\n| --- | --- | --- |\n| @alilc/lowcode-code-generator | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | modules/code-generator |\n| @alilc/lowcode-material-parser | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | modules/material-parser |\n| @alilc/lowcode-designer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/designer |\n| @alilc/lowcode-editor-core | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/editor-core |\n| @alilc/lowcode-editor-skeleton | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/editor-skeleton |\n| @alilc/lowcode-engine | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/engine |\n| @alilc/lowcode-plugin-designer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-designer |\n| @alilc/lowcode-plugin-outline-pane | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-outline-pane |\n| @alilc/lowcode-react-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-renderer |\n| @alilc/lowcode-react-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-simulator-renderer |\n| @alilc/lowcode-renderer-core | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/renderer-core |\n| @alilc/lowcode-shell | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/shell |\n| @alilc/lowcode-types  | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/types |\n| @alilc/lowcode-utils | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/utils |\n| @alilc/lowcode-datasource-engine | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-engine |\n| @alilc/lowcode-datasource-fetch-handler  | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-fetch-handler |\n| @alilc/lowcode-datasource-jsonp-handler | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-jsonp-handler |\n| @alilc/lowcode-datasource-mopen-handler  | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-mopen-handler |\n| @alilc/lowcode-datasource-mtop-handler | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-mtop-handler |\n| @alilc/lowcode-datasource-types | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-types |\n| @alilc/lowcode-datasource-universal-mtop-handler | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-universal-mtop-handler |\n| @alilc/lowcode-datasource-url-params-handler | [https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource) | packages/datasource-url-params-handler |\n| @alilc/build-plugin-alt | [https://github.com/alibaba/lowcode-tools](https://github.com/alibaba/lowcode-tools) | packages/build-plugin-alt |\n| @alilc/create-element | [https://github.com/alibaba/lowcode-tools](https://github.com/alibaba/lowcode-tools) | packages/create-element |\n| @alilc/lowcode-plugin-inject | [https://github.com/alibaba/lowcode-tools](https://github.com/alibaba/lowcode-tools) | packages/lowcode-plugin-inject |\n| @alilc/action-block | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/action-block |\n| @alilc/lowcode-plugin-base-monaco-editor | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-base-monaco-editor |\n| @alilc/lowcode-plugin-block | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-block |\n| @alilc/lowcode-plugin-code-editor | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-code-editor |\n| @alilc/lowcode-plugin-components-pane | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-components-pane |\n| @alilc/lowcode-plugin-datasource-pane  | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-datasource-pane |\n| @alilc/lowcode-plugin-manual | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-manual |\n| @alilc/lowcode-plugin-schema | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-schema |\n| @alilc/lowcode-plugin-undo-redo | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-undo-redo |\n| @alilc/lowcode-plugin-zh-en | [https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) | packages/plugin-zh-en |\n| @alifd/fusion-ui | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/fusion-ui |\n| @alilc/lowcode-materials | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/fusion-lowcode-materials |\n| @alilc/antd-lowcode-materials | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/antd-lowcode-materials |\n| @alifd/layout（原 @alifd/pro-layout 升级后的版本） | [https://github.com/alibaba-fusion/layout](https://github.com/alibaba-fusion/layout) |  |\n|  |  |  |\n|  |  |  |\n"
  },
  {
    "path": "docs/docs/guide/appendix/repos.md",
    "content": "---\ntitle: 低代码仓库列表\nsidebar_position: 2\n---\n## 1. 引擎主包\n包含引擎的 4 大模块，入料、编排、渲染和出码。\n\n仓库地址：[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine)\n子包明细：\n\n1. designer\n2. editor-core\n3. editor-skeleton\n4. engine\n5. ignitor\n6. plugin-designer\n7. plugin-outline-pane\n8. react-renderer\n9. react-simulator-renderer\n10. renderer-core\n11. types\n12. utils\n13. material-parser\n14. code-generator\n\n## 2. 引擎官方扩展包\n包含了常用的设置器（setter）、跟 setter 绑定的插件等\n\n仓库地址：[https://github.com/alibaba/lowcode-engine-ext](https://github.com/alibaba/lowcode-engine-ext)\n子包明细：\n\n- 设置器 setter\n   - array-setter\n   - bool-setter\n   - classname-setter\n   - color-setter\n   - events-setter\n   - expression-setter\n   - function-setter\n   - i18n-setter\n   - icon-setter\n   - json-setter\n   - mixed-setter\n   - number-setter\n   - object-setter\n   - out.txt\n   - radiogroup-setter\n   - select-setter\n   - slot-setter\n   - string-setter\n   - style-setter\n   - textarea-setter\n   - variable-setter\n- 插件 plugin\n   - plugin-event-bind-dialog 事件绑定浮层\n   - plugin-variable-bind-dialog 变量绑定浮层\n## 3. 低代码插件\n包含了常用的插件等\n\n仓库地址：[https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins)\n子包明细：\n\n- base-monaco-editor 基础代码编辑器\n- plugin-code-editor 源码编辑面板\n- plugin-datasource-pane 数据源面板\n- plugin-manual 产品使用手册面板\n- plugin-schema 页面数据面板\n- plugin-undo-redo 前进/后退功能\n- plugin-zh-cn 中英文切换功能\n\n## 4. 引擎 demo\n展示使用引擎编排和渲染等模块以及相应的依赖资源配置基础 demo\n\n仓库地址：[https://github.com/alibaba/lowcode-demo](https://github.com/alibaba/lowcode-demo)\n## 5. 工具链包\n包含生成引擎生态元素（setter、物料、插件）的脚手架，启动脚本，调试插件等\n\n仓库地址：[https://github.com/alibaba/lowcode-tools](https://github.com/alibaba/lowcode-tools)\n## 6. 低代码数据源引擎\n负责在渲染&出码两种运行时实现数据源管理，承担低代码搭建数据请求的能力；\n仓库地址：[https://github.com/alibaba/lowcode-datasource](https://github.com/alibaba/lowcode-datasource)\n## 7. 基础物料 & 物料描述\n仓库地址：[https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials)\n## 8. 出码 demo\n仓库地址：[https://github.com/alibaba/lowcode-code-generator-demo](https://github.com/alibaba/lowcode-code-generator-demo)\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/_category_.json",
    "content": "{\n  \"label\": \"预置设置器详情\",\n  \"position\": 5\n}\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/array.md",
    "content": "---\ntitle: ArraySetter\n---\n\n## 简介\n用来展示属性类型为数组的 setter\n## 展示\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01BXCpnh1OFebSSyeDQ_!!6000000001676-2-tps-584-362.png)\n## 配置示例\n```json\n\"setter\": {\n\t\"componentName\": \"ArraySetter\",\n\t\"props\": {\n\t\t\"itemSetter\": {\n\t\t\t\"componentName\": \"ObjectSetter\",\n\t\t\t\"props\": {\n\t\t\t\t\"config\": {\n\t\t\t\t\t\"items\": [{\n\t\t\t\t\t\t\t\"name\": \"title\",\n\t\t\t\t\t\t\t\"description\": \"标题\",\n\t\t\t\t\t\t\t\"setter\": \"StringSetter\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"callback\",\n\t\t\t\t\t\t\t\"description\": \"callback\",\n\t\t\t\t\t\t\t\"setter\": {\n\t\t\t\t\t\t\t\t\"componentName\": \"FunctionSetter\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n      \"initialValue\": {\n       \t \"title\": \"I am title\",\n         \"callback\": null\n      }\n\t\t}\n\t}\n}\n```\n## ArraySetter 配置\n\n| **属性名** | **类型** | **说明** |\n| --- | --- | --- |\n| itemSetter | ObjectSetter | ArraySetter 的子节点内容必须用 ObjectSetter 包裹 |\n\n## itemSetter 配置\n\n| **属性名** | **类型** | **说明** |\n| --- | --- | --- |\n| componentName | String ||\n| props |  |  |\n| initialValue | Object | 新增一项的初始值 |\n\n## ObjectSetter 配置\n| **属性名** | **类型** | **说明** |\n| --- | --- | --- |\n| descriptor | String | Item 在列表中展示的 item.key 名，需要和 config.items[] 中key对应 默认为 “项目X” ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01Okz1DY1Q17GGJBPDf_!!6000000001915-2-tps-640-372.png) |\n| config | Object | 配置项 |\n| config.items | Array | 子属性列表数据 |\n| config.items[].name | String | 子属性名称 |\n| config.items[].description | String | 子属性描述 |\n| config.items[].setter | Object &#124; String | 子属性setter配置 &#124; 子属性setter组件名 |\n| config.items[].isRequired | Boolean | 子属性是否开启快捷编辑,最多开启4个 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01EflYAK1IPpiChvjHz_!!6000000000886-2-tps-614-422.png) |\n| config.items[].condition | Boolean &#124; () => Boolean | 是否展示 |\n| config.items[].getValue | (target, value) => value | 数据获取的 hook，可修改获取数据 |\n| config.items[].setValue | (target, value) => value | 数据获取的 hook，可修改设置数据 |\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/behavior.md",
    "content": "---\ntitle: BehaviorSetter\n---\n\n详见 [npm 包说明](https://g.alicdn.com/code/npm/@ali/lowcode-setter-behavior/0.1.1/build/index.html)"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/bool.md",
    "content": "---\ntitle: BoolSetter\n---\n## 简介\n开关选择器\n## 展示\n\n![](https://img.alicdn.com/imgextra/i3/O1CN01KS7ndr1mHX0MITGPH_!!6000000004929-2-tps-320-82.png)\n## setter 配置\n\n| 属性名 | 说明 |\n| --- | --- |\n| disabled | 是否可选 |\n| defaultValue | 默认值 |\n\n## 返回类型\n\nBoolean\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/color.md",
    "content": "---\ntitle: ColorSetter\n---\n用来选择颜色。\n## 展示\n<img src=\"https://img.alicdn.com/imgextra/i4/O1CN01iYKRA920aDn1uhs3M_!!6000000006865-2-tps-590-728.png\" width=\"300\"/>\n\n## setter 配置\n| 属性名 | 说明 |\n| --- | --- |\n| defaultValue | 默认值 |\n\n## 返回类型\nString\n\n会返回 options 中的 value 值\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/event.md",
    "content": "---\ntitle: EventSetter\n---\n## 简介\n可以将事件绑定在物料上\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i3/O1CN01mAMfxZ20WYca6KqJb_!!6000000006857-2-tps-1202-1014.png\" width=\"300\"/>\n\n## 组件自带事件列表\n\n在物料协议的 configure.supports.events 中声明\n\n```json\n{\n\t\"configure \": {\n\t\t\"supports\": {\n\t\t\t\"style\": true,\n\t\t\t\"events\": [{\n\t\t\t\t\"name\": \"onChange\"\n\t\t\t}, {\n\t\t\t\t\"name\": \"onExpand\"\n\t\t\t}, {\n\t\t\t\t\"name\": \"onVisibleChange\"\n\t\t\t}]\n\t\t}\n\t}\n}\n```\n\n## 事件绑定\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01Q5gHFy1uSzqUeEqQK_!!6000000006037-2-tps-2540-1242.png)\n\n可以选择已有的事件 (schema 中的**methods**节点) 进行绑定，也可以选择新建事件，选择新建事件默认会增加_new 的事件后缀命名，点确定以后会跳转到对应代码插件对应区块。\n\n## 参数设置\n\n如果需要额外传参，需要将扩展参数设置打开，在代码面板中，编辑参数内容。\n\n注意：\n\n- 额外参数必须被包装成一个对象，如参数模板中所示\n- 可以使用动态变量例如 (this.items，this.state.xxx)\n\t```javascript\n\t{\n\t\ttestKey: this.state.text,\n\t}\n\t```\n\n- 该参数是额外参数，会加在原有参数后面，例如在 onClick 中加入扩展传参，最终函数消费的时候应该如下所示\n\t```javascript\n\t// e 为 onClick 原有函数传参，extParams 为自定义传参\n\tonClick(e, extParams) {\n\t\tthis.setState({\n\t\t\tisShowDialog: extParams.isShowDialog,\n\t\t});\n\t}\n\t```\n## 事件新建函数模板\n有时候我们创建的函数会有用到一些通用的函数模板，我们可以在物料协议的 events.template 中创建一个模板，如下\n\n```json\n{\n\t\"configure \": {\n\t\t\"supports\": {\n\t\t\t\"style\": true,\n\t\t\t\"events\": [{\n\t\t\t\t\"name\": \"onChange\",\n\t\t\t\t\"template\": \"templeteTest(e,${extParams}){this.setState({isShowDialog: false})}\"\n\t\t\t}, {\n\t\t\t\t\"name\": \"onExpand\"\n\t\t\t}, {\n\t\t\t\t\"name\": \"onVisibleChange\"\n\t\t\t}]\n\t\t}\n\t}\n}\n```\n\n其中 ${extParams} 为扩展参数占位符，如果用户没有声明扩展参数，会移除对应的参数声明，定义模板后，每次创建完函数会自动生成模板函数，如下图\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01XUoXnS1XiLxlxXniw_!!6000000002957-2-tps-1292-282.png)\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/function.md",
    "content": "---\ntitle: FunctionSetter\n---\n## 简介\n可以将function绑定在物料上\n\n## 设置器返回\n\n设置器返回一个Function对象，调用function()运行Function对象得到运行结果。\n\n如下是一个典型的使用案例：\n\n```javascript\nexport type TestProps = React.ComponentProps<typeof Test> & {\n  testFunction?: Function | undefined;\n};\n \nconst getTestData = () => {\n  if(this.props.testFunction === undefined){\n    return undefined;\n  }else{\n    return this.props.testFunction() // 返回testFunction()方法的运行结果;\n  }\n}\n```\n\n\n## 参数设置\n\n如果需要额外传参，需要将扩展参数设置打开，在代码面板中，编辑参数内容。\n\n注意：\n\n- 额外参数必须被包装成一个对象，如参数模板中所示\n- 可以使用动态变量例如 (this.items，this.state.xxx)\n\t```javascript\n\t{\n\t\ttestKey: this.state.text,\n\t}\n\t```\n\n- 该参数是额外参数，会加在原有参数后面，例如在 onClick 中加入扩展传参，最终函数消费的时候应该如下所示\n\t```javascript\n\t// e 为 onClick 原有函数传参，extParams 为自定义传参\n\tonClick(e, extParams) {\n\t\tthis.setState({\n\t\t\tisShowDialog: extParams.isShowDialog,\n\t\t});\n\t}\n\t```\n\n## 事件新建函数模板\n有时候我们创建的函数会有用到一些通用的函数模板，我们可以在物料协议的 meta.ts 中创建一个模板，如下\n\n```TypeScript\n{\n    name: 'onChange',\n    title: {\n        label: 'onChange',\n        tip: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n    },\n    propType: 'func',\n    setter: [\n        {\n            componentName: 'FunctionSetter',\n            props: {\n                template: 'onTableChange(value,${extParams}){\\n\\n}',\n            },\n        },\n    ],\n}\n```\n\n其中 ${extParams} 为扩展参数占位符，如果用户没有声明扩展参数，会移除对应的参数声明。"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/icon.md",
    "content": "---\ntitle: IconSetter\n---\n## 简介\n用来选择图标\n## 展示\n<img src=\"https://img.alicdn.com/imgextra/i1/O1CN01hdJPHx1zwNKa78YgN_!!6000000006778-2-tps-1172-579.png\" width=\"500\"/>\n\n## setter 配置\n\n| **属性名** | **类型** | **说明** |\n| --- | --- | --- |\n| type | String | 选择器返回类型 **可选值**: \"string\" \\| \"node\" |\n| defaultValue | String &#124; ReactNode | 默认值 |\n| hasClear | Boolean | 选择器是否显示清除按钮 |\n| icons | Array | 自定义 icon 集合；默认值详见[图标可选值](#图标可选值) |\n| placeholder | String | 没有值的时候的占位符 |\n\n## 返回类型\n\nString | ReactNode\n\n## 图标可选值\n\n```javascript\n[\n  'smile',\n  'cry',\n  'success',\n  'warning',\n  'prompt',\n  'error',\n  'help',\n  'clock',\n  'success-filling',\n  'delete-filling',\n  'favorites-filling',\n  'add',\n  'minus',\n  'arrow-up',\n  'arrow-down',\n  'arrow-left',\n  'arrow-right',\n  'arrow-double-left',\n  'arrow-double-right',\n  'switch',\n  'sorting',\n  'descending',\n  'ascending',\n  'select',\n  'semi-select',\n  'loading',\n  'search',\n  'close',\n  'ellipsis',\n  'picture',\n  'calendar',\n  'ashbin',\n  'upload',\n  'download',\n  'set',\n  'edit',\n  'refresh',\n  'filter',\n  'attachment',\n  'account',\n  'email',\n  'atm',\n  'copy',\n  'exit',\n  'eye',\n  'eye-close',\n  'toggle-left',\n  'toggle-right',\n  'lock',\n  'unlock',\n  'chart-pie',\n  'chart-bar',\n  'form',\n  'detail',\n  'list',\n  'dashboard',\n]\n```\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/mixed.md",
    "content": "---\ntitle: MixedSetter\n---\n## 简介\n可以让属性同时支持多个 setter\n\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i4/O1CN01zlCJu21iBLBnxmIn2_!!6000000004374-2-tps-1552-480.png\" width=\"500\"/>\n\n## 配置\n\n| **属性名** | **类型** | **说明** |\n| --- | --- | --- |\n| setters | Array<String\\> | SetterName |\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/number.md",
    "content": "---\ntitle: NumberSetter\n---\n## 简介\n用于输入数字。\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i3/O1CN01b9bRiX1C6F4pCV7GB_!!6000000000031-2-tps-576-402.png\" width=\"300\"/>\n\n## setter 配置\n| 属性名 | 说明 |\n| --- | --- |\n| min, max | 指定最大最小值 |\n| defaultValue | 默认值 |\n| step | 指定步长 number |\n| units | 指定单位 string |\n| precision | 设置小数位数 number |\n\n## 返回类型\nNumber\n\n会返回 value 值\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/radioGroup.md",
    "content": "---\ntitle: RadioGroupSetter\n---\n## 简介\n用于直观的展示选择并选择。\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i2/O1CN01rId9td25yYv0my5Hd_!!6000000007595-2-tps-564-98.png\" width=\"300\"/>\n\n## setter 配置\n| 属性名 | 说明 |\n| --- | --- |\n| defaultValue | 默认值 |\n| options | 传入的数据源，**参数格式**: [{img: 'url', value: 'text', label/title: 'text'}, ...] \\| [ 'text', 'text', ...] |\n\n## 返回类型\nString | Number | Boolean\n会返回 options 中的 value 值\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/select.md",
    "content": "---\ntitle: SelectSetter\n---\n## 简介\n用来选择组件。在限定的可选性内进行选择，核心能力是选择\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i4/O1CN013arqCy1f1JfwdTGQo_!!6000000003946-2-tps-574-602.png\" width=\"300\"/>\n\n## setter 配置\n| 属性名 | 说明 |\n| --- | --- |\n| mode | 选择器模式 可选值: 'single', 'multiple', 'tag' |\n| defaultValue | 默认值 |\n| options | 传入的数据源，**参数格式**: [ {label/title: '文字', value: 'text'}, ...] |\n\n## 返回类型\n\nString | Number | Boolean\n会返回 options 中的 value 值\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/slot.md",
    "content": "---\ntitle: SlotSetter\n---\n## 简介\n通过一个开启一个 slot（插槽），可以在物料特定的一个位置渲染一个或者多个节点。slot 比较适合物料的局部自定义渲染。\n\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i3/O1CN01DwFQ221ks3MDXhk36_!!6000000004738-2-tps-588-454.png\" width=\"300\"/>\n\n<br/>\n<br/>\n\n<img src=\"https://img.alicdn.com/imgextra/i1/O1CN01pQC6EE1bWDwIkVq2z_!!6000000003472-2-tps-644-164.png\" width=\"300\"/>\n\n## setter 配置\n\n| 属性名 | 类型 | 说明 |\n| --- | --- | --- |\n| initialValue | Object | 默认值 { \"type\": \"JSSlot\", \"params\": [ \"module\" ], \"value\": [] } params:接收函数的入参，可以直接在slot节点中消费，通过this.module (这里module是示例值，可根据实际函数入参更改) value:可以定义一个节点，每次打开插槽的时候默认填充一个节点 |\n| hideParams | boolean | 是否隐藏入参，注意该值只能隐藏入参的输入框，适合单行展示，实际渲染的时候，还是会传入 params 的参数，和 params:[]不同 |\n| checkedText | string | switch 选中文案，默认显示\"启用\" |\n| unCheckedText | string | switch 取消文案，默认显示\"关闭\" |\n\n## 配置示例\n### 配置\n\n```typescript\n{\n    name: 'propName',\n    title: 'propTitle',\n    setter: {\n      componentName: 'SlotSetter',\n      isRequired: true,\n      title: '组件坑位',\n      initialValue: {\n        type: 'JSSlot',\n        value: [],\n      },\n    }\n  }\n```\n### 组件\n\n```typescript\nfunction A(props) {\n  return props.propName;\n}\n```\n## 带参数的插槽示例\n### 配置\n\n```typescript\n{\n  name: 'propName',\n  title: 'propTitle',\n  setter: {\n    componentName: 'SlotSetter',\n    isRequired: true,\n    title: '组件坑位',\n    initialValue: {\n      type: 'JSSlot',\n      params: [ 'module'],\n      value: [],\n    },\n  }\n}\n```\n### 组件\n\n组件需要传参数进行渲染，和普通示例的使用不一样。\n\n```typescript\nfunction A(props) {\n  const module = [];\n  return props.propName(module);\n}\n```\n### param 使用示例\n\n1.开启插槽\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01RlOXAV1TbFMBZa6xq_!!6000000002400-2-tps-3584-1800.png)\n\n2.拖拽组件到插槽中\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01NNiWLs26961orvk9i_!!6000000007618-2-tps-3584-1806.png)\n\n3.在插槽内组件中使用变量绑定，绑定 this.xxx\n\nxxx 入参的配置\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01cBn2ym1XF2cDZo5Yp_!!6000000002893-2-tps-3584-1806.png)\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/string.md",
    "content": "---\ntitle: StringSetter\n---\n## 简介\n\n用来展示和修改字符串类型的属性值，不可换行\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i4/O1CN0102tNBy1eEJIMDVZju_!!6000000003839-2-tps-714-88.png\" width=\"300\"/>\n\n## setter 配置\n\n| 属性名 | 说明 |\n| --- | --- |\n| placeholder | 输入提示 |\n\n## 返回类型\nString\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/style.md",
    "content": "---\ntitle: StyleSetter\n---\n## 简介\n通过开启 StyleSetter，我们可以将样式配置面板来配置样式属性。\n\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i1/O1CN01plhL0t1DH43CZ8hAa_!!6000000000190-2-tps-596-1478.png\" width=\"300\"/>\n\n## setter 配置\n\n| 属性名 | 类型 | 说明 |\n| --- | --- | --- |\n| unit | String | 默认值 px <img src=\"https://img.alicdn.com/imgextra/i4/O1CN014BRbq41TKIhXjQuOf_!!6000000002363-2-tps-576-98.png\" width=\"250\"/> |\n| placeholderScale | Number | 默认计算尺寸缩放 默认值为 1  <img src=\"https://img.alicdn.com/imgextra/i4/O1CN01OLWb2g1Yd94uAC6ax_!!6000000003081-2-tps-250-98.png\" width=\"100\"/> 在没有设定数值的时候，系统会通过 window.getComputedStyle 来计算展示的数值。在某些场景下，例如手机场景，在编辑器展示的是 375 的实际宽度，但是实际设计尺寸是 750 的宽度，这个时候需要对这个计算尺寸设成 2 |\n| showModuleList | String[] | 默认值 ['background', 'border', 'font', 'layout', 'position'] 分别对应背景、边框、文字、布局、位置五个区块，可以针对不同的场景按需进行展示。 例如文字的组件，我不需要修改边框的样式，就可以把边框模块隐藏掉 |\n| isShowCssCode | Boolean | 默认值: true, 是否展示css源码编辑  |\n| layoutPropsConfig | Object | 布局样式设置 |\n| layoutPropsConfig.showDisPlayList | String[] | 默认值 ['inline', 'flex', 'block', 'inline-block', 'none'] <img src=\"https://img.alicdn.com/imgextra/i3/O1CN01nucfjP1gT5Iu6IMua_!!6000000004142-2-tps-474-72.png\" width=\"250\"/> 可按需展示 |\n| layoutPropsConfig.isShowPadding | String | 默认值 true <img src=\"https://img.alicdn.com/imgextra/i4/O1CN01frOzt81uLfVjYIR8I_!!6000000006021-2-tps-548-382.png\" width=\"250\"/> 是否展示内边距（四个边） ||\n| layoutPropsConfig.isShowMargin | Boolean | 默认值 true <img src=\"https://img.alicdn.com/imgextra/i3/O1CN01H2qo0N1dVssDYT8EN_!!6000000003742-2-tps-536-482.png\" width=\"250\"/> 是否展示外边距（四个边） ||\n| layoutPropsConfig.isShowWidthHeight | Boolean | 默认值 true <img src=\"https://img.alicdn.com/imgextra/i2/O1CN01A0pqoz1CAp2KUv230_!!6000000000041-2-tps-546-102.png\" width=\"250\"/> 是否展示宽高 |\n| fontPropsConfig | Object | 文字样式设置 |\n| fontPropsConfig.fontFamilyList | Array | [ { value: 'Helvetica', label: 'Helvetica' }, { value: 'Arial', label: 'Arial' },] 可以定制文字字体选项 |\n| positionPropsConfig | Object | 位置样式设置 |\n| positionPropsConfig.isShowFloat | Boolean  | 默认 true 是否展示浮动 |\n| positionPropsConfig.isShowClear | Boolean | 默认 true 是否展示清除浮动 |\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/textArea.md",
    "content": "---\ntitle: TextAreaSetter\n---\n## 简介\n表单输入组件。\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i3/O1CN012p7cxS1KsLbETRYpY_!!6000000001219-2-tps-1026-292.png\" width=\"300\"/>\n\n## setter 配置\n| **属性名** | **类型** | **说明** |\n| --- | --- | --- |\n| placeholder | String | 输入提示 |\n\n## 返回类型\nString\n"
  },
  {
    "path": "docs/docs/guide/appendix/setterDetails/variable.md",
    "content": "---\ntitle: VariableSetter\n---\n## 简介\n\n用来给属性值设定变量\n\n## 展示\n\n<img src=\"https://img.alicdn.com/imgextra/i3/O1CN01RhKkpP1QexivgHNVB_!!6000000002002-2-tps-578-92.png\" width=\"300\"/>\n<br/>\n\n<img src=\"https://img.alicdn.com/imgextra/i3/O1CN014GxSj41xovf3cpX6y_!!6000000006491-2-tps-1564-1190.png\" width=\"500\"/>\n\n## 变量列表\n包含所有的在协议中的**state**(state 属性) 节点数据和**methods**(自定义处理函数) 节点数据\n"
  },
  {
    "path": "docs/docs/guide/appendix/setters.md",
    "content": "---\ntitle: 预置设置器列表\nsidebar_position: 4\n---\n| 预置 Setter | 返回类型 | 用途 | 截图 |\n| --- | --- | --- | --- |\n| [ArraySetter](./setterDetails/array) | T[] | 列表数组行数据设置器 | ![](https://img.alicdn.com/imgextra/i1/O1CN01UNmb7429mtHsbTHg3_!!6000000008111-2-tps-584-362.png) |\n| [BoolSetter](./setterDetails/behavior) | boolean | 布尔型数据设置器， | ![](https://img.alicdn.com/imgextra/i2/O1CN01gZlHyx24MiZfjU61A_!!6000000007377-2-tps-320-82.png) |\n| ClassNameSetter | string | 样式名设置器 | ![](https://img.alicdn.com/imgextra/i3/O1CN01ResoVi1PtKWxwuww8_!!6000000001898-2-tps-502-180.png) |\n| [ColorSetter](./setterDetails/color) | string | 颜色设置器 | ![](https://img.alicdn.com/imgextra/i4/O1CN018gsNdw1Qt9zsZWP9K_!!6000000002033-2-tps-590-728.png) |\n| DateMonthSetter | | 日期型 - 月数据设置器 | |\n| DateRangeSetter | | 日期型数据设置器，可选择时间区间 | |\n| DateSetter | | 日期型数据设置器 | |\n| DateYearSetter || 日期型 - 年数据设置器 | |\n| [EventSetter](./setterDetails/event) | function | 事件绑定设置器 | ![](https://img.alicdn.com/imgextra/i4/O1CN01qxIYiO1ksVknhTpnW_!!6000000004739-2-tps-1202-1014.png) |\n| [IconSetter](./setterDetails/icon) | string | 图标设置器 | ![](https://img.alicdn.com/imgextra/i3/O1CN01zsOMxo1TXaBmjHCRc_!!6000000002392-2-tps-1172-579.png) |\n| [FunctionSetter](./setterDetails/function) | function | 函数型数据设置器 | ![](https://img.alicdn.com/imgextra/i4/O1CN01jLiJBo1ZIp7OmDLp0_!!6000000003172-2-tps-794-110.png) |\n| JsonSetter | object | json 型数据设置器 | ![](https://img.alicdn.com/imgextra/i2/O1CN01mQTFjY1YiBQzWYj64_!!6000000003092-2-tps-1076-1068.png) |\n| [MixedSetter](./setterDetails/mixed) | any | 混合型数据设置器 | ![](https://img.alicdn.com/imgextra/i1/O1CN01ZxomFY1JW4j7wIGuQ_!!6000000001035-2-tps-1552-480.png) |\n| [NumberSetter](./setterDetails/number) | number | 数值型数据设置器 | ![](https://img.alicdn.com/imgextra/i3/O1CN01dSfSgg1WS2EpbqJIO_!!6000000002786-2-tps-1152-328.png) |\n| ObjectSetter | Record<string, any> | 对象数据设置器，一般内嵌在 ArraySetter 中 ||\n| [RadioGroupSetter](./setterDetails/radioGroup)| string &#124; number &#124; boolean | 枚举型数据设置器，采用 tab 选择的形式展现 || ![](https://img.alicdn.com/imgextra/i4/O1CN01Z0Zgi51W10s5L2Hce_!!6000000002727-2-tps-564-98.png) |\n| [SelectSetter](./setterDetails/select) | string &#124; number &#124; boolean | 枚举型数据设置器，采用下拉的形式展现 | ![](https://img.alicdn.com/imgextra/i1/O1CN01sfUEgZ1I0BXCl60LM_!!6000000000830-2-tps-582-282.png) |\n| [SlotSetter](./setterDetails/slot) | Element &#124; Element[] | 节点型数据设置器 | ![](https://img.alicdn.com/imgextra/i3/O1CN01wulNGt1qNip0IlEsF_!!6000000005484-2-tps-644-164.png) |\n| [StringSetter](./setterDetails/string) | string | 短文本型数据设置器，不可换行 | ![](https://img.alicdn.com/imgextra/i4/O1CN01iYalzO1xVh1ikLvSr_!!6000000006449-2-tps-414-102.png) |\n| StyleSetter || 样式设置器 | ![](https://img.alicdn.com/imgextra/i4/O1CN01ZwX2pO26UAFKuYfuF_!!6000000007664-2-tps-788-1214.png) |\n| [TextAreaSetter](./setterDetails/textArea) | string | 长文本型数据设置器，可换行 | ![](https://img.alicdn.com/imgextra/i4/O1CN01GMu8YJ1nqAZoYQ3xi_!!6000000005140-2-tps-1026-292.png) |\n| TimePicker | | 时间型数据设置器 ||\n| [VariableSetter](./setterDetails/variable) | any | 变量型数据设置器， | ![](https://img.alicdn.com/imgextra/i1/O1CN015V5AAY1v3B8XxQ75k_!!6000000006116-2-tps-578-92.png) |\n"
  },
  {
    "path": "docs/docs/guide/create/_category_.json",
    "content": "{\n  \"label\": \"创建低代码编辑器\",\n  \"position\": 1,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/guide/create/useEditor.md",
    "content": "---\ntitle: 接入编辑器\nsidebar_position: 0\n---\n\n您有两种方式初始化低代码编辑器：\n\n1. clone 低代码项目的官方 demo，直接启动项目。适合普通人。\n2. 手工引入低代码 UMD 包，手工配置、打包和启动。适合 Webpack 配置工程师。\n\n## 方法 1：通过官方命令行工具创建编辑器\n\n1. 确保本地安装了 Node.js 和 npm，如果没有，[您可以通过 nvm 进行快捷的安装](https://github.com/nvm-sh/nvm)\n2. 确保为 npm [设置了可以访问的 npm 源，保证安装过程无网络问题](https://npmmirror.com/)\n3. 安装官方命令行工具\n   ```bash\n   npm install -g @alilc/create-element@latest\n   ```\n4. 通过命令行工具创建\n   ```bash\n   npm init @alilc/element editor-project-name\n   ```\n   这时会看到一个选项列表\n\n   <img src=\"https://img.alicdn.com/imgextra/i3/O1CN01LAaw2R1veHDYUzGB1_!!6000000006197-2-tps-676-142.png\" width=\"350\"/>\n\n   选择`编辑器`，并填写对应的问题，即可完成创建。\n\n   > 注 @alilc/create-element 版本需 >= 1.0.4，若看不到`编辑器`选项，请重新执行步骤 3\n5. 进入创建后的目录\n   ```bash\n   cd editor-project-name\n   ```\n6. 安装依赖\n   ```bash\n   npm install\n   ```\n7. 安装依赖成功后，启动项目 (注意观察上一步的输出，如有 error 等失败信息，请先进行排查)\n   ```bash\n   npm start\n   ```\n   执行后如果看到这个界面，说明项目启动成功。您可以继续看后续章节了。本章节后续内容均为高级配置方式。\n\n  ![image.png](https://img.alicdn.com/imgextra/i4/O1CN013qJVoV1OAcFNKFrIQ_!!6000000001665-2-tps-3060-1634.png)\n\n## 方法 2: 使用 UMD 包方式配置\n\n如果您不是从零开始的项目，您可能需要手工引入低代码引擎。\n\n### 引入 UMD 包资源\n\n我们需要在启动前，正确在项目中通过 UMD 包方式直接依赖如下内容：\n> 亦可使用异步加载工具，如果您按照正确的顺序进行加载\n\n```html\n<!-- 低代码引擎的页面框架样式 -->\n<link rel=\"stylesheet\" href=\"https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/css/engine-core.css\" />\n<!-- Fusion Next 控件样式 -->\n<link rel=\"stylesheet\" href=\"https://g.alicdn.com/code/lib/alifd__next/1.23.24/next.min.css\">\n<!-- 低代码引擎的页面主题样式，可以替换为 theme-lowcode-dark -->\n<link rel=\"stylesheet\" href=\"https://alifd.alicdn.com/npm/@alifd/theme-lowcode-light/0.2.0/next.min.css\">\n<!-- 低代码引擎官方扩展的样式 -->\n<link rel=\"stylesheet\" href=\"https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine-ext/1.0.5/dist/css/engine-ext.css\" />\n\n<!-- React，可替换为 production 包 -->\n<script src=\"https://g.alicdn.com/code/lib/react/16.14.0/umd/react.development.js\"></script>\n<!-- React DOM，可替换为 production 包 -->\n<script src=\"https://g.alicdn.com/code/lib/react-dom/16.14.0/umd/react-dom.development.js\"></script>\n<!-- React 向下兼容，预防物料层的依赖 -->\n<script src=\"https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\"></script>\n<script src=\"https://g.alicdn.com/platform/c/react15-polyfill/0.0.1/dist/index.js\"></script>\n<!-- lodash，低代码编辑器的依赖 -->\n<script src=\"https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js\"></script>\n<!-- 日期处理包，Fusion Next 的依赖 -->\n<script src=\"https://g.alicdn.com/code/lib/moment.js/2.29.1/moment-with-locales.min.js\"></script>\n<!-- Fusion Next 的主包，低代码编辑器的依赖 -->\n<script src=\"https://g.alicdn.com/code/lib/alifd__next/1.23.24/next.min.js\"></script>\n<!-- 低代码引擎的主包 -->\n<script crossorigin=\"anonymous\" src=\"https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js\"></script>\n<!-- 低代码引擎官方扩展的主包 -->\n<script crossorigin=\"anonymous\" src=\"https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine-ext/1.0.5/dist/js/engine-ext.js\"></script>\n```\n> 注：如果 unpkg 的服务比较缓慢，您可以使用官方 CDN 来获得确定版本的低代码引擎，如对于引擎的 1.0.18 版本，可用以下官方 CDN 替代\n> - [https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js](https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js)\n\n\n### 配置打包\n\n因为这些资源已经通过 UMD 方式引入，所以在 webpack 等构建工具中需要配置它们为 external，不再重复打包：\n\n```javascript\n{\n  \"externals\": {\n    \"react\": \"var window.React\",\n    \"react-dom\": \"var window.ReactDOM\",\n    \"prop-types\": \"var window.PropTypes\",\n    \"@alifd/next\": \"var window.Next\",\n    \"@alilc/lowcode-engine\": \"var window.AliLowCodeEngine\",\n    \"@alilc/lowcode-engine-ext\": \"var window.AliLowCodeEngineExt\",\n    \"moment\": \"var window.moment\",\n    \"lodash\": \"var window._\"\n  }\n}\n```\n\n### 初始化低代码编辑器\n\n正确引入后，我们可以直接通过 window 上的变量进行引用，如 `window.AliLowCodeEngine.init`。您可以直接通过此方式初始化低代码引擎：\n\n```javascript\n// 确保在执行此命令前，在 <body> 中已有一个 id 为 lce-container 的 <div />\nwindow.AliLowCodeEngine.init(document.getElementById('lce-container'), {\n  enableCondition: true,\n  enableCanvasLock: true,\n});\n```\n\n如果您的项目中使用了 TypeScript，您可以通过如下 devDependencies 引入相关包，并获得对应的类型推断。\n```javascript\n// package.json\n{\n  \"devDependencies\": {\n    \"@alilc/lowcode-engine\": \"^1.0.0\"\n  }\n}\n```\n```javascript\n// src/index.tsx\nimport { init } from '@alilc/lowcode-engine';\n\ninit(document.getElementById('lce-container'), {\n  enableCondition: true,\n  enableCanvasLock: true,\n});\n```\n\ninit 的功能包括但不限于：\n\n1. 传递 options 并设置 config 对象；\n2. 传递 preference 并设置 plugins 入参；\n3. 初始化 Workbench；\n\n> 本节中的低代码编辑器例子可以在 demo 中找到：[https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/index.ts](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/index.ts)\n\n## 配置低代码编辑器\n详见[低代码扩展简述](/site/docs/guide/expand/editor/summary)章节。\n"
  },
  {
    "path": "docs/docs/guide/create/useRenderer.md",
    "content": "---\ntitle: 接入运行时\nsidebar_position: 1\n---\n\n低代码引擎的编辑器将产出两份数据：\n\n- 资产包数据 assets：包含物料名称、包名及其获取方式，对应协议中的[《低代码引擎资产包协议规范》](/site/docs/specs/assets-spec)\n- 页面数据 schema：包含页面结构信息、生命周期和代码信息，对应协议中的[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)\n\n经过上述两份数据，可以直接交由渲染模块或者出码模块来运行，二者的区别在于：\n\n- 渲染模块：使用资产包数据、页面数据和低代码运行时，并且允许维护者在低代码编辑器中用 `低代码（LowCode）`的方式继续维护；\n- 出码模块：不依赖低代码运行时和页面数据，直接生成可直接运行的代码，并且允许维护者用 `源码（ProCode）` 的方式继续维护，但无法再利用低代码编辑器；\n\n> 渲染和出码的详细阐述可参考此文：[低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ)\n\n## 渲染模块\n\n[在 Demo 中](https://lowcode-engine.cn/demo/demo-general/index.html)，右上角有渲染模块的示例使用方式：\n![Mar-13-2022 16-52-49.gif](https://img.alicdn.com/imgextra/i2/O1CN01PRsEl61o7Zct5fJML_!!6000000005178-1-tps-1534-514.gif)\n\n基于官方提供的渲染模块 [@alifd/lowcode-react-renderer](https://github.com/alibaba/lowcode-engine/tree/main/packages/react-renderer)，你可以在 React 上下文渲染低代码编辑器产出的页面。\n\n### 构造渲染模块所需数据\n\n渲染模块所需要的数据需要通过编辑器产出的数据进行一定的转换，规则如下：\n\n- schema：从编辑器产出的 projectSchema 中拿到 componentsTree 中的首项，即 `projectSchema.componentsTree[0]`；\n- components：需要根据编辑器产出的资产包 assets 中，根据页面 projectSchema 中声明依赖的 componentsMap，来加载所有依赖的资产包，最后获取资产包的实例并生成物料 - 资产包的键值对 components。\n\n这个过程可以参考 demo 项目中的 `src/preview.tsx`：\n\n```typescript\nasync function getSchemaAndComponents() {\n  const packages = JSON.parse(window.localStorage.getItem('packages') || '');\n  const projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || '');\n  const { componentsMap: componentsMapArray, componentsTree } = projectSchema;\n  const componentsMap: any = {};\n  componentsMapArray.forEach((component: any) => {\n    componentsMap[component.componentName] = component;\n  });\n  const schema = componentsTree[0];\n\n  const libraryMap = {};\n  const libraryAsset = [];\n  packages.forEach(({ package: _package, library, urls, renderUrls }) => {\n    libraryMap[_package] = library;\n    if (renderUrls) {\n      libraryAsset.push(renderUrls);\n    } else if (urls) {\n      libraryAsset.push(urls);\n    }\n  });\n\n  const vendors = [assetBundle(libraryAsset, AssetLevel.Library)];\n\n  const assetLoader = new AssetLoader();\n  await assetLoader.load(libraryAsset);\n  const components = await injectComponents(buildComponents(libraryMap, componentsMap));\n\n  return {\n    schema,\n    components,\n  };\n}\n```\n\n### 进行渲染\n\n拿到 schema 和 components 以后，您可以借由资产包数据和页面数据来完成页面的渲染：\n```tsx\nimport React from 'react';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\n\nconst SamplePreview = () => {\n  return (\n    <ReactRenderer\n      schema={schema}\n      components={components}\n    />\n  );\n}\n```\n\n> 注 1：您可以注意到，此处是依赖了 React 进行渲染的，对于 Vue 形态的渲染或编辑器支持，详见[对应公告](https://github.com/alibaba/lowcode-engine/issues/236)。\n>\n> 注 2：本节示例可在 Demo 代码里找到更完整的版本：[https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/preview.tsx](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/preview.tsx)\n\n\n## 出码模块\n\n[在 Demo 中](https://lowcode-engine.cn/demo/demo-general/index.html)，右上角有出码模块的示例使用方式：\n\n![Mar-13-2022 16-55-56.gif](https://img.alicdn.com/imgextra/i3/O1CN017CVeka27p3vwrGI1D_!!6000000007845-1-tps-1536-514.gif)\n\n> 本节示例可在出码插件里找到：[https://github.com/alibaba/lowcode-code-generator-demo](https://github.com/alibaba/lowcode-code-generator-demo)\n\n\n## 低代码的生产和消费流程总览\n\n经过“接入编辑器” - “接入运行时”这两节的介绍，我们已经可以了解到低代码所构建的生产和消费流程了，梳理如下图：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01yiFiUc1rT32o9HpnW_!!6000000005631-2-tps-3206-1786.png)\n\n如上述流程所示，您一般需要一个后端项目来保存页面数据信息，如果资产包信息是动态的，也需要保存资产包信息。\n"
  },
  {
    "path": "docs/docs/guide/design/_category_.json",
    "content": "{\n  \"label\": \"引擎设计原理\",\n  \"position\": 3,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/guide/design/datasourceEngine.md",
    "content": "---\ntitle: 数据源引擎设计\nsidebar_position: 7\n---\n## 核心原理\n\n考虑之后的扩展性和兼容性，核心分为了 2 类包，一个是 **datasource-engine** ，另一个是 **datasource-engine-x-handler** ，x 的意思其实是对应数据源的 type，比如说 **datasource-engine-mtop-handler**，也就是说我们会将真正的请求工具放在 handler 里面去处理，engine 在使用的时候由使用方自身来决定需要注册哪些 handler，这样的目的有 2 个，一个是如果将所有的 handler 都放到一个包，对于端上来说这个包过大，有一些浪费资源和损耗性能的问题，另一个是如果有新的类型的数据源出现，只需要按照既定的格式去新增一个对应的 handler 处理器即可，达到了高扩展性的目的；\n\n![](https://img.alicdn.com/imgextra/i3/O1CN011ep9No2ACzrgzgtk0_!!6000000008168-2-tps-720-370.png)\n\n### DataSourceEngine\n\n- engine：engine 主要分 2 类，一类是面向 render 引擎的，可以从 engine/interpret 引入，一类是面向出码或者说直接单纯使用数据源引擎的场景，可以从 engine/runtime 引入，代码如下\n\n```typescript\nimport { createInterpret, createRuntime } from '@alilc/lowcode-datasource-engine';\n```\n\ncreate 方法定义如下\n\n```typescript\ninterface IDataSourceEngineFactory {\n    create(dataSource: DataSource, context: Omit<IRuntimeContext, 'dataSourceMap' | 'reloadDataSource'>, extraConfig?: {\n        requestHandlersMap: RequestHandlersMap;\n        [key: string]: any;\n    }): IDataSourceEngine;\n}\n```\n\ncreate 接收三个参数，第一个是 DataSource，对于运行时渲染和出码来说，DataSource 的定义分别如下：\n\n```typescript\n/**\n * 数据源对象--运行时渲染\n */\nexport interface DataSource {\n    list: DataSourceConfig[];\n    dataHandler?: JSFunction;\n}\n\n/**\n * 数据源对象\n */\nexport interface DataSourceConfig {\n    id: string;\n    isInit: boolean | JSExpression;\n    type: string;\n    requestHandler?: JSFunction;\n    dataHandler?: JSFunction;\n    options?: {\n        uri: string | JSExpression;\n        params?: JSONObject | JSExpression;\n        method?: string | JSExpression;\n        isCors?: boolean | JSExpression;\n        timeout?: number | JSExpression;\n        headers?: JSONObject | JSExpression;\n        [option: string]: CompositeValue;\n    };\n    [otherKey: string]: CompositeValue;\n}\n```\n\n但是对于出码来说，create 和 DataSource 定义如下：\n\n```typescript\nexport interface IRuntimeDataSourceEngineFactory {\n    create(dataSource: RuntimeDataSource, context: Omit<IRuntimeContext, 'dataSourceMap' | 'reloadDataSource'>, extraConfig?: {\n        requestHandlersMap: RequestHandlersMap;\n        [key: string]: any;\n    }): IDataSourceEngine;\n}\n\nexport interface RuntimeOptionsConfig {\n    uri: string;\n    params?: Record<string, unknown>;\n    method?: string;\n    isCors?: boolean;\n    timeout?: number;\n    headers?: Record<string, unknown>;\n    shouldFetch?: () => boolean;\n    [option: string]: unknown;\n}\nexport declare type RuntimeOptions = () => RuntimeOptionsConfig; // 考虑需要动态获取值的情况，这里在运行时会真正的转为一个 function\n\nexport interface RuntimeDataSourceConfig {\n    id: string;\n    isInit: boolean;\n    type: string;\n    requestHandler?: () => {};\n    dataHandler: (data: unknown, err?: Error) => {};\n    options?: RuntimeOptions;\n    [otherKey: string]: unknown;\n}\n\n/**\n * 数据源对象\n */\nexport interface RuntimeDataSource {\n    list: RuntimeDataSourceConfig[];\n    dataHandler?: (dataMap: DataSourceMap) => void;\n}\n```\n\n2 者的区别还是比较明显的，一个是带 js 表达式一类的字符串，另一个是真正转为直接可以运行的 js 代码，对于出码来说，转为可执行的 js 代码的过程是出码自身负责的，对于渲染引擎来说，它只能接受到初始的 schema json 所以需要数据源引擎来做转化\n\n- context：数据源引擎内部有一些使用了 this 的表达式，这些表达式需要求值的时候依赖上下文，因此需要将当前的上下文丢给数据源引擎，另外在 handler 里面去赋值的时候，也会用到诸如 setState 这种上下文里面的 api，当然，这个是可选的，我们后面再说。\n\n```typescript\n/**\n * 运行时上下文--暂时是参考 react，当然可以自己构建，完全没问题\n */\nexport interface IRuntimeContext<TState extends object = Record<string, unknown>> {\n    /** 当前容器的状态 */\n    readonly state: TState;\n    /** 设置状态 (浅合并) */\n    setState(state: Partial<TState>): void;\n    /** 自定义的方法 */\n    [customMethod: string]: any;\n    /** 数据源，key 是数据源的 ID */\n    dataSourceMap: Record<string, IRuntimeDataSource>;\n    /** 重新加载所有的数据源 */\n    reloadDataSource(): Promise<void>;\n    /** 页面容器 */\n    readonly page: IRuntimeContext & {\n        readonly props: Record<string, unknown>;\n    };\n    /** 低代码业务组件容器 */\n    readonly component: IRuntimeContext & {\n        readonly props: Record<string, unknown>;\n    };\n}\n```\n\n- extraConfig：这个字段是为了留着扩展用的，除了一个必填的字段 **requestHandlersMap**\n\n```typescript\nexport declare type RequestHandler<T = unknown> = (ds: RuntimeDataSourceConfig, context: IRuntimeContext) => Promise<RequestResult<T>>;\nexport declare type RequestHandlersMap = Record<string, RequestHandler>;\n```\n\nRequestHandlersMap 是一个把数据源以及对应的数据源 handler 关联起来的桥梁，它的 key 对应的是数据源 DataSourceConfig 的 type，比如 mtop/http/jsonp ... ，每个类型的数据源在真正使用的时候会调用对应的 type-handler，并将当前的参数和上下文带给对应的 handler。\n\ncreate 调用结束后，可以获取到一个 DataSourceEngine 实例\n\n```typescript\nexport interface IDataSourceEngine {\n    /** 数据源，key 是数据源的 ID */\n    dataSourceMap: Record<string, IRuntimeDataSource>;\n    /** 重新加载所有的数据源 */\n    reloadDataSource(): Promise<void>;\n}\n```\n"
  },
  {
    "path": "docs/docs/guide/design/editor.md",
    "content": "---\ntitle: 编排模块设计\nsidebar_position: 3\n---\n本篇重点介绍如何从零开始设计编排模块，设计思路是什么？思考编排的本质是什么？围绕着本质，如何设计并实现对应的功能模块。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01fGzyI41bqpl6AavNp_!!6000000003517-2-tps-1920-1080.png)\n\n## 编排是什么\n\n所谓编排，即将设计器中的所有物料，进行布局设置、组件设置、交互设置（JS 编写/逻辑编排）后，形成符合业务诉求的 schema 描述。\n## 编排的本质\n\n首先，思考编排的本质是什么？\n\n编排的本质是生产符合《阿里巴巴中后台前端搭建协议规范》的数据**，**在这个场景里，协议是通过 JSON 来承载的。如：\n\n```json\n{\n  \"componentName\": \"Page\",\n  \"props\": {\n    \"layout\": \"wide\"\n  },\n  \"children\": [\n    {\n      \"componentName\": \"Button\",\n      \"props\": {\n        \"size\": \"large\"\n      }\n    }\n  ]\n}\n```\n\n可是在真实场景，节点数可能有成百上千，每个节点都具有新增、删除、修改、移动、插入子节点等操作，同时还有若干约束，JSON 结构操作起来不是很便利，于是我们仿 DOM 设计了 **节点模型 & 属性模型，**用更具可编程性的方式来编排，这是**编排系统的基石**。\n\n其次，每次编排动作后（CRUD），都需要实时的渲染出视图。广义的视图应该包括各种平台上的展现，浏览器、Rax、小程序、Flutter 等等，所以使用何种渲染器去渲染 JSON 结构应该可以由用户去扩展，我们定义一种机制去衔接设计态和渲染态。\n\n至此，我们已经完成了**编排模块最基础的功能**，接下来，就是完善细节，逐步丰满功能。比如：\n1. 编排面板的整体功能区划分设计；\n2. 节点属性设计；节点删除、移动等操作设计；容器节点设计；\n3. 节点拖拽功能、拖拽定位设计和实现；\n4. 节点在画布上的辅助功能，比如 hover、选中、选中时的操作项、resize、拖拽占位符等；\n5. 设计态和渲染态的坐标系转换，滚动监听等；\n6. 快捷键机制；\n7. 历史功能，撤销和重做；\n8. 结构化的插件扩展机制；\n9. 原地编辑功能；\n\n有非常多模块，但只要记住一点，这些功能的目的都是辅助用户在画布上有更好的编排体验、扩展能力而逐个增加设计的。\n\n## 编排功能模块\n### 模型设计\n\n编排实际上操作 schema，但是实际代码运行的过程中，我们将 schema 分成了很多层，每一层有各自的职责，他们所负责的功能是明确清晰的。这就是低代码引擎中的模型设计。\n\n我们通过将 schema 和常用的操作等结合起来，最终将低代码引擎的模型分为节点模型、属性模型、文档模型和项目模型。\n\n#### 项目模型（`Project`）\n\n项目模型提供项目管理能力。通常一个引擎启动会默认创建一个 `Project` 实例，有且只有一个。项目模型实例下可以持有多个文档模型的实例，而当前处于设计器设计状态的文档模型，我们将其添加 active 标识，也将其称为 `currentDocument`，可以通过 `project.currentDocument` 获得。\n\n一个 `Project` 包含若干个 `DocumentModel` 实例，即项目模型和文档模型的关系是 1 对 n，如下图所示：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01G28BKC1RvHRvhhiDf_!!6000000002173-2-tps-1226-1648.png)\n\n#### 文档模型（`DocumentModel`）\n\n文档模型提供文档管理的能力，每一个页面即一个文档流，对应一个文档模型。文档模型包含了一组 Node 组成的一颗树，类似于 DOM。我们可以通过文档模型来操作 `Node` 树，来达到管理文档模型的能力。每一个文档模型对应多个 `Node`，但是根 `Node` 只有一个，即 `rootNode` 和 `nodes`。\n\n文档模型可以通过 `Node` 树，通过 `doc.schema` 来导出文档的 `schema`，并使用其进行渲染。\n\n他们的关系如下图：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01NYVhN61nab6hsw5ZK_!!6000000005106-2-tps-960-1490.png)\n\n#### 节点模型（`Node`）\n\n我们先看一下一个 `Node` 在 `schema` 中对应的示例：\n\n```javascript\n{\n  componentName: 'Text',\n  id: 'node_k1ow3cbf',\n  props: {\n    showTitle: false,\n    behavior: 'NORMAL',\n    content: {\n      use: 'zh_CN',\n      en_US: 'Title',\n      zh_CN: '个人信息',\n      type: 'i18n',\n    },\n    fieldId: 'text_k1ow3h1j',\n    maxLine: 0,\n  },\n  condition: true,\n}\n```\n\n上面的示例是一个 `Text` 的 `Node` 节点，而我们的 `Node` 节点模型就是负责这一层级的 `Schema` 管理。它的功能聚焦于单层级的 schema 相关操作。我们可以看一下节点模型的一些方法，了解其功能。\n\n```typescript\ndeclare class Node<Schema extends NodeSchema = NodeSchema> {\n  // Props\n  props: Props;\n  get propsData(): PropsMap | PropsList | null;\n  getProp(path: string, stash?: boolean): Prop | null;\n  getPropValue(path: string): any;\n  setPropValue(path: string, value: any): void;\n  clearPropValue(path: string): void;\n  mergeProps(props: PropsMap): void;\n  setProps(props?: PropsMap | PropsList | Props | null): void;\n\n  // Node\n  get parent(): ParentalNode | null;\n  get children(): NodeChildren | null;\n  get nextSibling(): Node | null;\n  get prevSibling(): Node | null;\n  remove(useMutator?: boolean, purge?: boolean): void;\n  select(): void;\n\thover(flag?: boolean): void;\n  replaceChild(node: Node, data: any): Node;\n  mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any): void;\n  removeChild(node: Node): void;\n  insert(node: Node, ref?: Node, useMutator?: boolean): void;\n  insertBefore(node: any, ref?: Node, useMutator?: boolean): void;\n  insertAfter(node: any, ref?: Node, useMutator?: boolean): void;\n\n  // Schema\n  get schema(): Schema;\n  set schema(data: Schema);\n  export(stage?: TransformStage): Schema;\n\treplaceWith(schema: Schema, migrate?: boolean): any;\n}\n```\n\n这里没有展示全部的方法，但是我们可以发现，`Node` 节点模型核心功能点有三个：\n\n1. `Props` 管理：通过 `Props` 实例管理所有的 `Prop`，包括新增、设置、删除等 `Prop` 相关操作。\n2. `Node` 管理：管理 `Node` 树的关系，修改当前 `Node` 节点或者 `Node` 子节点等。\n3. `Schema` 管理：可以通过 `Node` 获取当前层级的 `Schema` 描述协议内容，并且也可以修改它。\n\n通过 `Node` 这一层级，对 `Props`、`Node` 树和 `Schema` 的管理粒度控制到最低，这样扩展性也就更强。\n\n#### 属性模型（Prop）\n\n一个 `Props` 对应多个 `Prop`，每一个 `Prop` 对应 schema 的 `props` 下的一个字段。\n\n`Props` 管理的是 `Node` 节点模型中的 `props` 字段下的内容。而 `Prop` 管理的是 `props` 下的每一个 `key` 的内容，例如下面的示例中，一个 `Props` 管理至少 6 个 `Prop`，而其中一个 `Prop` 管理的是 `showTitle` 的结果。\n\n```javascript\n{\n  props: {\n    showTitle: false,\n    behavior: 'NORMAL',\n    content: {\n      use: 'zh_CN',\n      en_US: 'Title',\n      zh_CN: '个人信息',\n      type: 'i18n',\n    },\n    fieldId: 'text_k1ow3h1j',\n    maxLine: 0,\n  },\n}\n```\n#### 组件描述模型（ComponentMeta）\n\n编排已经等价于直接操作节点 & 属性了，而一个节点和一组对应的属性相当于一个真实的组件，而真实的组件一定是有约束的，比如组件名、组件类型、支持哪些属性以及属性类型、组件能否拖动、支持哪些扩展操作、组件是否是容器型组件、A 组件中能否放入 B 组件等等。\n\n于是，我们设计了一份协议专门负责组件描述，即《中后台搭建组件描述协议》，而编排模块中也有负责解析和使用符合描述协议规范的模块。\n\n每一个组件对应一个 `ComponentMeta` 的实例，其属性和方法就是描述协议中的所有字段，所有 `ComponentMeta` 都由设计器器的 `designer` 模块进行创建和管理，其他模块通过 `designer` 来获取指定的 `ComponentMeta` 实例，尤其是每个 `Node` 实例上都会挂载对应的 `ComponentMeta` 实例。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01NSh0LI1b150RUzOUc_!!6000000003404-2-tps-998-756.png)\n\n组件描述模型是后续编排辅助的基础，包括设置面板、拖拽定位机制等。\n#### 项目、文档、节点和属性模型关系\n\n整体来看，一个 Project 包含若干个 DocumentModel 实例，每个 DocumentModel 包含一组 Node 构成一颗树（类似 DOM 树），每个 Node 通过 Props 实例管理所有 Prop。整体的关系图如下。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01mufxpY1qCGvDTSdw9_!!6000000005459-2-tps-1694-1356.png)\n\n节点 & 属性模型是引擎基石，几乎贯穿所有模块，相信从上面的类图已经能看出几个基础类的职责以及依赖关系。\n\n节点 & 属性模型等价于 JSON 数据结构，而编排的本质是产出 JSON 数据结构，现在可以重新表述为编排的本质是操作节点 & 属性模型了。\n\n```typescript\n// 一段编排的示例代码\nrootNode.insertAfter({ componentName: 'Button', props: { size: 'medium' } });\nrootNode.insertAfter({ componentName: 'Button', props: { size: 'medium' } });\nrootNode.children.get(1).getProp('size').setValue('large');\nrootNode.children.get(2).remove();\nrootNode.export();\n// => 产出 schema\n```\n\n### 画布渲染\n\n画布渲染使用了设计态与渲染态的双层架构。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01cZ6Q32260qtiDofwi_!!6000000007600-2-tps-1416-710.png)\n\n如上图，设计器和渲染器其实处在不同的 Frame 下，渲染器以单独的 `iframe` 嵌入。这样做的好处，一是为了给渲染器一个更纯净的运行环境，更贴近生产环境，二是扩展性考虑，让用户基于接口约束自定义自己的渲染器。\n\n#### xxx-renderer\n\nxxx-renderer 是一个纯 renderer，即一个渲染器，通过给定输入 schema、依赖组件和配置参数之后完成渲染。\n\n#### xxx-simulator-renderer\n\nxxx-simulator-renderer 通过和 host 进行通信来和设计器打交道，提供了 `DocumentModel` 获取 schema 和组件。将其传入 xxx-renderer 来完成渲染。\n\n另外其提供了一些必要的接口，来帮助设计器完成交互，比如点击渲染画布任意一个位置，需要能计算出点击的组件实例，继而找到设计器对应的 Node 实例，以及组件实例的位置/尺寸信息，让设计器完成辅助 UI 的绘制，如节点选中。\n\n#### react-simulator-renderer\n\n以官方提供的 react-simulator-renderer 为例，我们看一下点击一个 DOM 节点后编排模块是如何处理的。\n\n首先在初始化的时候，renderer 渲染的时候会给每一个元素添加 ref，通过 ref 机制在组件创建时将其存储起来。在存储的时候我们给实例添加 `Symbol('_LCNodeId')` 的属性。\n\n当点击之后，会去根据 `__reactInternalInstance$` 查找相应的 fiberNode，通过递归查找到对应的 React 组件实例。找到一个挂载着 `Symbol('_LCNodeId')` 的实例，也就是上面我们初始化添加的属性。\n\n通过 `Symbol('_LCNodeId')` 属性，我们可以获取 Node 的 id，这样我们就可以找到 Node 实例。\n\n通过 `getBoundingClientRect` 我们可以获取到 Node 渲染出来的 DOM 的相关信息，包括 `x`、`y`、`width`、`height` 等。\n\n通过 DOM 信息，我们将 focus 节点所需的标志渲染到对应的地方。hover、拖拽占位符、resize handler 等辅助 UI 都是类似逻辑。\n\n#### 通信机制\n\n既然设计器和渲染器处于两个 Frame，它们之间的事件通信、方法调用是通过各自的代理对象进行的，不允许其他方式，避免代码耦合。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01hxtg7X1M3AZsAdt83_!!6000000001378-2-tps-1290-648.png)\n\n##### host\nhost 可以访问设计器的所有模块，由于 renderer 层不负责与设计器相关的交互。所以增加了一层 host，作为通信的中间层。host 可以访问到设计器中所有模块，并提供相关方法供 simulator-renderer 层调用。例如 schema 的获取、组件获取等。\n\nsimulator-renderer 通过调用 host 的方法，将 schema、components 等参数传给 renderer，让 renderer 进行渲染。\n\n##### xxx-simulator-renderer\n\n为了完成双向交互，simulator-renderer 也需要提供一些方法来供 host 层调用，之后当设计器和用户有交互，例如上述提到的节点选中。这里需要提供的方法有：\n\n- getClientRects\n- getClosestNodeInstance\n- findDOMNodes\n- getComponent\n- setNativeSelection\n- setDraggingState\n- setCopyState\n- clearState\n\n这样，host 和 simulator-renderer 之间便通过相关方法实现了双向通信，能在隔离设计器的基础上完成设计器到画布和画布到设计器的通信流程。\n\n### 编排辅助的核心\n#### 设置面板与设置器\n当在渲染画布上点击一个 DOM 节点，我们可以通过 xxx-simulator-renderer 获取 `Node` 节点，我们在 `Node` 上挂载了 `ComponentMeta` 实例。通过 `ComponentMeta` 我们获取到当前组件的描述模型。通过描述模型，我们即可获得组件、即当前 Node 支持的所有属性配置。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01c7nkoo1OXyRhVAFlK_!!6000000001716-2-tps-1500-985.png)\n\n##### 设置面板\n\n设置面板对于配置项的呈现结构是通过 `ComponentMeta.configure` 来确定的。\n\n```json\n{\n  \"component\": {\n    \"isContainer\": true\n  },\n  \"props\": {\n    \"isExtends\": true,\n    \"override\": [\n      {\n        \"name\": \"count\",\n        \"title\": {\n          \"label\": \"展示的数字\",\n          \"tip\": \"count|大于 overflowCount 时显示为 ${overflowCount}+，为 0 时默认隐藏\",\n          \"docUrl\": \"https://fusion.alibaba-inc.com/pc/component/basic/badge\"\n        },\n        \"setter\": {\n          \"componentName\": \"MixedSetter\",\n          \"props\": {\n            \"setters\": [\n              \"StringSetter\",\n              \"ExpressionSetter\"\n            ]\n          }\n        }\n      }\n    ]\n  }\n}\n```\n\n上述的 `component.isContainer` 描述了这个组件是否是一个容器组件。而 props 下的属性就是我们在设置面板中展示的属性，包含了这个属性的名称、使用的设置器、配置之后影响的是哪个属性等。\n\n而这只是描述，编排模块的 `SettingTopEntry` 便是管理设置面板的实现模块。\n\n`SettingTopEntry` 包含了 n 个 `SettingField`，每一个 `SettingField` 就对应下面要将的设置器。即 `SettingTopEntry` 负责管理多个 `SettingField`。\n\n##### 设置器\n选中节点可供配置的属性都有相应的设置器配置，比如文本、数字、颜色、JSON、Choice、I18N、表达式 等等，或者混合多种。\n\n设置器本质上是一个 React 组件，但是设置面板在渲染时会传入当前配置项对应的 `SettingField` 实例，`SettingField` 本质上就是包裹了 `Prop` 实例，设置器内部的行为以及 UI 变化都由设置器自己把控，但当属性值发生变化时需要通过 `SettingField` 下的 `Prop` 来修改值，因为修改 `Prop` 实例就相当于修改了 schema。一方面这样的设置器设置之后，保存的 schema 才是正确的，另外一方面，只有 schema 变化了，才能触发渲染画布重新渲染。\n\n#### 拖拽引擎 & 拖拽定位机制\n\n![](https://img.alicdn.com/imgextra/i4/O1CN01G8zyBw1OkL8m0FG4J_!!6000000001743-1-tps-1425-917.gif)\n\n拖拽引擎（`Dragon`）核心完成的工作是将被拖拽对象拖拽到目标位置，涉及到几个概念：\n\n- 被拖拽对象 - `DragObject`\n- 拖拽到的目标位置 - `DropLocation`\n- 拖拽感应区 - `IPublicModelSensor`\n- 定位事件 - `LocateEvent`\n\n##### Sensor\n\n在引擎初始化的时候，我们监听 `document` 和 iframe `contentDocument` 的 `mouse`、`keyboard`、`drag` 事件来感知拖拽的发生。而这些监听的区域我们又称为拖拽感应区，也就是 `Sensor`。`Sensor` 会有多个，因为感应器有多个，默认设置器和设置面板是没有 `Sensor`，但是他们是可以注册 `Sensor` 来增加感应区域，例如大纲树就注册了自己的 `Sensor`。\n\n`Sensor` 有两个关键职责：\n1. 用于事件对象转换，比如坐标系换算。\n2. 根据拖拽过程中提供的位置信息，结合每一层 `Node` 也就是组件包含的描述信息，知道其是否能作为容器等限制条件，来进行进一步的定位，最后计算出精准信息来进行视图渲染。\n\n**拖拽流程**\n1. 在引擎初始化的时候，初始化多个 `Sensor`。\n2. 当拖拽开始的时候，开启 `mousemove`、`mouseleave`、`mouseover` 等事件的监听。\n3. 拖拽过程中根据 `mousemove` 的 `MouseEvent` 对象封装出 `LocateEvent` 对象，继而交给相应 `sensor` 做进一步定位处理。\n4. 拖拽结束时，根据拖拽的结果进行 schema 变更和视图渲染。\n5. 最后关闭拖拽开始时的事件监听。\n\n##### 拖拽方式\n根据拖拽的对象不同，我们将拖拽分为几种方式：\n1. **画布内拖拽：**此时 sensor 是 simulatorHost，拖拽完成之后，会根据拖拽的位置来完成节点的精确插入。\n2. **从组件面板拖拽到画布**：此时的 sensor 还是 simulatorHost，因为拖拽结束的目标还是画布。\n3. **大纲树面板拖拽到画布中**：此时有两个 sensor，一个是大纲树，当我们拖拽到画布区域时，画布区域内的 simulatorHost 开始接管。\n4. **画布拖拽到大纲树中**：从画布中开始拖拽时，最新生效的是 simulatorHost，当离开画布到大纲树时，大纲树 sensor 开始接管生效。当拖拽到大纲树的某一个节点下时，大纲树会将大纲树中的信息转化为 schema，然后渲染到画布中。\n### 其他\n\n引擎的编排能力远远不止上述所描述的功能，这里只描述了其核心和关键的功能。在整个引擎的迭代和设计过程中还有很多细节来使我们的引擎更好用、更容易扩展。\n\n#### schema 处理的管道机制\n\n通过 PropsReducer 的管道机制，用户可以定制自己需要的逻辑，来修改 Schema。\n\n#### 组件 metadata 处理的管道机制\n\n组件的描述信息都收拢在各自的 ComponentMeta 实例内，涉及到的消费方几乎遍及整个编排过程，包括但不限于 组件拖拽、拖拽辅助 UI、设置区、原地编辑、大纲树 等等。\n\n在用户需要自定义的场景，开放 ComponentMeta 的修改能力至关重要，因此我们设计了 metadata 初始化/修改的管道机制。\n\n#### hotkey & builtin-hotkey\n\n快捷键的实现，以及引擎内核默认绑定的快捷键行为。\n\n#### drag resize 引擎\n\n对于布局等类型的组件，支持拖拽改变大小。resize 拖拽引擎根据组件 ComponentMeta 声明来开启，拖拽后，触发组件的钩子函数（`onResizeStart` / `onResize` / `onResizeEnd`），完成 resize 过程。\n\n#### OffsetObserver\n\n设计态的辅助 UI 需要根据渲染态的视图变化而变化，比如渲染容器滚动了，此时通过 OffsetObserver 做一个动态的监听。\n\n#### 插件机制\n\n我们希望保持引擎内核足够小，但拥有足够强的扩展能力，所有扩展功能都通过插件机制来承载。\n"
  },
  {
    "path": "docs/docs/guide/design/generator.md",
    "content": "---\ntitle: 出码模块设计\nsidebar_position: 5\n---\n\n本篇主要讲解了出码模块实现的基本思路与一些概念。如需接入出码和定制出码方案，可以参考《[使用出码功能](/site/docs/guide/expand/runtime/codeGeneration)》一节。\n\n## npm 包与仓库信息\n\n| **NPM 包** | **代码仓库** | **说明** |\n| --- | --- | --- |\n| [@alilc/lowcode-code-generator](https://www.npmjs.com/package/@alilc/lowcode-code-generator) | [alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine)（子目录：modules/code-generator）| 出码模块核心库，支持在 node 环境下运行，也提供了浏览器下运行的 standalone 模式 |\n| [@alilc/lowcode-plugin-code-generator](https://www.npmjs.com/package/@alilc/lowcode-plugin-code-generator) | [alibaba/lowcode-code-generator-demo](https://github.com/alibaba/lowcode-code-generator-demo) | 出码示例 -- 浏览器端出码插件 |\n\n## 出码模块原理\n\n出码模块的输入和输出很简单：\n![](https://img.alicdn.com/imgextra/i3/O1CN01OkDmKq1xMX6Xxv6co_!!6000000006429-0-tps-1262-346.jpg)\n\n这里有几个概念：\n\n- schema: 搭建协议内容，指符合《阿里巴巴中后台前端搭建协议规范》的 schema\n- solution：出码方案，指具体的项目框架（如 Rax，Ice.js)\n- Source Codes：生成的源代码，以目录树的形式进行描述\n\n可以看出，这是一个与用户基本没有交互，通过既定的流程完成整个功能链路的模块。其核心暴露的是一个将搭建协议 schema 按既定的 solution 转换为代码的函数。对于使用者来说就是一个输入输出都确定的黑盒系统。\n\n### 出码流程概述\n\n出码模块和编译器很类似，都是将代码的一种表现形式转换成另一种表现形式，如：\n\n#### 编译器流程\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN019F21Lb1bsCwvNcWRq_!!6000000003520-2-tps-3228-492.png)\n\n#### 出码模块流程\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01SEcVta1uLD72W0URZ_!!6000000006020-2-tps-1536-182.png)\n\n### 出码流程详解\n#### 协议解析\n\n协议解析主要是将输入的 schema 解析成更适合出码模块内部使用的数据结构的过程。这样在后面的代码生成过程中就可以直接用这些数据，不必重复解析了。\n\n![](https://img.alicdn.com/imgextra/i3/O1CN016EeitG1giCNCNTLVF_!!6000000004175-0-tps-1282-515.jpg)\n\n主要步骤如下：\n\n- 解析三方组件依赖\n- 分析 ref API 的使用情况\n- 建立容器之间的依赖关系索引\n- 分析容器内的组件依赖关系\n- 分析路由配置\n- 分析 utils 和 NPM 包依赖关系\n- 其他兼容处理\n\n#### 前置优化\n\n前置优化是计划基于策略对 schema 做一些优化。\n\n主要逻辑分为分析、规则和优化三个部分，组合为一个支持通过配置进行一定程度定制化的策略包。每个策略包会先执行分析器，对输入进行特征提取，然后通过规则对特征进行判断，决定是否执行优化动作：\n\n![](https://img.alicdn.com/imgextra/i4/O1CN01P0Lw7v1lfyWtfQTuR_!!6000000004847-2-tps-994-278.png)\n\n#### 代码生成\n代码生成的流程如下：\n![](https://img.alicdn.com/imgextra/i1/O1CN01lhcWBg1RG3nsoSoY2_!!6000000002083-2-tps-1468-464.png)\n\n如果简单粗暴地拼字符串生成源代码将难以扩展和维护，因此出码模块在代码生成过程中将代码进行了一些抽象化。\n\n日常开发中，我们常常是基于某一个特定的项目框架，将一些配置、UI 代码、逻辑代码放到他们应该在的地方，最终形成一套可以 run 起来的业务系统。那么其实对于出码这件事，我们也可以层层拆解，**项目 -> 插槽 -> 模块 -> 文件 -> 代码块**（代码片段）。这样就能将复杂的项目产出问题，拆分为一个个相对专注且单一的代码块产出问题，同时也支持组合复用。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01vOGmBT1JaegccXDt8_!!6000000001045-2-tps-892-454.png)\n\n注：中间表达结构即为对 Schema 解析后的结构化产物\n\n##### 插槽\n\n首先来看下插槽，插槽描述了对应模块在项目中相对路径，并且可以对模块做固定的命名。每个插槽都有一系列插件来完成代码产出工作。生成的一个或多个文件，最终会依照插槽的描述放入项目中。\n\n```typescript\n// 项目模版\nexport interface IProjectTemplate {\n  slots: Record<string, IProjectSlot>;\n}\n\n// 插槽\ninterface IProjectSlot {\n  path: string[];\n  fileName?: string;\n}\n\n// 插槽出码插件配置\ninterface IProjectPlugins {\n  [slotName: string]: BuilderComponentPlugin[];\n}\n```\n##### 代码块\n\n代码块是出码产物的最小单元，由出码模块插件产出，多个代码块最后会被组装为代码文件。每个代码块通过 name 描述自己，再通过 linkAfter 描述应该跟在哪些 name 的代码块后面。\n\n```typescript\ninterface ICodeChunk {\n  type: ChunkType;        // 处理类型 ast | string | json\n  fileType: string;       // 文件类型 js | css | ts ...\n  name: string;           // 代码块名称，与 linkAfter 相关\n  subModule?: string;     // 模块内文件名，默认是 index\n  content: ChunkContent;  // 代码块内容，数据格式与 type 相关\n  linkAfter: string[];\n}\n```\n\n#### 后置优化\n\n后置优化分为文件级别和项目级别两种：\n\n- 文件级别：在生成完一个文件后进行处理\n- 项目级别：在所有文件都生成完了之后进行处理\n\n文件级别的后置优化目前主要是有 prettier 这个代码格式化工具。\n"
  },
  {
    "path": "docs/docs/guide/design/materialParser.md",
    "content": "---\ntitle: 入料模块设计\nsidebar_position: 2\n---\n## 介绍\n入料模块负责物料接入，通过自动扫描、解析源码组件，产出一份符合《中后台低代码组件描述协议》的** **JSON Schema。这份 Schema 包含基础信息和属性描述信息部分，低代码引擎会基于它们在运行时自动生成一份 configure 配置，用作设置面板展示。\n\n## npm 包与仓库信息\n\n- npm 包：@alilc/lowcode-material-parser\n- 仓库：[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的 modules/material-parser\n\n## 原理\n入料模块使用动静态分析结合的方案，动态胜在真实，静态胜在细致，不过全都依赖源码中定义的属性，若未定义，或者定义错误，则无法正确入料。\n\n### 整体流程\n大体分为本地化、扫描、解析、转换、校验 5 部分，如下图所示。\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01sXf5fL1E5RcRxAlM1_!!6000000000300-2-tps-2116-206.png)\n\n### 静态解析\n在静态分析时，分为 JS 和 TS 两种情况。\n\n#### 静态解析 JS\n在 JS 情况下，基于 react-docgen 进行扩展，自定义了 resolver 及 handler，前者用于寻找组件定义，后者用于解析 propTypes、defaultProps 等信息，整体流程图如下：\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01VrhkEb1R6tsntvGhV_!!6000000002063-2-tps-2176-478.png)\n\nreact-docgen 使用 babel 生成语法树，再使用 ast-types 进行遍历去寻找组件节点及其属性类型定义。原本的 react-docgen 只能解析单文件，且不能解析 IIFE、逗号表达式等语法结构 (一般出现在转码后的代码中)。笔者对其进行改造，使之可以递归解析多文件去查找组件定义，且能够解开 IIFE，以及对逗号表达式进行转换，以方便后续的组件解析。另外，还增加了子组件解析的功能，即类似 `Button.Group = Group` 这种定义。\n\n#### 静态解析 TS\n在 TS 情况下，还要再细分为 TS 源码和 TS 编译后的代码。\nTS 源码中，React 组件具有类型签名；TS 编译后的代码中，dts 文件 (如有) 包含全部的 class / interface / type 类型信息。可以从这些类型信息中获取组件属性描述。整体流程图如下：\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN014lOIIy1FUvGW6wcYZ_!!6000000000491-2-tps-2280-240.png)\n\nreact-docgen 内置了 TypeScript 的 babel 插件，所以也具备解析 interface 的能力，可惜能力有限，babel 只能解析 TS 代码，但没法做类型检查，类型处理是由 react-docgen 实现的，它对于 extends/implements/utility 的情况处理不好，并且没有类型推断，虽然可以对其功能进行完善，不过这种情况下，应该借助 TypeScript Compiler 的能力，而非自己造轮子。通过调研，发现市面上有 typescript-react-docgen 这个项目。它在底层依赖了 TypeScript，且产出的数据格式与 react-docgen 一致，所以我们选择基于它进行解析。\n\nTypeScript Compiler 会递归解析某个文件中出现及引用的全部类型，当然，前提是已经定义或安装了相应的类型声明。typescript-react-docgen 会调用 TypeScript Compiler 的 API，获取每个文件输出的类型，判断其是否为 React 组件。满足下列条件之一的，会被判定为 React 组件：\n\n1. 获取其函数签名，如果只有一个入参，或者第一个入参名称为 props，会被判定为函数式组件；\n2. 获取其 `constructor` 方法，如果其返回值包含 props 属性，会被判定为有状态组件。\n\n然后，遍历组件的 props 类型，获取每个属性的类型签名字符串，比如 `(a: string) => void`。typescript-react-docgen 可以克服 react-docgen 解析 TypeScirpt 类型的问题，但是每个类型都以字符串的形式来呈现，不利于后续的解析。所以，笔者对其进行了扩展，递归解析每一层的属性值。此外，在函数式组件的判定上，笔者做了完善，会看函数的返回值是否为 `ReactElement` ，若是，才为函数式组件。\n\n下面讲对于一些特殊情况的处理。\n\n**循环定义**\n\nTypeScript 类型可以循环定义，比如下面的 JSON 类型：\n\n```typescript\ninterface Json {\n  [x: string]: string | number | boolean | Json | JsonArray;\n}\ntype JsonArray = Array<string | number | boolean | Json | JsonArray>;\n```\n\n因为低代码组件描述协议中没有引用功能，而且也不方便在界面上展示出来，所以这种循环定义无需完全解析，入料模块会在检测到循环定义的时候，把类型简化为 `object` 。对于特殊的类型，如 JSON，可以用相应的 Setter 来编辑。\n\n**复杂类型**\nTypeScript Compiler 会将合成类型的所有属性展开，比如 `boolean | string`，会被展开为 `true | false | string`，这带来了不必要的精确，我们需要的只是 `boolean | string` 而已。当然，对于这个例子，我们很容易把它还原回 `boolean | string`，然而，对于诸如 `React.ButtonHTMLAttributes<any> & {'data-name': string}` 这种类型，它会把 `ButtonHTMLAttributes` 中众多的属性和 `data-name` 混杂在一起，完全无法分辨，只能以展开的形式提供。这 100 多个属性，如果都放在设置面板，绝对是使用者的噩梦，所以，其结果会被简化为 `object` 。当然，即使没有 `{'data-name': string}`，`ButtonHTMLAttributes` 也是没有单独的 Setter 的，同样会被简化为 `object` 。\n\n### 动态解析\n\n当一个组件，使用静态解析无法入料时，会使用动态解析。\n\n整体流程图如下：\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01dJ62Dm1u5de8GihG6_!!6000000005986-2-tps-2516-449.png)\n\n基本思想很简单，require 组件进来，然后读取其组件类上定义的 propTypes 和 defaultProps 属性。这里使用了 parse-prop-types 库，使用它的时候必须在组件之前引用，因为它会先对 prop-types 库进行修改，在每个 PropTypes 透出的函数上挂上类型，比如 string, number 等等，然后再去遍历。动态解析可以解析出全部的类型信息，因为 PropTypes 有可能引入依赖组件的一些类型定义，这在静态解析中很难做到，或者成本较高，而对于动态解析来说，都由运行时完成了。\n\n##### 技术细节\n\n值得注意的是，有些 js 文件里还会引入 css 文件，而且从笔者了解的情况来看，这种情况在集团内部不在少数。这种组件不配合 webpack 使用，肯定会报错，但是使用 webpack 会明显拖慢速度，所以笔者采用了 sandbox 的方式，对 require 进来的类 css 文件进行 mock。这里，笔者使用了 vm2 这个库，它对 node 自带的 vm 进行了封装，可以劫持文件中的 require 方法。因为 parse-prop-types 的修改在沙箱中会失效，所以笔者也 mock 了组件中的 prop-types 库。\n\n### 整体大图\n把上述的静态解析和动态解析流程结合起来，可以得到以下大图。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01TA9lQp27QmwVT7WUC_!!6000000007792-2-tps-2658-1072.png)\n"
  },
  {
    "path": "docs/docs/guide/design/renderer.md",
    "content": "---\ntitle: 渲染模块设计\nsidebar_position: 4\n---\n## 低代码渲染介绍\n\n<img src=\"https://img.alicdn.com/imgextra/i1/O1CN01TXW6Ku1iQSGIPzncW_!!6000000004407-2-tps-1440-872.png\" width=\"400\"/>\n\n基于 Schema 和物料组件，如何渲染出我们的页面？这一节描述的就是这个。\n\n## npm 包与仓库信息\n\n- React 框架渲染 npm 包：@alilc/lowcode-react-renderer\n- 仓库：[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的\n   - packages/renderer-core\n   - packages/react-renderer\n   - packages/react-simulator-renderer\n\n## 渲染框架原理\n### 整体架构\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01i4IiSR1cMtUFXaWQq_!!6000000003587-2-tps-1686-1062.png)\n\n- 协议层：基于[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec) 产出的 Schema 作为我们的规范协议。\n- 能力层：提供组件、区块、页面等渲染所需的核心能力，包括 Props 解析、样式注入、条件渲染等。\n- 适配层：由于我们使用的运行时框架不是统一的，所以统一使用适配层将不同运行框架的差异部分，通过接口对外，让渲染层注册/适配对应所需的方法。能保障渲染层和能力层直接通过适配层连接起来，能起到独立可扩展的作用。\n- 渲染层：提供核心的渲染方法，由于不同运行时框架提供的渲染方法是不同的，所以其通过适配层进行注入，只需要提供适配层所需的接口，即可实现渲染。\n- 应用层：根据渲染层所提供的方法，可以应用到项目中，根据使用的方法和规模即可实现应用、页面、区块的渲染。\n\n### 核心解析\n\n这里主要解析一下刚刚提到的架构中的适配层和渲染层。\n\n#### 适配层\n适配层提供的是各个框架之间的差异项。比如 `React.createElement` 和 `Rax.createElement` 方法是不同的。所以需要在适配层对 API 进行抹平。\n\n##### React\n```typescript\nimport { createElement } from 'react';\nimport {\n  adapter,\n} from '@ali/lowcode-renderer-core';\n\nadapter.setRuntime({\n  createElement,\n});\n```\n##### Rax\n```typescript\nimport { createElement } from 'rax';\nimport {\n  adapter,\n} from '@ali/lowcode-renderer-core';\n\nadapter.setRuntime({\n  createElement,\n});\n```\n这时，在核心层使用的 `createElement` 会基于使用不同的 renderer 而使用不同的方法，自动适配框架所需的运行时方法。\n\n所需的方法包括：\n\n- `setRuntime`：设置运行时相关方法\n   - `Component`：组件类，参考 React 的 `Component`。\n   - `PureComponent`：组件类，参考 React 的 `PureComponent`。\n   - `createContext`：创建一个 `Context` 对象的方法。例如，当 React 渲染一个订阅了这个 `Context` 对象的组件，这个组件会从组件树中离自身最近的那个匹配的 `Provider` 中读取到当前的 `context` 值。\n   - `createElement`：创建 `Component` 元素，例如在 React 中即为创建 React 元素。\n   - `forwardRef`：ref 转发的方法。Ref 转发是一个可选特性，其允许某些组件接收 ref，并将其向下传递（换句话说，“转发”它）给子组件。\n   - `findDOMNode`：是一个访问底层 DOM 节点的方法。如果组件已经被挂载到 DOM 上，此方法会返回浏览器中相应的原生 DOM 元素。\n- `setRenderers`\n   - `PageRenderer`：页面渲染的方法。可以定制页面渲染的生命周期，定制导航，定制路由等。\n   - `ComponentRenderer`：组件渲染的方法。\n   - `BlockRenderer`：区块渲染的方法。\n\n#### 渲染层\n##### React Renderer\n内部的技术栈统一都是 React，大多数适配层的 API 都是按照 React 来设计的，所以对于 React Renderer 来说，需要做的不多。\n\nReact Renderer 的代码量很少，主要是将 React API 注册到适配层中。\n\n```typescript\nimport React, { Component, PureComponent, createElement, createContext, forwardRef, ReactInstance, ContextType } from 'react';\nimport ReactDOM from 'react-dom';\nimport {\n  adapter,\n  pageRendererFactory,\n  componentRendererFactory,\n  blockRendererFactory,\n  addonRendererFactory,\n  tempRendererFactory,\n  rendererFactory,\n  types,\n} from '@ali/lowcode-renderer-core';\nimport ConfigProvider from '@alifd/next/lib/config-provider';\n\nwindow.React = React;\n(window as any).ReactDom = ReactDOM;\n\nadapter.setRuntime({\n  Component,\n  PureComponent,\n  createContext,\n  createElement,\n  forwardRef,\n  findDOMNode: ReactDOM.findDOMNode,\n});\n\nadapter.setRenderers({\n  PageRenderer: pageRendererFactory(),\n  ComponentRenderer: componentRendererFactory(),\n  BlockRenderer: blockRendererFactory(),\n  AddonRenderer: addonRendererFactory(),\n  TempRenderer: tempRendererFactory(),\n  DivRenderer: blockRendererFactory(),\n});\n\nadapter.setConfigProvider(ConfigProvider);\n```\n\n##### Rax Renderer\nRax 的大多数 API 和 React 基本也是一致的，差异点在于重写了一些方法。\n```typescript\nimport { Component, PureComponent, createElement, createContext, forwardRef } from 'rax';\nimport findDOMNode from 'rax-find-dom-node';\nimport {\n  adapter,\n  addonRendererFactory,\n  tempRendererFactory,\n  rendererFactory,\n} from '@ali/lowcode-renderer-core';\nimport pageRendererFactory from './renderer/page';\nimport componentRendererFactory from './renderer/component';\nimport blockRendererFactory from './renderer/block';\nimport CompFactory from './hoc/compFactory';\n\nadapter.setRuntime({\n  Component,\n  PureComponent,\n  createContext,\n  createElement,\n  forwardRef,\n  findDOMNode,\n});\n\nadapter.setRenderers({\n  PageRenderer: pageRendererFactory(),\n  ComponentRenderer: componentRendererFactory(),\n  BlockRenderer: blockRendererFactory(),\n  AddonRenderer: addonRendererFactory(),\n  TempRenderer: tempRendererFactory(),\n});\n```\n\n### 多模式渲染\n#### 预览模式渲染\n预览模式的渲染，主要是通过 Schema、components 即可完成上述的页面渲染能力。\n```typescript\nimport ReactRenderer from '@ali/lowcode-react-renderer';\nimport ReactDOM from 'react-dom';\nimport { Button } from '@alifd/next';\n\nconst schema = {\n  componentName: 'Page',\n  props: {},\n  children: [\n    {\n      componentName: 'Button',\n      props: {\n        type: 'primary',\n        style: {\n          color: '#2077ff'\n        },\n      },\n      children: '确定',\n    },\n  ],\n};\n\nconst components = {\n  Button,\n};\n\nReactDOM.render((\n  <ReactRenderer\n    schema={schema}\n    components={components}\n  />\n), document.getElementById('root'));\n```\n\n#### 设计模式渲染（Simulator）\n设计模式渲染就是将编排生成的《搭建协议》渲染成视图的过程，视图是可以交互的，所以必须要处理好内部数据流、生命周期、事件绑定、国际化等等。也称为画布的渲染，画布是 UI 编排的核心，它一般融合了页面的渲染以及组件/区块的拖拽、选择、快捷配置。\n画布的渲染和预览模式的渲染的区别在于，画布的渲染和设计器之间是有交互的。所以在这里我们新增了一层 `Simulator` 作为设计器和渲染的连接器。\n`Simulator` 是将设计器传入的 `DocumentModel` 和组件/库描述转成相应的 Schema 和 组件类。再调用 Render 层完成渲染。我们这里介绍一下它提供的能力。\n##### 整体架构\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN017cYBAp1hvJKPUVLbx_!!6000000004339-2-tps-1500-864.png)\n\n- `Project`：位于顶层的 Project，保留了对所有文档模型的引用，用于管理应用级 Schema 的导入与导出。\n- `Document`：文档模型包括 Simulator 与数据模型两部分。Simulator 通过一份 Simulator Host 协议与数据模型层通信，达到画布上的 UI 操作驱动数据模型变化。通过多文档的设计及多 Tab 交互方式，能够实现同时设计多个页面，以及在一个浏览器标签里进行搭建与配置应用属性。\n- `Simulator`：模拟器主要承载特定运行时环境的页面渲染及与模型层的通信。\n- `Node`：节点模型是对可视化组件/区块的抽象，保留了组件属性集合 Props 的引用，封装了一系列针对组件的 API，比如修改、编辑、保存、拖拽、复制等。\n- `Props`：描述了当前组件所维系的所有可以「设计」的属性，提供一系列操作、遍历和修改属性的方法。同时保持对单个属性 Prop 的引用。\n- `Prop`：属性模型 Prop 与当前可视化组件/区块的某一具体属性想映射，提供了一系列操作属性变更的 API。\n- `Settings`：`SettingField` 的集合。\n- `SettingField`：它连接属性设置器 `Setter` 与属性模型 `Prop`，它是实现多节点属性批处理的关键。\n- 通用交互模型：内置了拖拽、活跃追踪、悬停探测、剪贴板、滚动、快捷键绑定。\n\n##### 模拟器介绍\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01GF1PMj288kxovvnK8_!!6000000007888-2-tps-1500-740.png)\n\n- 运行时环境：从运行时环境来看，目前我们有 React 生态、Rax 生态。而在对外的历程中，我们也会拥有 Vue 生态、Angular 生态等。\n- 布局模式：不同于 C 端营销页的搭建，中后台场景大多是表单、表格，流式布局是主流的选择。对于设计师、产品来说，是需要绝对布局的方式来进行页面研发的。\n- 研发场景：从研发场景来看，低代码搭建不仅有页面编排，还有诸如逻辑编排、业务编排的场景。\n\n基于以上思考，我们通过基于沙箱隔离的模拟器技术来实现了多运行时环境（如 React、Rax、小程序、Vue）、多模式（如流式布局、自由布局）、多场景（如页面编排、关系图编排）的 UI 编排。通过注册不同的运行时环境的渲染模块，能够实现编辑器从 React 页面搭建到 Rax 页面搭建的迁移。通过注册不同的模拟器画布，你可以基于 G6 或者 mxgraph 来做关系图编排。你可以定制一个流式布局的画布，也可以定制一个自由布局的画布。\n"
  },
  {
    "path": "docs/docs/guide/design/setter.md",
    "content": "---\ntitle: 设置器设计\nsidebar_position: 6\n---\n\n设置器，又称为 Setter，是作为物料属性和用户交互的重要途径，在编辑器日常使用中有着非常重要的作用，本文重点介绍 Setter 的设计原理和使用方式，帮助用户更好的理解 Setter。\n\n在编辑器的右边区域，Setter 的区块就展现在这里，如下图：\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01qEjjoQ24QNkD42wzl_!!6000000007385-2-tps-3836-1730.png)\n\n其中包含 属性、样式、事件、高级：\n\n- 属性：展示该物料常规的属性；\n- 样式：展示该物料样式的属性；\n- 事件：如果该物料有声明事件，则会出现事件面板，用于绑定事件；\n- 高级：两个逻辑相关的属性，**条件渲染**和**循环。**\n## npm 包与仓库信息\n\n- npm 包：@alilc/lowcode-engine-ext\n- 仓库：[https://github.com/alibaba/lowcode-engine-ext](https://github.com/alibaba/lowcode-engine-ext)\n\n## 设置器模块原理\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01EAmitQ1U5TUws63AV_!!6000000002466-2-tps-1534-964.png)\n\n设置面板依赖于以下三块抽象\n\n- 编辑器上下文 `editor`，主要包含：消息通知、插件引用等\n- 设置对象 `settingTarget`，主要包含：选中的节点、是否同一值、值的储存等\n- 设置列 `settingField`，主要和当前设置视图相关，包含视图的 `ref`、以及设置对象 `settingTarget`\n\n### SettingTarget 抽象\n\n如果不是多选，可以直接暴露 `Node` 给到这，但涉及多选编辑的时候，大家的值通常是不一样的，设置的时候需要批量设置进去，这里主要封装这些逻辑，把多选编辑的复杂性屏蔽掉。\n\n所选节点所构成的**设置对象**抽象如下：\n\n```typescript\ninterface SettingTarget {\n  // 所设置的节点集，至少一个\n  readonly nodes: Node[];\n  // 所有属性值数据\n  readonly props: object;\n  // 设置属性值\n  setPropValue(propName: string, value: any): void;\n  // 获取属性值\n  getPropValue(propName: string): any;\n  // 设置多个属性值，替换原有值\n  setProps(data: object): void;\n  // 设置多个属性值，和原有值合并\n  mergeProps(data: object): void;\n  // 绑定属性值发生变化时\n  onPropsChange(fn: () => void): () => void;\n}\n```\n\n基于设置对象所派生的**设置目标属性**抽象如下：\n\n```typescript\ninterface SettingTargetProp extends SettingTarget {\n  // 当前属性名称\n  readonly propName: string;\n  // 当前属性值\n  value: any;\n  // 是否设置对象的值一致\n  isSameValue(): boolean;\n  // 是否是空值\n  isEmpty(): boolean;\n  // 设置属性值\n  setValue(value: any): void;\n  // 移除当前设置\n  remove(): void;\n}\n```\n\n### SettingField 抽象\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01D855j01j8sg9GdtJr_!!6000000004504-2-tps-2022-402.png)\n\n```typescript\ninterface SettingField extends SettingTarget {\n  // 当前 Field 设置的目标属性，为 group 时此值为空\n  readonly prop?: SettingTargetProp;\n\n  // 当前设置项的 ref 引用\n  readonly ref?: ReactInstance;\n\n  // 属性配置描述传入的配置\n  readonly config: SettingConfig;\n  // others....\n}\n```\n"
  },
  {
    "path": "docs/docs/guide/design/specs.md",
    "content": "---\ntitle: 协议栈简介\nsidebar_position: 1\n---\n## 什么是低代码协议\n低代码引擎体系基于三份协议来构建，分别是 [《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)、[《低代码引擎物料协议规范》](/site/docs/specs/material-spec)和[《低代码引擎资产包协议规范》](/site/docs/specs/assets-spec), 它们保障了低代码领域的标准化，成为了生态建设和流通的基石。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01axsOyW1s01YgXnT8z_!!6000000005703-2-tps-1888-1000.png)\n\n## 为什么需要协议\n\n首先，我们做一个不恰当的类比，我们将低代码引擎和 JavaScript 语言做一下类别。还记得之前，大家都被浏览器兼容性支配的恐惧，特别是 IE 和其他浏览器，对上层 API 实现的不一致，导致一份代码需要运行在两端需要做适配。当浏览器 / JavaScript 相关的标准出现之后，各个浏览器进行了 API 的统一，使得我们终于可以从这部分工作中解放出来（PS：Babel 对于语言特性的转换是另一个方面的问题）。\n\n而在《低代码引擎搭建协议规范》出现之前，低代码领域也有类似的问题。\n\n### 概念不通\n\n在交流的过程中，一些对于搭建产品的术语的不一致，导致了一些沟通成本，不管是在文章分享、技术分享、交流会上，都会有这个问题。\n\n### 物料孤岛\n\n由于低代码产品实现的方式不同，物料的消费方式也各不相同。这里分为两种物料，低代码物料和 ProCode 物料。\n\n对于低代码物料来说，A 平台创建的物料无法使用到 B 平台上，如果想在 B 平台实现同样的物料，需要按照 B 平台的标准搭建一份物料。\n\n对于 ProCode 物料来说，需要在低代码平台进行消费，是需要进行转换的，包括搭建配置项的生成、物料搭建视图等，可能还需要特殊的描述文件进行描述。由于这一层没有统一，同一份 ProCode 物料每接入一个低代码，可能需要的描述文件格式不同，转换的代码不同，使用的工具也不同。\n\n### 生态隔离\n\n不同低代码平台的生态体系也不相同，有的低代码平台的物料生态不错，有的低代码平台的搭建体验生态不错。但是这些利好的生态，都是无法互通的，甚至就算知道了代码也无法复用，因为底层是不一致的。对于阿里巴巴集团来说，每一个平台都创建一份自己的生态，这并不是利好的。\n\n### 低水平重复建设\n\n大家可能觉得，以上问题对于自己造轮子来说，其实也是有利的，因为自己得到了技术上的成长。\n\n但是对于低代码的平台方，实际上更多的工作，在物料的转化、物料的生成、搭建体验的小优化、部分其他平台生态的实现。这些的技术深度其实并不高，属于低水平重复建设部分。\n\n### 价值不高\n\n如果每个业务都要从 0 开始做，做自己的平台，会花费大量的时间来构建底层基础设施，对业务本身而言并不是一件好事；而且前端领域的底层基础设施都大同小异，不同团队重复构建造成了极大的资源浪费。\n\n这样的建设，会导致从 0 到 1 都需要花费大量的时间，往往在内部人力不足、投入有限时，产品很容易在未发展壮大的时候就面临了死亡相关的决策。\n\n设想一下，如果可以开发一份全集团低代码平台都可以使用的物料，是否更有成就感呢？如果可以基于已有生态进行低代码平台的快速落地，而不是花费 1-2 年搭建一个可用的低代码平台，再验证市场。在快速的验证之后，再进行更深入的打磨，这其中的思考和技术含量是否更优于之前的模式呢？\n\n以 2019 年的阿里巴巴的情况举例，不同平台的低代码物料但不限于：\n\n1. vc-deep — vc 协议 + Deep 组件库 (阿里巴巴企业智能团队基于 Fusion Next 定制)；\n2. Iceluna 协议 + Fusion Next；\n3. AIMake 物料；\n4. vc-fusion-basic + 业务改造 — vc 协议 + Fusion Next(各业务 Fork 定制)；\n5. vision 魔改 + vc 协议扩展 + fusion 业务组件；\n6. vc 协议 + antd；\n\n可以看到，各个搭建平台都需要维护一套自己的基础组件库，这是非常不合理的，对基础组件库的维护会分散开发同学完成业务目标的精力。\n\n建立统一的低代码领域标准化，是百利而无一害的。于是，在阿里巴巴集团 2020 年进行了讨论，建立了搭建治理&物料流通战役，此战役便产出了上文中的协议规范，成为了低代码引擎和其生态的基础。\n\n## 协议的作用\n\n基于统一的协议，我们完成业务组件、区块、模板等各类物料的标准统一，各类中后台研发系统生产的物料可借助物料中心进行跨系统流通，通过丰富物料生态的共享提升各平台研发系统的效率。同时完成低代码引擎的标准统一以及低代码搭建中台能力的输出，帮助业务方快速孵化本业务域中后台研发系统。\n\n### 打破物料孤岛\n\n#### 物料中心\n\n这里以阿里集团的前端物料中间建设为例，在《低代码引擎物料协议规范》落地之后，建立了阿里巴巴各个中后台研发平台沟通、对话的基础，物料流通的先决条件已经成熟，这个时候我们还需要一个统一的物料源，用于管理物料的上传、存储、检索、分发，一个典型的中心化架构，类似 npm 的管理，这便是我们物料中心。\n\nFusion Market 是物料中心的前身，它提供了业务组件的存储、文档展示和全局透出的功能，由于 fusion 体系在集团内的广泛使用，Fusion Market 沉淀了不少的业务组件，但是这个项目却一直不温不火，只看到业务组件数量的增加，却未看到物料流通起来。其中一个原因是，没有阿里巴巴前端委员会的背书，规范很难统一，规范如果不统一，物料就很难流通；\n\n在规范成立之后，物料中心也将有了建设的基础，最终于 2019 年建立了物料中心，提供了物料流通的平台能力。\n\n#### 低代码基础物料\n\n就像 AntD、Element 之于源码研发模式，在低代码研发模式下各个搭建平台也需要一套统一的、开箱即用的低代码基础组件库。基于低代码描述协议完成了两份低代码基础物料的建设，即“Fusion 低代码基础组件库”和“AntD 低代码基础组件库”。\n\n#### 源码组件低代码化\n\n将源码组件一键转化为低代码物料，符合低代码物料规范，可以在低代码平台进行流通。\n### 低代码物料中心\n\n当低代码物料积累到一定的量级之后，所有的搭建平台的业务物料越来越多。这些物料通过低代码物料中心进行统一的管理和消费。\n### 设置器生态的基础\n\nSnippet(组件默认搭建 schema ) 由《低代码引擎搭建协议规范》定义，低代码引擎会按照规范对组件进行渲染，Configure 由《低代码引擎物料协议规范》定义，它描述了组件的 props 以及每个 prop 对应的设置器 (Prop 配置面板)，低代码引擎提供了 20+ 个内置设置器，但如果我们组件的 props 超出了引擎内置设置器的范围，就需要我们自己来开发对应设置器。\n设置器最终也慢慢形成了自己的生态，这使得开发物料更加容易，可以使用已有的生态中的设置器，进行物料配置描述。\n### 低代码引擎实现标准\n\n低代码引擎是以上生态的消费端，它是实现了标准协议的低代码引擎。这是不可或缺的部分，低代码引擎这里就相当于一个标准浏览器，一方面给其他的低代码平台提供了一个 Demo，其他平台可以参考低代码引擎进行实现，满足官方协议，便也可以消费相关的物料生态和其他生态。\n"
  },
  {
    "path": "docs/docs/guide/design/summary.md",
    "content": "---\ntitle: 架构综述\nsidebar_position: 0\n---\n## 分层架构描述\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN016l8gDo1z7zlRlW1P0_!!6000000006668-2-tps-1920-1080.png)\n\n我们设计了这样一套分层架构，自下而上分别是协议 - 引擎 - 生态 - 平台。\n\n- 底层协议栈定义的是标准，**标准的统一让上层产物的互通成为可能**。\n- 引擎是**对协议的实现**，同时通过能力的输出，向上**支撑生态开放体系**，提供各种生态扩展能力。\n- 生态就好理解了，是基于引擎核心能力上扩展出来的，比如物料、设置器、插件等，还有工具链支撑开发体系。\n- 最后，各个平台基于引擎内核以及生态中的产品组合、衔接形成满足其需求的低代码平台。\n\n**每一层都明确自身的定位，各司其职，协议不会去思考引擎如何实现，引擎也不会实现具体上层平台功能，上层平台的定制化均通过插件来实现，这些理念将会贯穿我们体系设计、实现的过程。**\n\n## 引擎内核简述\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01QUUVu21LjTXqY6H8I_!!6000000001335-2-tps-1920-1080.png)\n\n低代码引擎分为 4 大模块，入料 - 编排 - 渲染 - 出码：\n\n- 入料模块就是将外部的物料，比如海量的 npm 组件，按照[《低代码引擎物料协议规范》](/site/docs/specs/material-spec)进行描述。将描述后的数据通过引擎 API 注册后，在编辑器中使用。\n  > **注意，这里仅是增加描述，而非重写一套，这样我们能最大程度复用 ProCode 体系已沉淀的组件。**\n- 编排，本质上来讲，就是**不断在生成符合[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)的页面描述，将编辑器中的所有物料，进行布局设置、组件 CRUD 操作、以及 JS / CSS 编写/ 逻辑编排 **等，最终转换成页面描述，技术细节后文会展开。\n- 渲染，顾名思义，就是**将编排生成的页面描述结构渲染成视图的过程**，视图是面向用户的，所以必须处理好内部数据流、生命周期、事件绑定、国际化等。\n- 出码，就是**将编排过程产生的符合[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)的页面描述转换成另一种 DSL 或 编程语言代码的过程**。\n\n## 引擎生态简述\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01LkRseZ23W31l8DPzS_!!6000000007262-2-tps-1920-1080.png)\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01PYBVfZ1hL82XPrXzX_!!6000000004260-2-tps-1920-1080.png)\n\n引擎生态主要分为 3 部分，物料、设置器和插件。\n\n### 物料生态\n\n物料是低代码平台的生产资料，没有物料低代码平台则变成了无源之水无本之木。低代码平台的物料即低代码组件。因此低代码物料生态指的是：\n1. 低代码物料生产能力和规范。\n2. 对低代码物料进行统一管理的物料中心。\n3. 基于 Fusion Next 的低代码基础组件库。\n\n### 设置器生态\n\n对于已接入物料的属性配置，需要不同的设置器。\n\n比如配置数值类型的 age，需要一个数值设置器，配置对象类型的 hobby，需要一个对象设置器，依次类推。\n\n每个设置器本质上都是一个 React 组件，接受由引擎传入的参数，比如 value 和 onChange，value 是初始传入的值，onChange 是在设置器的值变化时的回传函数，将值写回到引擎中。\n\n```typescript\n// 一个最简单的文本设置器示例\nclass TextSetter extends Component {\n  render() {\n    const { value, onChange } = this.props;\n    return <input value={value} onChange={(e) => onChange(e.target.value)} />;\n  }\n}\n```\n\n大多数组件所使用的设置器都是一致或相似的。如同建设低代码基础组件库一样，设置器生态是一组基础的设置器，供大多数组件配置场景使用。\n\n同时提供了设置器的定制功能。\n\n### 插件生态\n低代码引擎本身只包含了最小的内核，而我们所能看到的设计器上的按钮、面板等都是插件提供的。插件是组成设计器的必要部分。\n\n因此我们提供了一套官方的插件生态，提供最基础的设计器功能。帮助用户通过使用插件，快速完成自己的设计器。\n"
  },
  {
    "path": "docs/docs/guide/expand/_category_.json",
    "content": "{\n  \"label\": \"扩展低代码编辑器\",\n  \"position\": 2,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/_category_.json",
    "content": "{\n  \"label\": \"扩展编辑态\",\n  \"position\": 1,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/cli.md",
    "content": "---\ntitle: 低代码生态脚手架 & 调试机制\nsidebar_position: 10\n---\n## 脚手架简述\n\n在 fork 低代码编辑器 demo 项目后，您可以直接在项目中任意扩展低代码编辑器。如果您想要将自己的组件/插件/设置器封装成一个独立的 npm 包并提供给社区，您可以使用我们的低代码脚手架建立低代码扩展。\n\n> Windows 开发者请在 WSL 环境下使用开发工具\n>\n> WSL 中文 doc：[https://docs.microsoft.com/zh-cn/windows/wsl/install](https://docs.microsoft.com/zh-cn/windows/wsl/install)\n>\n> 中文教程：[https://blog.csdn.net/weixin_45027467/article/details/106862520](https://blog.csdn.net/weixin_45027467/article/details/106862520)\n\n\n## 脚手架功能\n### 脚手架初始化\n\n```bash\nnpm init @alilc/element your-element-name\n```\n不写 your-element-name 的情况下，则在当前目录创建。\n\n> 注 1：如遇错误提示 `sh: create-element: command not found` 可先执行下述命令\n```bash\nnpm install -g @alilc/create-element\n```\n\n> 注 2：觉得安装速度比较慢的同学，可以设置 npm 国内镜像，如\n```bash\nnpm init @alilc/element your-element-name --registry=https://registry.npmmirror.com\n```\n\n选择对应的元素类型，并填写对应的问题，即可完成创建。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01LAaw2R1veHDYUzGB1_!!6000000006197-2-tps-676-142.png)\n\n### 脚手架本地环境调试\n\n```bash\ncd your-element-name\nnpm install\nnpm start\n```\n\n### 脚手架构建\n\n```bash\nnpm run build\n```\n\n### 脚手架发布\n\n修改版本号后，执行如下指令即可：\n\n```bash\nnpm publish\n```\n\n## 🔥🔥🔥 在低代码项目中调试物料/插件/设置器\n\n> 📢📢📢 低代码生态脚手架提供的调试利器，在启动 setter/插件/物料 项目后，直接在已有的低代码平台就可以调试，不需要 npm link / 手改 npm main 入口等传统方式，轻松上手，强烈推荐使用！！\n\n### 组件/插件/Setter 侧\n\n1. 插件/setter 在原有 alt 的配置中添加相关的调试配置\n  ```json\n  // build.json 中\n  {\n    \"plugins\": [\n      [\n        \"@alilc/build-plugin-alt\",\n        {\n          \"type\": \"plugin\",\n          \"inject\": true, // 开启注入调试\n          // 配置要打开的页面，在注入调试模式下，不配置此项的话不会打开浏览器\n          // 支持直接使用官方 demo 项目：https://lowcode-engine.cn/demo/index.html\n          \"openUrl\": \"https://lowcode-engine.cn/demo/index.html?debug\"\n        }\n      ],\n    ]\n  }\n  ```\n\n2. 组件需先安装 @alilc/build-plugin-alt，再将组件内的 `build.lowcode.js`文件修改如下\n  ```javascript\n  const { library } = require('./build.json');\n\n  module.exports = {\n    alias: {\n      '@': './src',\n    },\n    plugins: [\n      [\n        // lowcode 的配置保持不变，这里仅为示意。\n        '@alifd/build-plugin-lowcode',\n        {\n          library,\n          engineScope: \"@alilc\"\n        },\n      ],\n      [\n        '@alilc/build-plugin-alt',\n        {\n          type: 'component',\n          inject: true,\n          library,\n          // 配置要打开的页面，在注入调试模式下，不配置此项的话不会打开浏览器\n          // 支持直接使用官方 demo 项目：https://lowcode-engine.cn/demo/index.html\n          openUrl: \"https://lowcode-engine.cn/demo/index.html?debug\"\n        }\n      ]],\n  };\n  ```\n\n3. 本地组件/插件/Setter正常启动调试，在项目的访问地址增加 debug，即可开启注入调试。\n  ```url\n  https://lowcode-engine.cn/demo/demo-general/index.html?debug\n  ```\n\n### 项目侧的准备\n\n> 如果你的低代码项目 fork 自官方 demo，那么项目侧的准备已经就绪，不用再看以下内容~\n\n1. 安装 @alilc/lowcode-plugin-inject\n  ```bash\n  npm i @alilc/lowcode-plugin-inject  --save-dev\n  ```\n\n2. 在引擎初始化侧引入插件\n  ```typescript\n  import Inject, { injectAssets } from '@alilc/lowcode-plugin-inject';\n  import { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\n  export default async () => {\n    // 注意 Inject 插件必须在其他插件前注册，且所有插件的注册必须 await\n    await plugins.register(Inject);\n    await plugins.register(OtherPlugin);\n    await plugins.register((ctx: IPublicModelPluginContext) => {\n      return {\n        name: \"editor-init\",\n        async init() {\n          // 设置物料描述前，使用插件提供的 injectAssets 进行处理\n          const { material, project } = ctx;\n          material.setAssets(await injectAssets(assets));\n        },\n      };\n    });\n  }\n  ```\n\n3. 在 saveSchema 时过滤掉插入的 url，避免影响渲染态\n  ```typescript\n  import { filterPackages } from '@alilc/lowcode-plugin-inject';\n  export const saveSchema = async () => {\n    // ...\n    const packages = await filterPackages(editor.get('assets').packages);\n    window.localStorage.setItem(\n      'packages',\n      JSON.stringify(packages),\n    );\n    // ...\n  };\n  ```\n\n4. 如果希望预览态也可以注入调试组件，则需要在 preview 逻辑里插入组件\n  ```javascript\n  import { injectComponents } from '@alilc/lowcode-plugin-inject';\n\n  async function init() {\n    // 在传递给 ReactRenderer 前，先通过 injectComponents 进行处理\n    const components = await injectComponents(buildComponents(libraryMap, componentsMap));\n    // ...\n  }\n  ```\n\n注：若控制台出现如下错误，直接访问一次该 url 即可~\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01cvKmeK1saCqpIxbLW_!!6000000005782-2-tps-1418-226.png)\n\n\n## Meta 信息\nmeta 信息是放在生态元素 package.json 中的一小段 json，用户可以通过 meta 了解到这个元素的一些基本信息，如元素类型，一些入口信息等。\n\n```typescript\ninterface LcMeta {\n  type: 'plugin' | 'setter' | 'component';  // 元素类型，尚未实现\n  pluginName: string;                       // 插件名，仅插件包含\n  meta: {\n    dependencies: string[];                 // 插件依赖的其他插件列表，仅插件包含\n    engines: {\n      lowcodeEngine: string;                // 适配的引擎版本\n    }\n    prototype: string;                      // 物料描述入口，仅组件包含，尚未实现\n    prototypeView: string;                  // 物料设计态入口，仅组件包含，尚未实现\n  }\n}\n```\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/graph.md",
    "content": "---\ntitle: 图编排扩展\nsidebar_position: 8\n---\n## 项目运行\n### 前置准备\n1. 参考 https://lowcode-engine.cn/site/docs/guide/quickStart/start\n2. 参考至Demo下载 https://lowcode-engine.cn/site/docs/guide/quickStart/start#%E4%B8%8B%E8%BD%BD-demo\n### 选择demo-graph-x6\n在根目录下执行：\n```bash\ncd demo-graph-x6\n```\n### 安装依赖\n在 lowcode-demo/demo-graph-x6目录下执行：\n```bash\nnpm install\n```\n### 启动Demo\n在 lowcode-demo/demo-graph-x6 目录下执行：\n```bash\nnpm run start\n```\n之后就可以通过 http://localhost:5556/ 来访问我们的 DEMO 了。\n\n## 认识Demo\n这里的Demo即通过图编排引擎加入了几个简单的物料而来，已经是可以面向真是用户的产品界面。\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN016TbCI31hM2sJy8qkR_!!6000000004262-2-tps-5120-2726.png)\n### 区域组成\n#### 顶部：操作区​\n- 右侧：保存到本地、重置页面、自定义按钮\n#### 顶部：工具区\n- 左侧：删除、撤销、重做、放大、缩小\n#### 左侧：面板与操作区​\n- 物料面板：可以查找节点，并在此拖动节点到编辑器画布中\n#### 中部：可视化页面编辑画布区域​\n- 点击节点/边在右侧面板中能够显示出对应组件的属性配置选项\n- 拖拽修改节点的排列顺序\n#### 右侧：组件级别配置​\n- 选中的组件：从页面开始一直到当前选中的节点/边位置，点击对应的名称可以切换到对应的节点上\n- 选中组件的配置：属性：节点的基础属性值设置\n\n> 每个区域的组成都可以被替换和自定义来生成开发者需要的业务产品。\n\n## 目录介绍\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01Luc8gr1tLq5QTbpb9_!!6000000005886-0-tps-832-1522.jpg)\n\n- public：与其他demo保持一致，均是lowcode engine所必要依赖\n- src\n  - plugins:：自定义插件，完成了x6的切面回调处理功能\n  - services：mock数据，真实场景中可能为异步获取数据\n\n## 开发插件\n```typescript\nfunction pluginX6DesignerExtension(ctx: IPublicModelPluginContext) {\n  return {\n    init() {\n      // 获取 x6 designer 内置插件的导出 api\n      const x6Designer = ctx.plugins['plugin-x6-designer'] as IDesigner;\n\n      x6Designer.onNodeRender((model, node) => {\n        // @ts-ignore\n        // 自定义 node 渲染逻辑\n        const { name, title } = model.propsData;\n        node.attr('text/textWrap/text', title || name);\n      });\n\n      x6Designer.onEdgeRender((model, edge) => {\n        // @ts-ignore\n        const { source, target, sourcePortId, targetPortId } = model.propsData;\n        console.log(sourcePortId, targetPortId);\n        requestAnimationFrame(() => {\n          edge.setSource({ cell: source, port: sourcePortId });\n          edge.setTarget({ cell: target, port: targetPortId });\n        });\n\n        // https://x6.antv.vision/zh/docs/tutorial/intermediate/edge-labels x6 标签模块\n        // appendLabel 会触发 onEdgeLabelRender\n        edge.appendLabel({\n          markup: Markup.getForeignObjectMarkup(),\n          attrs: {\n            fo: {\n              width: 120,\n              height: 30,\n              x: -60,\n              y: -15,\n            },\n          },\n        });\n      });\n\n      x6Designer.onEdgeLabelRender((args) => {\n        const { selectors } = args\n        const content = selectors.foContent as HTMLDivElement\n        if (content) {\n          ReactDOM.render(<div>自定义 react 标签</div>, content)\n        }\n      })\n    }\n  }\n}\n\npluginX6DesignerExtension.pluginName = 'plugin-x6-designer-extension';\n\nexport default pluginX6DesignerExtension;\n```\nx6Designer为图实例暴露出来的一些接口，可基于此进行一些图的必要插件的封装，整个插件的封装完全follow低代码引擎的插件，详情可参考 https://lowcode-engine.cn/site/docs/guide/expand/editor/pluginWidget\n\n## 开发物料\n```bash\nnpm init @alilc/element your-material-demo\n```\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01DCCqO82ADuhS8ztCt_!!6000000008170-2-tps-546-208.png)\n\n仓库初始化完成\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01qK2rUe1JNpdqbdhoW_!!6000000001017-0-tps-5120-2830.jpg)\n\n接下来即可编写物料内容了\n图物料与低代码的dom场景存在画布的差异，因此暂不支持物料单独调试，须通过项目demo进行物料调试\n\n### 资产描述\n```bash\nnpm run lowcode:build\n```\n如果物料是个React组件，则在执行上述命令时会自动生成对应的meta.ts，<b>但图物料很多时候并非一个React组件，因此须手动生产meta.ts</b>\n\n可参考：  https://github.com/alibaba/lowcode-materials/blob/main/packages/graph-x6-materials/lowcode/send-email/meta.ts\n同时会自动生成物料描述文件\n\n### 物料调试\n#### 物料侧\n物料想要支持被项目动态inject调试，须在build.lowcode.js中加入\n```javascript\n[\n  '@alilc/build-plugin-alt',\n  {\n    type: 'component',\n    inject: true,\n    library\n  },\n]\n```\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01HyXfL12992sDkOmOg_!!6000000008024-0-tps-5120-2824.jpg)\n\n本地启动\n```bash\nnpm run lowcode:dev\n```\n#### 项目侧\n通过@alilc/lce-graph-core加载物料的天然支持了debug，因此无须特殊处理。\n若项目中自行加载，则参考 https://lowcode-engine.cn/site/docs/guide/expand/editor/cli\n项目访问地址后拼接query \"?debug\"即可进入物料调试\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01ke58hT1aRoYJzkutk_!!6000000003327-2-tps-5120-2790.png)\n\n\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/material.md",
    "content": "---\ntitle: 物料扩展\nsidebar_position: 1\n---\n## 物料简述\n物料是页面搭建的原料，按照粒度可分为组件、区块和模板：\n\n1. 组件：组件是页面搭建最小的可复用单元，其只对外暴露配置项，用户无需感知其内部实现；\n2. 区块：区块是一小段符合低代码协议的 schema，其内部会包含一个或多个组件，用户向设计器中拖入一个区块后可以随意修改其内部内容；\n3. 模板：模板和区块类似，也是一段符合低代码协议的 schema，不过其根节点的 componentName 需固定为 Page，它常常用于初始化一个页面；\n\n低代码编辑器中的物料需要进行一定的配置和处理，才能让用户在低代码平台使用起来。这个过程中，需要一份一份配置文件，也就是资产包。资产包文件中，针对每个物料定义了它们在低代码编辑器中的使用描述。\n## 资产包配置\n### 什么是低代码资产包\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01SQJfxh1Y8uwDXksaK_!!6000000003015-2-tps-3068-1646.png)\n在低代码 Demo 中，我们可以看到，组件面板不只提供一个组件，组件是以集合的形式提供给低代码平台的，而低代码资产包正是这些组件构成集合的形式。\n**_它背后的 Interface，_**[**_在引擎中的定义摘抄如下_**](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/assets.ts)**_：_**\n\n```typescript\nexport interface Assets {\n  version: string; // 资产包协议版本号\n  packages?: Array<Package>; // 大包列表，external 与 package 的概念相似，融合在一起\n  components: Array<ComponentDescription> | Array<RemoteComponentDescription>; // 所有组件的描述协议列表\n  sort: ComponentSort; // 新增字段，用于描述组件面板中的 tab 和 category\n}\n\nexport interface ComponentSort {\n  groupList?: String[]; // 用于描述组件面板的 tab 项及其排序，例如：[\"精选组件\", \"原子组件\"]\n  categoryList?: String[]; // 组件面板中同一个 tab 下的不同区间用 category 区分，category 的排序依照 categoryList 顺序排列；\n}\n\nexport interface RemoteComponentDescription {\n  exportName: string; // 组件描述导出名字，可以通过 window[exportName] 获取到组件描述的 Object 内容；\n  url: string; // 组件描述的资源链接；\n  package: { // 组件 (库) 的 npm 信息；\n    npm: string;\n  }\n}\n```\n资产包协议 TS 描述\n### Demo 中的资产包\n在 Demo 项目中，自带了一份默认的资产包：\n> [https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/services/assets.json](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/services/assets.json)\n\n这份资产包里的物料是我们内部沉淀出的，用户可以通过这套资产包体验引擎提供的搭建、配置能力。\n**_在项目中正常注册资产包：_**\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n// 以任何方式引入 assets\nmaterial.setAssets(assets);\n```\n**_以支持调试的方式注册资产包：_**\n> 这样启动并部署出来的项目，可以通过在预览地址加上 ?debug 来调试本地物料。\n> 例如：\n> - 通过插件初始化一个物料\n> - 按照参考文章配置物料支持调试\n> - 启动物料\n> - 访问：[https://lowcode-engine.cn/demo/demo-general/index.html?debug](https://lowcode-engine.cn/demo/demo-general/index.html)\n>\n详细参考：[低代码生态脚手架 & 调试机制](https://lowcode-engine.cn/site/docs/guide/expand/editor/cli)\n\n```typescript\nimport { material } from '@alilc/lowcode-engine';\nimport Inject, { injectAssets } from '@alilc/lowcode-plugin-inject';\nawait material.setAssets(await injectAssets(assets));\n```\n\n### 手工配置资产包\n参考 Demo 中的[基础 Fusion Assets 定义](https://github.com/alibaba/lowcode-demo/blob/main/demo-basic-fusion/src/services/assets.json)，如果我们修改 assets.json，我们就能做到配置资产包：\n\n- packages 对象：我们需要在其中定义这个包的获取方式，如果不定义，就不会被低代码引擎动态加载并对应上组件实例。定义方式是 UMD 的包，低代码引擎会尝试在 window 上寻找对应 library 的实例；\n- components 对象：我们需要在其中定义物料描述，物料描述我们将在下一节继续讲解。\n## 物料描述配置\n### 什么是物料描述\n在低代码平台中，用户是不同的，有可能是开发、测试、运营、设计，也有可能是销售、行政、HR 等等各种角色。他们大多数不具备专业的前端开发知识，对于低代码平台来说，我们使用组件的流程如下：\n\n1. 用户通过拖拽/选择组件，在画布中看到组件；\n2. 选中组件，出现组件的配置项；\n3. 修改组件配置项；\n4. 画布更新生效。\n\n**_当我们选中一个组件，我们可以看到面板右侧会显示组件的配置项。_**\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01T5hGcl25ABLpLIWKh_!!6000000007485-2-tps-1500-743.png)\n**_它包含以下内容：_**\n\n1. 基础信息：描述组件的基础信息，通常包含包信息、组件名称、标题、描述等。\n2. 组件属性信息：描述组件属性信息，通常包含参数、说明、类型、默认值 4 项内容。\n3. 能力配置/体验增强：推荐用于优化搭建产品编辑体验，定制编辑能力的配置信息。\n\n因此，我们设计了[**《中后台低代码组件描述协议》**](/site/docs/specs/material-spec)来描述一个低代码编辑器中可被配置的内容。\n### Demo 中的物料描述\n我们可以从 Demo 中的 assets.json 找到如下三个物料描述：\n\n- @alifd/pro-layout：布局组件，放在`window.AlifdProLayoutMeta`，[meta 文件地址](https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/meta.js)；\n- @alifd/fusion-ui：精选组件，放在`window.AlifdFusionUiMeta`，[meta 文件地址](https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/build/lowcode/meta.js)；\n- @alilc/lowcode-materials：原子组件，放在 `window.AlilcLowcodeMaterialsMeta`，[meta 文件地址](https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/build/lowcode/meta.js)；\n\n**_引擎中，会尝试调用对应 meta 文件，并注入到全局：_**\n```tsx\nconst src = 'https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/meta.js';\nconst script = document.createElement('script');\nscript.src = src;\ndocument.head.appendChild(script);\n```\n然后在 window 上就能拿到对应的物料描述内容了：\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01DHSEOH1RwCEq19Ro9_!!6000000002175-2-tps-1896-1138.png)\n手工配置物料描述时，可以用这样的方式参考一下 Demo 中的物料描述是如何实现的。\n### 手工配置物料描述\n详见：“物料描述详解”章节。\n## 物料的低代码开发\n> _**注意：引擎提供的 cli 并未对 windows 系统做适配，windows 环境必须使用 **_[_**WSL**_](https://docs.microsoft.com/zh-cn/windows/wsl/install)_**，其他终端不保证能正常运行**_\n\n您可以通过本节内容，完成一个组件在低代码编辑器中的配置和调试。\n### 前言（必读）\n引擎提供的物料开发脚手架内置了**_入料模块_**，初始化的时候会自动根据源码解析出一份_**低代码描述**_，但是从源码解析出来的低代码描述让用户直接使用是不够精细的，因为源码包含的信息不够，它没办法完全包含配置项的交互；\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN010t0YzC1znDPQB1LUA_!!6000000006758-2-tps-802-1830.png)\n比如设计师出了上面的设计稿，这里面除了有哪些 props 可被配置，通过哪个设置器配置，还包含了 props 之间的聚合、排序，甚至有自定义 setter，这些信息源码里是不具备的，需要在低代码描述里进行开发；\n**_因此我们建议只把 cli 初始化的低代码描述作为启动，要根据用户习惯对配置项进行设计，然后人工地去开发调试直接的低代码描述。_**\n### 新开发组件\n#### 组件项目初始化\n```bash\nnpm init @alilc/element your-material-name\n```\n#### 选择组件类型\n> 组件 -> <组件组织方式>\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01BTiMt51iLPtzDbuh8_!!6000000004396-2-tps-1596-464.png)\n这里我们选择 react-组件库，之后便生出我们的组件库项目，目录结构如下：\n```\nmy-materials\n├── README.md\n├── components  (业务组件目录）\n│   ├── ExampleComponent              // 业务组件1\n│   │   ├── build                     // 【编译生成】【必选】\n│   │   │   └── index.html\t\t\t\t\t\t// 【编译生成】【必选】可直接预览文件\n│   │   ├── lib                       // 【编译生成】【必选】\n│   │   │   ├── index.js              // 【编译生成】【必选】js 入口文件\n│   │   │   ├── index.scss            // 【编译生成】【必选】css 入口文件\n│   │   │   └── style.js\t\t\t\t\t\t\t// 【编译生成】【必选】js 版本 css 入口文件，方便去重\n│   │   ├── demo                      // 【必选】组件文档，用于生成组件开发预览，以及生成组件文档\n│   │   │   └── basic.md\n│   │   ├── src                       // 【必选】组件源码\n│   │   │   ├── index.js              // 【必选】，组件出口文件\n│   │   │   └── main.scss             // 【必选】，仅包含组件自身样式的源码文件\n│   │   ├── README.md                 // 【必选】，组件说明及API\n│   │   └── package.json              // 【必选】\n└── └── ExampleComponent2             // 业务组件2\n```\n#### 组件开发与调试\n```bash\n# 安装依赖\nnpm install\n\n# 启动 lowcode 环境进行调试预览\nnpm run lowcode:dev\n\n# 构建低代码产物\nnpm run lowcode:build\n```\n执行上述命令后会在组件 (库) 根目录生成一个 `lowcode` 文件夹，里面会包含每个组件的低代码描述：\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN016m7gOK1DvpIcnlTvY_!!6000000000279-2-tps-1446-906.png)\n\n在 src/components 目录新增一个组件并在 src/index.tsx 中导出，然后再执行 npm run lowcode:dev 时，低代码插件会在 lowcode/<component-name\\> 目录自动生成新增组件的低代码描述（meta.ts）。\n\n用户可以直接修改低代码描述来修改组件的配置：\n\n- 设置组件的 setter（上一个章节介绍的设置器，也可以定制设置器用到物料中）；\n- 新增组件配置项;\n- 更改当前配置项；\n#### 配置示例\n隐藏一个 prop\n```typescript\n{\n  name: 'dataSource',\n  condition: () => false,\n}\n```\n展示样式\n```typescript\n{\n  name: 'dataSource',\n  display: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry', // 常用的是 inline(默认), block、entry\n}\n```\n#### 编辑态视图\n用户可以在 lowcode/<component-name\\> 目录下新增 view.tsx 来增加编辑态视图。编辑态视图用于在编辑态时展示与真实预览不一样的视图。\nview.tsx 输出的也是一个 React 组件。\n\n注意：如果是单组件，而非组件库模式的话，view.tsx 应置于 lowcode 而非 lowcode/<component-name\\> 目录下\n\n\n#### 发布组件\n```bash\n# 在组件根目录下，执行\n$ npm publish\n```\n### 现存组件低代码化\n组件低代码化是指，在引入低代码平台之前，我们大多数都是使用源码开发的组件，也就是 ProCode 组件。\n\n在引入低代码平台之后，原来的源码组件是需要转化为低代码物料，这样才能在低代码平台进行消费。\n\n所以接下来会说明，对于已有的源码组件，我们如何把它低代码化。\n#### 配置低代码开发环境\n在您的组件开发环境中，安装 [build-scripts](https://github.com/ice-lab/build-scripts) 和它的低代码开发插件：\n```bash\nnpm install -D @alifd/build-plugin-lowcode @alib/build-scripts --save-dev\n```\n新增 build-scripts 配置文件：build.lowcode.js\n\n```javascript\nmodule.exports = {\n  alias: {\n    '@': './src',\n  },\n  plugins: [\n    [\n      \"@alifd/build-plugin-lowcode\",\n      {\n        engineScope: '@alilc',\n      }\n    ]\n  ],\n};\n\n```\n在 package.json 中定义低代码开发相关命令\n```javascript\n\"lowcode:dev\": \"build-scripts start --config ./build.lowcode.js\",\n\"lowcode:build\": \"build-scripts build --config ./build.lowcode.js\",\n```\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN014iSa1P1dNdkUUtoMm_!!6000000003724-2-tps-1830-822.png)\n#### 开发调试\n\n```bash\n# 启动低代码开发调试环境\nnpm run lowcode:dev\n```\n\n组件开发形式还和原来的保持一致，但是新增了一份组件的配置文件，其中配置方式和低代码物料的配置是一样的。\n\n#### 构建\n\n```bash\n# 构建低代码产物\nnpm run lowcode:build\n```\n\n#### 发布组件\n```bash\n# 在组件根目录下，执行\nnpm publish\n```\n\n## 在项目中引入组件 (库)\n> 以下内容可观看[《阿里巴巴低代码引擎项目实战 (3)-自定义组件接入》](https://www.bilibili.com/video/BV1dZ4y1m76S/)直播回放\n\n对于平台或者用户来说，可能所需要的组件集合是不同的。如果需要自定义组件集合，就需要定制资产包，定制的资产包是配置了一系列组件的，将这份资产包用于引擎即可在引擎中使用自定义的组件集合。\n\n### 管理一份资产包\n项目中使用的组件相关资源都需要在资产包中定义，那么我们自己开发的组件库如果要在项目中使用，只需要把组件构建好的相关资源 merge 到 assets.json 中就可以；\n\n#### 自定义组件加入到资产包\n通过官方脚手架自定义组件构建发布之后，npm 包里会出现一个 `build/lowcode/assets-prod.json`文件，我们只需要把该文件的内容 merge 到项目的 assets.json 中就可以；\n\n#### 资产包托管\n\n- 最简单的方式就是类似[引擎 demo 项目](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/services/assets.json)的做法，在项目中维护一份 assets.json，新增组件或者组件版本更新都需要修改这份资产包；\n- 灵活一点的做法是通过 oss 等服务维护一份远程可配置的 assets.json，新增组件或者组件更新只需要修改这份远程的资产包，项目无需更新；\n- 再高级一点的做法是实现一个资产包管理的服务，能够通过用户界面去更新资产包的内容；\n\n### 在项目中引入资产包\n```typescript\nimport { material, plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\n// 动态加载 assets\nplugins.register((ctx: IPublicModelPluginContext) => {\n  return {\n    name: 'ext-assets',\n    async init() {\n      try {\n        // 将下述链接替换为您的物料即可。无论是通过 utils 从物料中心引入，还是通过其他途径如直接引入物料描述\n        const res = await window.fetch('https://fusion.alicdn.com/assets/default@0.1.95/assets.json');\n        const assets = await res.text();\n        material.setAssets(assets);\n      } catch (err) {\n        console.error(err);\n      }\n    },\n  }\n}).catch(err => console.error(err));\n```\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/metaSpec.md",
    "content": "---\ntitle: 物料描述详解\nsidebar_position: 2\n---\n## 物料描述概述\n\n中后台前端体系中，存在大量的组件，程序员可以通过阅读文档，知悉组件的用法。可是搭建平台无法理解 README，而且很多时候，README 里并没有属性列表。这时，我们需要一份额外的描述，来告诉低代码搭建平台，组件接受哪些属性，又是该用怎样的方式来配置这些属性，于是，[**《中后台低代码组件描述协议》**](/site/docs/specs/material-spec)应运而生。协议主要包含三部分：基础信息、属性信息 props、能力配置/体验增强 configure。\n\n物料配置，就是产出一份符合[**《中后台低代码组件描述协议》**](/site/docs/specs/material-spec)的 JSON Schema。如果需要补充属性描述信息，或需要定制体验增强部分（如修改 Setter、调整展示顺序等），就可以通过修改这份 Schema 来实现。目前有自动生成、手工配置这两种方式生成物料描述配置。\n\n## 可视化生成物料描述\n\n使用 Parts 造物平台：[使用文档](/site/docs/guide/expand/editor/parts/partsIntro)\n\n## 自动生成物料描述\n\n可以使用官方提供的 `@alilc/lowcode-material-parser` 解析本地组件，自动生成物料描述。把物料描述放到资产包定义中，就能让低代码引擎理解如何制作物料。详见上一个章节“物料扩展”。\n\n下面以某个组件代码片段为例：\n```typescript\n// /path/to/component\nimport { PureComponent } from 'react';\nimport PropTypes from 'prop-types';\n\nexport default class FusionForm extends PureComponent {\n  static displayName = 'FusionForm';\n\n  static defaultProps = {\n    name: '张三',\n    age: 18,\n    friends: ['李四','王五','赵六'],\n  }\n\n  static propTypes = {\n    /**\n     * 这是用于描述姓名\n     */\n    name: PropTypes.string.isRequired,\n    /**\n     * 这是用于描述年龄\n     */\n    age: PropTypes.number,\n    /**\n     * 这是用于描述好友列表\n     */\n    friends: PropTypes.array\n  };\n\n  render() {\n    return <div>dumb</div>;\n  }\n}\n```\n\n引入 parse 工具自动解析\n\n```typescript\nimport parse from '@alilc/lowcode-material-parser';\n(async () => {\n  const result = await parse({ entry: '/path/to/component' });\n  console.log(JSON.stringify(result, null, 2));\n})();\n```\n\n因为一个组件可能输出多个子组件，所以解析结果是个数组。\n\n```json\n[\n  {\n    \"componentName\": \"FusionForm\",\n    \"title\": \"\",\n    \"docUrl\": \"\",\n    \"screenshot\": \"\",\n    \"devMode\": \"proCode\",\n    \"npm\": {\n      \"package\": \"\",\n      \"version\": \"\",\n      \"exportName\": \"default\",\n      \"main\": \"\",\n      \"destructuring\": false,\n      \"subName\": \"\"\n    },\n    \"props\": [\n      {\n        \"name\": \"name\",\n        \"propType\": \"string\",\n        \"description\": \"这是用于描述姓名\",\n        \"defaultValue\": \"张三\"\n      },\n      {\n        \"name\": \"age\",\n        \"propType\": \"number\",\n        \"description\": \"这是用于描述年龄\",\n        \"defaultValue\": 18\n      },\n      {\n        \"name\": \"friends\",\n        \"propType\": \"array\",\n        \"description\": \"这是用于描述好友列表\",\n        \"defaultValue\": [\n          \"李四\",\n          \"王五\",\n          \"赵六\"\n        ]\n      }\n    ]\n  }\n]\n```\n\n## 手工配置物料描述\n\n如果自动生成的物料无法满足需求，我们就需要手动配置物料描述。本节将分场景描述物料配置的内容。\n\n### 常见配置\n\n#### 组件的属性只有有限的值\n\n增加一个 size 属性，只能从 'large'、'normal'、'small' 这个候选值中选择。\n\n以上面自动解析的物料为例，在此基础上手工加上 size 属性：\n\n```json\n[\n  {\n    \"componentName\": \"FusionForm\",\n    \"title\": \"\",\n    \"docUrl\": \"\",\n    \"screenshot\": \"\",\n    \"devMode\": \"proCode\",\n    \"npm\": {\n      \"package\": \"\",\n      \"version\": \"\",\n      \"exportName\": \"default\",\n      \"main\": \"\",\n      \"destructuring\": false,\n      \"subName\": \"\"\n    },\n    \"props\": [\n      {\n        \"name\": \"name\",\n        \"propType\": \"string\",\n        \"description\": \"这是用于描述姓名\",\n        \"defaultValue\": \"张三\"\n      },\n      {\n        \"name\": \"age\",\n        \"propType\": \"number\",\n        \"description\": \"这是用于描述年龄\",\n        \"defaultValue\": 18\n      },\n      {\n        \"name\": \"friends\",\n        \"propType\": \"array\",\n        \"description\": \"这是用于描述好友列表\",\n        \"defaultValue\": [\n          \"李四\",\n          \"王五\",\n          \"赵六\"\n        ]\n      }\n    ],\n    // 手工增加的 size 属性\n    \"configure\": {\n      \"isExtend\": true,\n      \"props\": [\n        {\n          \"title\": \"尺寸\",\n          \"name\": \"size\",\n          \"setter\": {\n            \"componentName\": 'RadioGroupSetter',\n            \"isRequired\": true,\n            \"props\": {\n              \"options\": [\n                { \"title\": \"大\", \"value\": \"large\" },\n                { \"title\": \"中\", \"value\": \"normal\" },\n                { \"title\": \"小\", \"value\": \"small\" }\n              ]\n            },\n          }\n        }\n      ]\n    }\n  }\n]\n```\n\n#### 组件的属性既可以设置固定值，也可以绑定到变量\n\n我们知道一种属性形式就需要一种 setter 来设置，如果想要将 value 属性允许输入字符串，那就需要设置为 `StringSetter`，如果允许绑定变量，就需要设置为 `VariableSetter`，具体设置器请参考[预置设置器列表](/site/docs/guide/appendix/setters)。\n\n那如果都想要呢？可以使用 `MixedSetter` 来实现。\n\n```javascript\n{\n  // ...\n  configure: {\n    isExtend: true,\n    props: [\n      {\n        title: '输入框的值',\n        name: 'activeValue',\n        setter: {\n          componentName: 'MixedSetter',\n          isRequired: true,\n          props: {\n            setters: [\n              'StringSetter',\n              'NumberSetter',\n              'VariableSetter',\n            ],\n          },\n        }\n      }\n    ]\n  }\n}\n```\n\n设置后，就会出现“切换设置器”的操作项了\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01jBqcuK1xYRP00WyVx_!!6000000006455-2-tps-598-252.png)\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01944xqq1PYihvYQb4v_!!6000000001853-2-tps-244-308.png)\n\n#### 开启组件样式设置\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01EBStyl24EvqJkAdh1_!!6000000007360-2-tps-820-772.png)\n\n```javascript\n{\n  configure: {\n    // ...,\n    supports: {\n      style: true,\n    },\n    // ...\n  }\n}\n```\n\n#### 设置组件的默认事件\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN012gijqt1NERwqF5f6Y_!!6000000001538-2-tps-776-800.png)\n\n```javascript\n{\n  configure: {\n    // ...\n    supports: {\n      events: ['onPressEnter', 'onClear', 'onChange', 'onKeyDown', 'onFocus', 'onBlur'],\n    },\n    // ...\n  }\n}\n```\n\n#### 设置 prop 标题的 tip\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01d8TdsY1jhENsKvwAv_!!6000000004579-2-tps-908-176.png)\n\n```javascript\n{\n  name: 'label',\n  setter: 'StringSetter',\n  title: {\n    label: {\n      type: 'i18n',\n      zh_CN: '标签文本',\n      en_US: 'Label',\n    },\n    tip: {\n      type: 'i18n',\n      zh_CN: '属性：label | 说明：标签文本内容',\n      en_US: 'prop: label | description: label content',\n    },\n  },\n}\n```\n\n#### 配置 prop 对应 setter 在配置面板的展示方式\n\n##### inline\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01z1sXj420vkP7vbeHj_!!6000000006912-2-tps-790-266.png)\n\n```javascript\n{\n  configure: {\n    props: [{\n      description: '标签文本',\n      display: 'inline',\n    }]\n  }\n}\n```\n\n##### block\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01i3MVKF299xchs6kMX_!!6000000008026-2-tps-792-274.png)\n\n```javascript\n{\n  configure: {\n    props: [{\n      description: '高级',\n      display: 'block',\n    }]\n  }\n}\n```\n\n##### accordion\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01RePeyy1nhvRiBMm2w_!!6000000005122-2-tps-798-740.png)\n\n```javascript\n{\n  configure: {\n    props: [{\n      description: '表单项配置',\n      display: 'accordion',\n    }]\n  }\n}\n```\n\n##### entry\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01zkjBak1YY6igYUO1n_!!6000000003070-2-tps-796-424.png)\n\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01lmuRTl1LOPKMnsfLJ_!!6000000001289-2-tps-794-632.png)\n\n```javascript\n{\n  configure: {\n    props: [{\n      description: '风格与样式',\n      display: 'entry',\n    }]\n  }\n}\n```\n\n##### plain\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01G0DOfV1jGD0v049gk_!!6000000004520-2-tps-776-438.png)\n\n```javascript\n{\n  configure: {\n    props: [{\n      description: '返回上级',\n      display: 'plain',\n    }]\n  }\n}\n```\n\n\n### 进阶配置\n\n#### 组件的 children 属性允许传入 ReactNode\n\n例如有一个如下的 Tab 选项卡组件，每个 TabPane 的 children 都是一个组件\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01Cu09HV1m8pTucSc7Q_!!6000000004910-2-tps-2332-334.png)\n\n只需要增加 `isContainer` 配置即可\n\n```javascript\n{\n  // ...\n  configure: {\n    // ...\n    component: {\n      // 新增，设置组件为容器组件，可拖入组件\n      isContainer: true,\n    },\n  }\n}\n```\n\n假设我们希望只允许拖拽 Table、Button 等内容放在 TabPane 里。配置白名单 `childWhitelist` 即可\n\n```javascript\n{\n  // ...\n  configure: {\n    // ...\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // 允许拖入的组件白名单\n        childWhitelist: ['Table', 'Button'],\n        // 同理也可以设置该组件允许被拖入哪些父组件里\n        parentWhitelist: ['Tab'],\n      },\n    },\n  },\n}\n```\n#### 组件的非 children 属性允许传入 ReactNode\n\n这就需要使用 `SlotSetter` 开启插槽了，如下面示例，给 Tab 的 title 开启插槽，允许拖拽组件\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01P77m5m1pKEBXTk9Yt_!!6000000005341-2-tps-3016-580.png)\n\n```json\n{\n  // ...\n  configure: {\n    isExtend: true,\n    props: [\n      {\n        title: '选项卡标题',\n        name: 'title',\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              'StringSetter',\n              'SlotSetter',\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n    ],\n  },\n}\n```\n\n#### 屏蔽组件在设计器中的操作按钮\n\n正常情况下，组件允许复制：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01925Nyl1a2AKNQ1XCP_!!6000000003271-2-tps-1158-226.png)\n\n如果希望禁止组件的复制行为，我们可以这样做：\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01IoLKUu1CXGRb0ileB_!!6000000000090-2-tps-1176-300.png)\n\n```javascript\n{\n  configure: {\n    component: {\n      disableBehaviors: ['copy'],\n    },\n  },\n}\n```\n\n#### 实现一个 BackwardSetter\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01GI4VfT23ga8TUCjIh_!!6000000007285-2-tps-776-438.png)\n\n```javascript\n{\n  name: 'back',\n  title: ' ',\n  display: 'plain',\n  setter: BackwardSetter,\n}\n\n// BackwardSetter\nimport { SettingTarget, DynamicSetter } from '@alilc/lowcode-types';\nconst BackwardSetter: DynamicSetter = (target: SettingTarget) => {\n  return {\n    componentName: (\n      <Button\n        onClick={() => {\n          target.getNode().parent.select();\n        }}\n      >\n        <Icon type=\"arrow-left\" /> 返回上级\n      </Button>\n    ),\n  };\n};\n```\n\n### 高级配置\n\n#### 不展现一个 prop 配置\n\n- 始终隐藏当前 prop\n\n```javascript\n{\n  // 始终隐藏当前 prop 配置\n  condition: () => false,\n}\n```\n\n- 根据其它 prop 的值展示/隐藏当前 prop\n\n```javascript\n{\n  // direction 为 hoz 则展示当前 prop 配置\n  condition: (target) => {\n    return target.getProps().getPropValue('direction') === 'hoz';\n  }\n}\n```\n\n#### props 联动\n\n```javascript\n// 根据当前 prop 的值动态设置其它 prop 的值\n{\n  name: 'labelAlign',\n  // ...\n  extraProps: {\n    setValue: (target, value) => {\n      if (value === 'inset') {\n        target.getProps().setPropValue('labelCol', null);\n        target.getProps().setPropValue('wrapperCol', null);\n      } else if (value === 'left') {\n         target.getProps().setPropValue('labelCol', { fixedSpan: 4 });\n         target.getProps().setPropValue('wrapperCol', null);\n      }\n      return target.getProps().setPropValue('labelAlign', value);\n    },\n  },\n}\n// 根据其它 prop 的值来设置当前 prop 的值\n{\n  name: 'status',\n  // ...\n  extraProps: {\n    getValue: (target) => {\n      const isPreview = target.getProps().getPropValue('isPreview');\n      return isPreview ? 'readonly' : 'editable';\n    }\n  }\n}\n```\n\n#### 动态 setter 配置\n\n可以通过 DynamicSetter 传入的 target 获取一些引擎暴露的数据，例如当前有哪些组件被加载到引擎中，将这个数据作为 SelectSetter 的选项，让用户选择：\n\n```javascript\n{\n  setter: (target) => {\n    return {\n      componentName: 'SelectSetter',\n      props: {\n        options: target.designer.props.componentMetadatas.filter(\n          (item) => item.isFormItemComponent).map(\n            (item) => {\n              return {\n                title: item.title || item.componentName,\n                value: item.componentName,\n              };\n            }\n          ),\n        ),\n      },\n    };\n  }\n}\n```\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/parts/_category_.json",
    "content": "{\n  \"label\": \"Parts 造物\",\n  \"position\": 1\n}\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/parts/partsIntro.md",
    "content": "---\ntitle: 介绍\nsidebar_position: 1\n---\n## 介绍\n![](https://gw.alicdn.com/imgextra/i2/O1CN01Gyq6AZ1nOENPTVXX7_!!6000000005079-2-tps-256-104.png)\n\n\n「Parts·造物」是基于开源低代码引擎打造的次时代物料研发和集成工具，一方面作为低代码引擎搭建低代码平台的一个样板展示开源生态下的各个组件如何集合在一起形成生产力，另一方面也可以生产低代码平台所需的物料。\n\n目前「Parts·造物」主要提供两大产品功能：\n   1. React 组件导入低代码引擎：通过在线可视化的「物料描述」配置，任意工具开发的 React 组件都可以快速完成对低代码引擎的适配，导入到低代码引擎项目中进行使用。不必额外开发新的组件。\n   2. 低代码生产组件：通过低代码的形式生产组件，极低上手门槛，提供丰富的原子组件用于组合，完善的调试预览和组件生命周期控制。生产的组件既可以在低代码引擎项目中使用，也可以出码后在普通源码项目中使用。\n\n\n## 联系我们\n\n<img src=\"https://img.alicdn.com/imgextra/i2/O1CN01UF88Xi1jC5SZ6m4wt_!!6000000004511-2-tps-750-967.png\" width=\"300\" />\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/parts/partsassets.md",
    "content": "---\ntitle: 资产包管理\nsidebar_position: 4\n---\n\n## 介绍\n\n通过前述介绍，相信大家已经了解如何使用「[Parts·造物](https://parts.lowcode-engine.cn/)」来将已有的 React 组件快速接入低代码引擎，以及生产低代码组件。\n\n大家在使用的过程中，可能会希望构建出来的资产包可以后续随时访问下载，或者希望构建资产包时各个组件的版本等信息可以持久化起来并且能够多人维护。\n\n通过「[Parts·造物](https://parts.lowcode-engine.cn/)」的 `资产包` 管理功能帮助大家解决这个问题\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01Fkaznh1zWj9wYKpcH_!!6000000006722-2-tps-1702-628.png)\n\n## 新建资产包\n\n首先，我们在 我的资产包 tab 中点击 `新建资产包`\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01qe8zfO1ilysebSfD5_!!6000000004454-2-tps-3064-1432.png)\n\n- 填写资产包名称\n- 配置资产包管理员，管理员拥有该资产包的所有权限，初始默认为资产包的创建者，还可以添加其他人作为管理员，\n- 配置资产包描述 (可选)\n- 点击 `确定`, 即可完成资产包的创建\n\n接下来需要为资产包添加一个或者多个组件。\n\n## 添加组件\n\n第二步：新建完资产包以后，我们就可以为其添加组件了，如果是新建资产包流程，新建完成之后会自动弹出组件配置的弹窗，当然，你可可以通过点击资产包卡片的方式打开组件配置的弹窗。\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01kqymdB1nkDQclPk7F_!!6000000005127-2-tps-965-261.png)\n\n- 点击弹窗中 `添加组件` 按钮，在弹出的组件选择面板中，选中需要添加的组件并点击 `下一步`。\n  ![image.png](https://img.alicdn.com/imgextra/i1/O1CN014Baihf1r742Qi1Wel_!!6000000005583-2-tps-1856-1520.png)\n- 进入组件版本以及描述协议版本选择界面，选择所需要的正确版本，点击 `安装` 即可完成一个组件的添加。\n  ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01Y7aWWi1MMPDVlidgz_!!6000000001420-2-tps-1668-1462.png)\n\n## 构建资产包\n\n添加完组件以后就点击 `保存并构建资产包` 进入资产包构建配置弹窗\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01iZf4Ue1PlXnyKYxnK_!!6000000001881-2-tps-1288-670.png)\n\n- `开启缓存` : 可充分利用之前的构建结果缓存来加速资产包的生成，我们会将每个组件的构建结果以 包名和版本号为 key 进行缓存。\n- `任务描述` : 当前构建任务的一些描述信息。\n\n点击 `确认` 按钮 会自动跳转到当前资产包的构建历史界面：\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01krDaFc1TuTztMPssI_!!6000000002442-2-tps-1726-696.png)\n构建历史界面会显示当前资产包所有的构建历史记录，表格状态栏展示了构建的状态：`成功`,`失败`,`正在运行` 三种状态，操作列可以在构建成功时复制或者下载资产包结果\n\n## 使用资产包\n你可以在 [lowcode-demo](https://github.com/alibaba/lowcode-demo) 中直接引用，可直接替换 demo 中原来的资产包文件：\n例如，在 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中，直接用你的资产包文件替换文件[assets.json](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/services/assets.json)，即可快速使用自己的物料了。\n\n### 在编辑器中使用资产包\n在使用含有低代码组件的资产包注意 注意引擎版本必须大于等于 `1.1.0-beta.9`。\n然后直接替换 [lowcode-demo](https://github.com/alibaba/lowcode-demo) demo 中的 `assets.json` 文件即可。\n\n### 在预览中使用资产包\n在预览中使用资产包的整体思路是从 `资产包` 中提取并转换出 `ReactRenderer` 渲染所需要的 react 组件列表 (`components` 参数)，然后将 `schema` 以及 `components` 传入到 `ReactRenderer` 中进行渲染，需要注意的是，在 `资产包` 的转换过程中，我们也需要将 `低代码组件` 转换成 react 组件，具体逻辑可以参考下 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中 `src/parse-assets.ts` 文件的实现。\n基于资产包进行预览的整体逻辑如下： [详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/preview.tsx)：\n```ts\nimport ReactDOM from 'react-dom';\nimport React, { useState } from 'react';\nimport { Loading } from '@alifd/next';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport { createFetchHandler } from '@alilc/lowcode-datasource-fetch-handler';\nimport {\n  getProjectSchemaFromLocalStorage,\n} from './services/mockService';\nimport assets from './services/assets.json';\nimport { parseAssets } from './parse-assets';\n\nconst getScenarioName = function () {\n  if (location.search) {\n    return new URLSearchParams(location.search.slice(1)).get('scenarioName') || 'index';\n  }\n  return 'index';\n};\n\nconst SamplePreview = () => {\n  const [data, setData] = useState({});\n  async function init() {\n    const scenarioName = getScenarioName();\n    const projectSchema = getProjectSchemaFromLocalStorage(scenarioName);\n    const { componentsMap: componentsMapArray, componentsTree } = projectSchema;\n    const schema = componentsTree[0];\n    const componentsMap: any = {};\n    componentsMapArray.forEach((component: any) => {\n      componentsMap[component.componentName] = component;\n    });\n\n    // 特别提醒重点注意！！！：从资产包中解析出所有的 react 组件列表\n    const { components } = await parseAssets(assets);\n\n    setData({\n      schema,\n      components,\n    });\n  }\n\n  const { schema, components } = data;\n\n  if (!schema || !components) {\n    init();\n    return <Loading fullScreen />;\n  }\n\n  return (\n    <div className=\"lowcode-plugin-sample-preview\">\n      <ReactRenderer\n        className=\"lowcode-plugin-sample-preview-content\"\n        schema={schema}\n        // // 将 react 组件列表传入 ReactRenderer 进行渲染\n        components={components}\n        appHelper={{\n          requestHandlersMap: {\n            fetch: createFetchHandler(),\n          },\n        }}\n      />\n    </div>\n  );\n};\n\nReactDOM.render(<SamplePreview />, document.getElementById('ice-container'));\n```\n\n从资产包中解析 react 组件列表的逻辑如下，[详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/parse-assets.ts)：\n```ts\nimport { ComponentDescription, ComponentSchema, RemoteComponentDescription } from '@alilc/lowcode-types';\nimport { buildComponents, AssetsJson, AssetLoader } from '@alilc/lowcode-utils';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport { injectComponents } from '@alilc/lowcode-plugin-inject';\nimport React, { createElement } from 'react';\n\nexport async function parseAssets(assets: AssetsJson) {\n  const { components: rawComponents, packages } = assets;\n  const libraryAsset = [];\n  const libraryMap = {};\n  const packagesMap = {};\n  packages.forEach(pkg => {\n    const { package: _package, library, urls, renderUrls, id } = pkg;\n    if (_package) {\n      libraryMap[id || _package] = library;\n    }\n    packagesMap[id || _package] = pkg;\n    if (renderUrls) {\n      libraryAsset.push(renderUrls);\n    } else if (urls) {\n      libraryAsset.push(urls);\n    }\n  });\n  const assetLoader = new AssetLoader();\n  await assetLoader.load(libraryAsset);\n  let newComponents = rawComponents;\n  if (rawComponents && rawComponents.length) {\n    const componentDescriptions: ComponentDescription[] = [];\n    const remoteComponentDescriptions: RemoteComponentDescription[] = [];\n    rawComponents.forEach((component: any) => {\n      if (!component) {\n        return;\n      }\n      if (component.exportName && component.url) {\n        remoteComponentDescriptions.push(component);\n      } else {\n        componentDescriptions.push(component);\n      }\n    });\n    newComponents = [...componentDescriptions];\n\n    // 如果有远程组件描述协议，则自动加载并补充到资产包中，同时出发 designer.incrementalAssetsReady 通知组件面板更新数据\n    if (remoteComponentDescriptions && remoteComponentDescriptions.length) {\n      await Promise.all(\n        remoteComponentDescriptions.map(async (component: any) => {\n          const { exportName, url, npm } = component;\n          await (new AssetLoader()).load(url);\n          function setAssetsComponent(component: any, extraNpmInfo: any = {}) {\n            const components = component.components;\n            if (Array.isArray(components)) {\n              components.forEach(d => {\n                newComponents = newComponents.concat({\n                  npm: {\n                    ...npm,\n                    ...extraNpmInfo,\n                  },\n                  ...d,\n                } || []);\n              });\n              return;\n            }\n            newComponents = newComponents.concat({\n              npm: {\n                ...npm,\n                ...extraNpmInfo,\n              },\n              ...component.components,\n            } || []);\n          }\n\n          function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') {\n            value.forEach((d: any, i: number) => {\n              const exportName = [preExportName, i.toString()].filter(d => !!d).join('.');\n              const subName = [preSubName, i.toString()].filter(d => !!d).join('.');\n              Array.isArray(d) ? setArrayAssets(d, exportName, subName) : setAssetsComponent(d, {\n                exportName,\n                subName,\n              });\n            });\n          }\n          if (window[exportName]) {\n            if (Array.isArray(window[exportName])) {\n              setArrayAssets(window[exportName] as any);\n            } else {\n              setAssetsComponent(window[exportName] as any);\n            }\n          }\n          return window[exportName];\n        }),\n      );\n    }\n  }\n  const lowcodeComponentsArray = [];\n  const proCodeComponentsMap = newComponents.reduce((acc, cur) => {\n    if ((cur.devMode || '').toLowerCase() === 'lowcode') {\n      lowcodeComponentsArray.push(cur);\n    } else {\n      acc[cur.componentName] = {\n        ...(cur.reference || cur.npm),\n        componentName: cur.componentName,\n      };\n    }\n    return acc;\n  }, {})\n\n  function genLowCodeComponentsMap(components) {\n    const lowcodeComponentsMap = {};\n    lowcodeComponentsArray.forEach((lowcode) => {\n      const id = lowcode.reference?.id;\n      const schema = packagesMap[id]?.schema;\n      const comp = genLowcodeComp(schema, {...components, ...lowcodeComponentsMap});\n      lowcodeComponentsMap[lowcode.componentName] = comp;\n    });\n    return lowcodeComponentsMap;\n  }\n  let components = await injectComponents(buildComponents(libraryMap, proCodeComponentsMap));\n  const lowCodeComponents = genLowCodeComponentsMap(components);\n  return {\n    components: { ...components, ...lowCodeComponents }\n  }\n}\n\nfunction genLowcodeComp(schema: ComponentSchema, components: any) {\n  return class LowcodeComp extends React.Component {\n    render(): React.ReactNode {\n      return createElement(ReactRenderer, {\n        ...this.props,\n        schema,\n        components,\n        designMode: '',\n      });\n    }\n  };\n}\n```\n## 联系我们\n\n<img src=\"https://img.alicdn.com/imgextra/i2/O1CN01UF88Xi1jC5SZ6m4wt_!!6000000004511-2-tps-750-967.png\" width=\"300\" />"
  },
  {
    "path": "docs/docs/guide/expand/editor/parts/partslcc.md",
    "content": "---\ntitle: 低代码组件\nsidebar_position: 2\n---\n## 什么是低代码组件\n我们先了解一下什么是低代码组件，为什么要用低代码组件。\n\n低代码组件是通过可视化的方式生产的组件，这些组件既可以用于低代码搭建体系，也可以用于 ProCode 开发体系（后续迭代）。\n\n那么为什么我们要使用低代码的形式来开发组件：\n* <font color=\"red\"><b>首先</b></font>：<b>轻快</b>，低代码组件只需通过浏览器秒级完成初始化工作，不需要 ProCode 繁重的环境准备；<b>环境一致（低代码环境）</b>，同时能够保证物料的开发环境和真实的运行环境是一致的，不会存在开发和运行环境不一致的问题。\n* <font color=\"red\"><b>其次</b></font>：<b>通用能力可视化方式抽象，提升研发效能</b>，比如获取远程数据、视图开发、依赖管理、生命周期、事件绑定等功能。\n  \n<font color=\"red\">低代码组件不是用来替代 ProCode 的开发方式</font>，而是让开发者可以从 ProCode 中重复的工作脱离出来，抽象更多业务垂直的能力，从而起到提效的作用。\n\n## 创建组件\n\n环境准备：我们可以通过 Parts 提供的通用[低代码组件开发环境](https://parts.lowcode-engine.cn/material#/)开发。\n\n点击开发新组件 --> 填写组件标题 --> 填写组件名称 --> 点击确定，完成组件创建工作。\n\n![](https://img.alicdn.com/imgextra/i2/O1CN01OTQRew25y6WxuONIx_!!6000000007594-2-tps-3396-1696.png)\n\n## 组件开发\n\n一张图速览低代码组件开发的功能模块，其中大部分功能可以参考[低代码引擎文档](https://lowcode-engine.cn/site/docs/guide/quickStart/intro)。\n\n![](https://img.alicdn.com/imgextra/i1/O1CN01gx96E121qzv4smV2v_!!6000000007037-2-tps-3456-1930.png)\n\n### 依赖管理\n\n依赖管理用于管理低代码组件本身的依赖（类似于 dependencies）。步骤：点击添加组件 -->  选择安装的组件 --> 保存并构建 (需要等待几分钟构建)。\n\n![](https://img.alicdn.com/imgextra/i4/O1CN01wC9JPK1J9dKLca9wK_!!6000000000986-2-tps-1438-819.png)\n\n### 属性定义\n\n用于定义组件接收外部传入的 propTypes，组件内部可以通过<font color=\"red\">this.props.${属性名称}</font>的方式获取属性值。\n\n属性定义前建议先阅读 [物料描述详解](https://lowcode-engine.cn/site/docs/guide/expand/editor/metaSpec)、[预置设置器](https://lowcode-engine.cn/site/docs/guide/appendix/setters)。\n\n![](https://img.alicdn.com/imgextra/i2/O1CN01wesIJA1nL1eSPrk7U_!!6000000005072-2-tps-1438-821.png)\n\n![](https://img.alicdn.com/imgextra/i3/O1CN01FZIRwv1es9lGplgIB_!!6000000003926-2-tps-1438-821.png)\n\n### 生命周期\n\n低代码组件的开发支持 componentDidMount、componentDidUpdate、componentDidCatch、componentWillUnmount 几个生命周期\n\n![](https://img.alicdn.com/imgextra/i4/O1CN010bnrxJ1oLlujlfFqj_!!6000000005209-2-tps-1438-819.png)\n\n### 组件调试\n\n我们提供了一套线上实时调试的方案，只需点击右上角的调试按钮，就能自动创建一个低代码应用，在这个应用中可以实时调试当前的低代码组件。\n\n![](https://img.alicdn.com/imgextra/i2/O1CN01Tk96vp1xrDeNeIUJD_!!6000000006496-2-tps-1438-820.png)\n\n在低代码应用中使用，组件面板 --> 低代码组件，找到对应的低代码组件拖入画布即可。\n\n![](https://img.alicdn.com/imgextra/i2/O1CN01oGHLea1lzDAhZQQVO_!!6000000004889-2-tps-1438-819.png)\n\n### 组件发布\n\n同时我们提供了组件发布的功能，用于组件版本管理，点击右上角的发布按钮即可发布组件\n\n![](https://img.alicdn.com/imgextra/i2/O1CN017suVAD1NXEC8zQgO1_!!6000000001579-2-tps-1438-821.png)\n\n## 组件使用\n\n组件的消费是通过资产包来管理的，详情请参考 [资产包管理](./partsassets)。\n\n## 组件导出\n\n开发好的低代码组件可以导出成为 React 组件，脱离低代码引擎独立使用。同时导出功能也为您的组件留出一份备份，您可以放心使用本产品的服务，而不用担心万一出现的不能服务的场景。\n\n在物料列表页面，低代码组件会有一个导出的动作。\n\n![](https://img.alicdn.com/imgextra/i2/O1CN016oUByO21spVHZvvw2_!!6000000007041-2-tps-1395-413.png)\n\n点击导出后，就会开启导出低代码组件的过程。这个过程持续 10s+，导出完成后会为您自动下载对应的 zip 包。\n\n![](https://img.alicdn.com/imgextra/i1/O1CN01lctpIo1aDcEvu75Mo_!!6000000003296-2-tps-1399-512.png)\n\nzip 包解压后可以看到一个完整的组件脚手架工程，您可以在这个工程里继续开发调试，或者发布到合适的 npm 源中。\n\n![](https://img.alicdn.com/imgextra/i1/O1CN010aAjsf1xYRPZBAh7d_!!6000000006455-2-tps-2154-1072.png)\n\n注意：目前导出功能暂不支持 低代码组件嵌套。\n\n## 联系我们\n\n<img src=\"https://img.alicdn.com/imgextra/i2/O1CN01UF88Xi1jC5SZ6m4wt_!!6000000004511-2-tps-750-967.png\" width=\"300\" />"
  },
  {
    "path": "docs/docs/guide/expand/editor/parts/prototype.md",
    "content": "---\ntitle: React 组件导入\nsidebar_position: 3\n---\n## 介绍\n大家在使用[低代码引擎](https://lowcode-engine.cn/)构建低代码应用平台时，遇到的一个主要问题是如何让已有的 React 组件能够快速低成本地接入进来。这个问题拆解下来主要包括两个子问题：\n1. 如何给已有组件[配置物料描述](/site/docs/specs/material-spec)，\n2. 如何构建出一个低代码引擎能够识别的资产包 (Assets)。\n\n我们的产品「[Parts·造物](https://parts.lowcode-engine.cn/)」可以帮助大家解决这个问题。我们通过在线可视化的方式完成物料描述配置，并且提供一键打包的功能生成引擎可以识别的资产包。\n\n## 导入物料\n首先，我们需要在 [物料管理](/site/docs/specs/material-spec) 页面导入我们需要进行在线物料描述配置的物料。\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01IyZdZf1L1VWWU3dnp_!!6000000001239-2-tps-1399-342.png)\n\n- 点击列表左上方的 导入已有物料 按钮\n- 在弹框中输入 npm 包名\n- 点击 获取包信息 按钮，获取 npm 包基本信息\n- 点击确定，导入成功\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN019FwWgs1kqgAXq5UNJ_!!6000000004735-2-tps-640-315.png)\n## 配置管理\n第二步：物料导入以后，我们就可以为导入的物料新增[物料描述配置](/site/docs/specs/material-spec)，点击右侧的组件配置开始配置。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01kqymdB1nkDQclPk7F_!!6000000005127-2-tps-965-261.png)\n### 新增配置\n\n- 点击配置管理右上角的 新增配置\n   - 选择组件的版本号\n   - 填写组件路径，一般和 npm 包的 package.json 里的 main 字段相同（如果填写错误，后面会渲染不出来）\n   - 描述字段用于给这份配置增加一些备注信息。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01i78OhT1cKbVWnXRNu_!!6000000003582-2-tps-596-418.png)\n\n为了降低配置成本，第一次新增配置的时候会自动解析组件代码，生成一份初始化组件物料描述。所以需要等待片刻，用于代码解析。解析完成后，点击配置按钮即可进入在线配置界面。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01R24mTl1tJY3oJ5DCi_!!6000000005881-2-tps-963-232.png)\n\n### 组件描述配置\n操作界面如下，接下来讲具体的配置流程\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01XjSW9I1u662raRg8E_!!6000000005987-2-tps-1438-938.png)\n\n#### 新增组件\n\n如果新增配置的过程中，代码自动解析失败或者解析出来的组件列表不满足开发要求，我们可以点击左侧组件列表插件 新增 按钮，添加新的组件，具体的字段描述可以参考提示内容，以 [react-color](https://github.com/casesandberg/react-color) 为例：\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01A9VFfQ1m9kH2Qliz4_!!6000000004912-2-tps-1436-1005.png)\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01klci7y1IUPflKpeVB_!!6000000000896-2-tps-1193-704.png)\n#### 给组件增加物料描述\n\n- 打开左侧 Setter 面板\n- 按照组件的属性拖入需要 Setter 类型（如图中组件的 width 属性，拖入数字 Setter）\n- 各种 Setter 的介绍可以参看这篇文档：[预置设置器列表](/site/docs/guide/appendix/setters)\n- 配置属性的基本信息（如图所示）\n- 配置完成后点击右上角的保存\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01gxLKBp1RaDEMPS54O_!!6000000002127-2-tps-1434-967.png)\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01uReCQ825yYuwIfj2J_!!6000000007595-2-tps-925-360.png)\n\n#### 高级配置（属性联动）\n\n举个栗子：如图所示，如果期望“设置器”这个配置项的值“被修改”的时候，下面的“默认值”跟着变化。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01bg7X571bpSZdnXTBW_!!6000000003514-2-tps-371-572.png)\n\n如何使用\n\n组件的属性配置目前支持 3 个基本的联动函数：\n\n- 显示状态：返回 true | false，如果返回 true，表示组件配置显示，否则配置时不显示\n- 获取值：当调用该配置节点的 getValue 方法时触发的方法\n- 值变化：当调用该配置节点的 setValue 方法时触发的方法\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN018ZJAJO21q57TdWfjM_!!6000000007035-2-tps-316-142.png)\n\n方法的第一个参数都是当前配置节点的对象，常用到的有以下几个：\n\n- getValue(): 获取当前节点的值，如果当前节点是子节点的话，否则为 undefined\n- setValue(): 设置当前节点的值，如果当前节点是子节点的话\n- parent: 当前节点的父节点\n- getPropValue(propName): 父节点获取子节点的属性值，propName 为子节点的属性名称\n- setPropValue(propName, value): 父节点设置子节点的属性值，propName 为子节点的属性名称，value 为设置的值\n- getConfig: 获取当前节点的配置，如 title、setter 等\n\n\n#### 调试物料描述\n\n点击右上角的预览按钮，开始调试我们刚刚配置的属性，如果是组件的首次预览，会有一段组件构建的过程（构建出 umd 包的过程），构建完成后就可以调试我们的配置了。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN012biqEn1uGAl650nb2_!!6000000006009-2-tps-1431-373.png)\n\n#### 发布物料描述\n物料描述调试没问题后，就可以到项目中去使用了，使用前需要先发布物料描述\n\n- 点击右上角的发布按钮\n- 选择需要发布的组件\n- 点击确定发布完成\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01uwa8RH1QDwM7FN31k_!!6000000001943-2-tps-1431-734.png)\n## 资产包\n第三步：物料描述发布完成后，接下来我们就需要构建出可用的资产包用于低代码应用中。\n\n#### 资产包构建\n有两种方式可以构建资产包：\n- 一种是通过 [`我的资产包`] 资产包管理模块进行整个资产包生命周期的管理，当然也包括资产包的构建，可参考 [资产包管理](./partsassets)\n- 一种是通过 [`我的物料`] 组件物料管理模块的 `资产包构建` 进行构建, 具体操作如下：\n\n  - 选择需要构建的组件\n  - 点击构建资产包按钮\n  - 选择刚刚的物料描述配置\n  - 开始构建，构建完成后你将得到一份 json 文件（里面包含了物料描述和 umd 包），就可以到项目中使用了\n\n#### 资产包使用\n详情请参考 [资产包管理](./partsassets#使用资产包)\n\n## 联系我们\n\n<img src=\"https://img.alicdn.com/imgextra/i2/O1CN01UF88Xi1jC5SZ6m4wt_!!6000000004511-2-tps-750-967.png\" width=\"300\" />\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/pluginContextMenu.md",
    "content": "---\ntitle: 插件扩展 - 编排扩展\nsidebar_position: 6\n---\n\n## 场景一：扩展选中节点操作项\n\n### 增加节点操作项\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01J7PrJc1S86XNDBIFQ_!!6000000002201-2-tps-1240-292.png)\n\n选中节点后，在选中框的右上角有操作按钮，编排模块默认实现了查看组件直系父节点、复制节点和删除节点按钮外，还可以通过相关 API 来扩展更多操作，如下代码：\n\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types';\nimport { Icon, Message } from '@alifd/next';\n\nconst addHelloAction = (ctx: IPublicModelPluginContext) => {\n  return {\n    async init() {\n      ctx.material.addBuiltinComponentAction({\n        name: 'hello',\n        content: {\n          icon: <Icon type=\"atm\" />,\n          title: 'hello',\n          action(node: IPublicModelNode) {\n            Message.show('Welcome to Low-Code engine');\n          },\n        },\n        condition: (node: IPublicModelNode) => {\n          return node.componentMeta.componentName === 'NextTable';\n        },\n        important: true,\n      });\n    },\n  };\n};\naddHelloAction.pluginName = 'addHelloAction';\nawait plugins.register(addHelloAction);\n```\n\n**_效果如下：_**\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01O8W2H61ybw2b7K5nV_!!6000000006598-2-tps-1315-343.png)\n\n具体 API 参考：[API 文档](/site/docs/api/material#addbuiltincomponentaction)\n### 删除节点操作项\n\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst removeCopyAction = (ctx: IPublicModelPluginContext) => {\n  return {\n    async init() {\n      ctx.material.removeBuiltinComponentAction('copy');\n    }\n  }\n};\nremoveCopyAction.pluginName = 'removeCopyAction';\nawait plugins.register(removeCopyAction);\n```\n\n**_效果如下：_**\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01Gfnu8J1O7PTRdoFQZ_!!6000000001658-2-tps-1319-290.png)\n\n具体 API 参考：[API 文档](/site/docs/api/material#removebuiltincomponentaction)\n\n## 实际案例\n\n### 区块管理\n\n- 仓库地址：[https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins)\n- 具体代码：[https://github.com/alibaba/lowcode-plugins/tree/main/packages/action-block](https://github.com/alibaba/lowcode-plugins/tree/main/packages/action-block)\n- 直播回放：\n   - [低代码引擎项目实战 (9)-区块管理 (1)-保存为区块](https://www.bilibili.com/video/BV1YF411M7RK/)\n   - [低代码引擎项目实战 (10)-区块管理 - 区块面板](https://www.bilibili.com/video/BV1FB4y1S7tu/)\n   - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - ICON 优化](https://www.bilibili.com/video/BV1zr4y1H7Km/)\n   - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 自动截图](https://www.bilibili.com/video/BV1GZ4y117VH/)\n   - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 样式优化](https://www.bilibili.com/video/BV1Pi4y1S7ZT/)\n   - [阿里低代码引擎项目实战 (12)-区块管理 (完结)-给引擎插件提个 PR](https://www.bilibili.com/video/BV1hB4y1277o/)\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/pluginWidget.md",
    "content": "---\ntitle: 插件扩展 - 面板扩展\nsidebar_position: 5\n---\n\n## 插件简述\n\n插件功能赋予低代码引擎更高的灵活性，低代码引擎的生态提供了一些官方的插件，但是无法满足所有人的需求，所以提供了强大的插件定制功能。\n\n通过定制插件，在和低代码引擎解耦的基础上，我们可以和引擎核心模块进行交互，从而满足多样化的功能。不仅可以自定义插件的 UI，还可以实现一些非 UI 的逻辑：\n\n1. 调用编辑器框架提供的 API 进行编辑器操作或者 schema 操作；\n2. 通过插件类的生命周期函数实现一些插件初始化的逻辑；\n3. 通过实现监听编辑器内的消息实现特定的切片逻辑（例如面板打开、面板关闭等）；\n\n> 本文仅介绍面板层面的扩展，编辑器插件层面的扩展可以参考 [\"插件扩展 - 编排扩展\"](./pluginContextMenu.md) 章节。\n\n## 注册插件 API\n\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst pluginA = (ctx: IPublicModelPluginContext, options: any) => {\n\treturn {\n    init() {\n      console.log(options.key);\n      // 往引擎增加面板\n      ctx.skeleton.add({\n        // area 配置见下方说明\n        area: 'leftArea',\n        // type 配置见下方说明\n        type: 'PanelDock',\n        content: <div>demo</div>,\n      });\n      ctx.logger.log('打个日志');\n    },\n    destroy() {\n      console.log('我被销毁了~');\n    },\n  };\n};\n\npluginA.pluginName = 'pluginA';\n\nplugins.register(pluginA, { key: 'test' });\n```\n\n> 如果您想了解抽取出来的插件如何封装成为一个 npm 包并提供给社区，可以参考[“低代码生态脚手架 & 调试机制”](./cli)章节。\n\n## 面板插件配置说明\n\n面板插件是作用于设计器的，主要是通过按钮、图标等展示在设计器的骨架中。设计器的骨架我们分为下面的几个区域，而我们的插件大多数都是作用于这几个区域的。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01Bkfm9E1MQWmBWeIOh_!!6000000001429-2-tps-1920-1080.png)\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01y05ZHC1Gix0p4nXxH_!!6000000000657-2-tps-3068-1648.png)\n\n### 展示区域 area\n\n#### topArea\n\n展示在设计器的顶部区域，常见的相关区域的插件主要是：、\n\n1. 注册设计器 Logo；\n2. 设计器操作回退和撤销按钮；\n3. 全局操作按钮，例如：保存、预览等；\n\n#### leftArea\n\n左侧区域的展示形式大多数是 Icon 和对应的面板，通过点击 Icon 可以展示对应的面板并隐藏其他的面板。\n\n该区域相关插件的主要有：\n\n1. 大纲树展示，展示该设计器设计页面的大纲。\n2. 组件库，展示注册到设计器中的组件，点击之后，可以从组件库面板中拖拽到设计器的画布中。\n3. 数据源面板\n4. JS 等代码面板。\n\n可以发现，这个区域的面板大多数操作时是不需要同时并存的，且交互比较复杂的，需要一个更整块的区域来进行操作。\n\n#### centerArea\n\n画布区域，由于画布大多数是展示作用，所以一般扩展的种类比较少。常见的扩展有：\n\n1. 画布大小修改\n2. 物料选中扩展区域修改\n\n#### rightArea\n\n右侧区域，常用于组件的配置。常见的扩展有：统一处理组件的配置项，例如统一删除某一个配置项，统一添加某一个配置项的。\n\n#### toolbar\n\n跟 topArea 类似，按需放置面板插件~\n\n### 展示形式 type\n\n#### PanelDock\n\nPanelDock 是以面板的形式展示在设计器的左侧区域的。其中主要有两个部分组成，一个是图标，一个是面板。当点击图标时可以控制面板的显示和隐藏。\n\n下图是组件库插件的展示效果。\n\n![Feb-08-2022 19-44-15.gif](https://img.alicdn.com/imgextra/i3/O1CN01XCrv5Q1hR5BgsyAiq_!!6000000004273-1-tps-1536-790.gif)\n\n其中右上角可以进行固定，可以对弹出的宽度做设定\n\n接入可以参考代码\n\n```javascript\nimport { skeleton } from '@alilc/lowcode-engine';\n\nskeleton.add({\n  area: 'leftArea', // 插件区域\n  type: 'PanelDock', // 插件类型，弹出面板\n  name: 'sourceEditor',\n  content: SourceEditor, // 插件组件实例\n  props: {\n    align: \"left\",\n    icon: \"wenjian\",\n    description: \"JS 面板\",\n  },\n  panelProps: {\n    floatable: true, // 是否可浮动\n    height: 300,\n    hideTitleBar: false,\n    maxHeight: 800,\n    maxWidth: 1200,\n    title: \"JS 面板\",\n    width: 600,\n  },\n});\n```\n\n#### Widget\n\nWidget 形式是直接渲染在当前编辑器的对应位置上。如 demo 中在设计器顶部的所有组件都是这种展现形式。\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01h89p5W1pfknnzwMqS_!!6000000005388-2-tps-1988-94.png)\n\n接入可以参考代码：\n\n```javascript\nimport { skeleton } from '@alilc/lowcode-engine';\n// 注册 logo 面板\nskeleton.add({\n  area: 'topArea',\n  type: 'Widget',\n  name: 'logo',\n  content: Logo, // Widget 组件实例\n  contentProps: { // Widget 插件 props\n    logo:\n    \"https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png\",\n    href: \"/\",\n  },\n  props: {\n    align: 'left',\n    width: 100,\n  },\n});\n```\n\n#### Dock\n\n一个图标的表现形式，可以用于语言切换、跳转到外部链接、打开一个 widget 等场景。\n\n```javascript\nimport { skeleton } from '@alilc/lowcode-engine';\n\nskeleton.add({\n  area: 'leftArea',\n  type: 'Dock',\n  name: 'opener',\n  props: {\n    icon: Icon, // Icon 组件实例\n    align: 'bottom',\n    onClick: function () {\n      // 打开外部链接\n      window.open('https://lowcode-engine.cn');\n      // 显示 widget\n      skeleton.showWidget('xxx');\n    }\n  }\n});\n```\n\n#### Panel\n\n一般不建议单独使用，通过 PanelDock 使用~\n\n## 实际案例\n\n### 页面管理面板\n\n- 仓库地址：[https://github.com/mark-ck/lowcode-portal](https://github.com/mark-ck/lowcode-portal)\n- 具体代码：[https://github.com/mark-ck/lowcode-portal/blob/master/src/plugins/pages-plugin/index.tsx](https://github.com/mark-ck/lowcode-portal/blob/master/src/plugins/pages-plugin/index.tsx)\n- 直播回放：\n   - [低代码引擎项目实战 (4)-自定义插件 - 页面管理](https://www.bilibili.com/video/BV17a411i73f/)\n   - [低代码引擎项目实战 (4)-自定义插件 - 页面管理 - 后端](https://www.bilibili.com/video/BV1uZ4y1U7Ly/)\n   - [低代码引擎项目实战 (4)-自定义插件 - 页面管理 - 前端](https://www.bilibili.com/video/BV1Yq4y1a74P/)\n   - [低代码引擎项目实战 (4)-自定义插件 - 页面管理 - 完结](https://www.bilibili.com/video/BV13Y4y1e7EV/)\n\n### 区块面板\n\n- 仓库地址：[https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins)\n- 具体代码：[https://github.com/alibaba/lowcode-plugins/tree/main/packages/plugin-block](https://github.com/alibaba/lowcode-plugins/tree/main/packages/plugin-block)\n- 直播回放：\n   - [低代码引擎项目实战 (9)-区块管理 (1)-保存为区块](https://www.bilibili.com/video/BV1YF411M7RK/)\n   - [低代码引擎项目实战 (10)-区块管理 - 区块面板](https://www.bilibili.com/video/BV1FB4y1S7tu/)\n   - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - ICON 优化](https://www.bilibili.com/video/BV1zr4y1H7Km/)\n   - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 自动截图](https://www.bilibili.com/video/BV1GZ4y117VH/)\n   - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 样式优化](https://www.bilibili.com/video/BV1Pi4y1S7ZT/)\n   - [阿里低代码引擎项目实战 (12)-区块管理 (完结)-给引擎插件提个 PR](https://www.bilibili.com/video/BV1hB4y1277o/)\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/setter.md",
    "content": "---\ntitle: 设置器扩展\nsidebar_position: 7\n---\n## 设置器简述\n\n设置器主要用于低代码组件属性值的设置，顾名思义叫\"设置器\"，又称为 Setter。由于组件的属性有各种类型，需要有与之对应的设置器支持，每一个设置器对应一个值的类型。\n\n### 设计器展示位置\n\n设置器展示在编辑器的右边区域，如下图：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01F0yBV91jNzkZKLzvJ_!!6000000004537-2-tps-3836-1730.png)\n\n其中包含四类设置器：\n\n- 属性：展示该物料常规的属性\n- 样式：展示该物料样式的属性\n- 事件：如果该物料有声明事件，则会出现事件面板，用于绑定事件。\n- 高级：两个逻辑相关的属性，**条件渲染**和**循环**\n\n### 设置器类型\n\n上述区域中是有多项设置器的，对于一个组件来说，每一项配置都对应一个设置器，比如我们的配置是一个文本，我们需要的是文本设置器，我们需要配置的是数字，我们需要的就是数字设置器。\n下图中的标题和按钮类型配置就分别是文本设置器和下拉框设置器。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01uMd1zQ20fiXawR4IU_!!6000000006877-2-tps-2120-1460.png)\n\n我们提供了常用的设置器作为内置设置器，也提供了定制能力帮助大家开发特定需求的设置器。\n\n## 为物料配置设置器\n\n我们提供了[常用的设置器](/site/docs/guide/appendix/setters)作为内置设置器。\n\n我们可以将目标组件的属性值类型值配置到物料资源配置文件中：\n\n```json\n{\n  \"componentName\": \"Message\",\n  \"title\": \"Message\",\n  \"configure\": {\n    \"props\": [\n      {\n        \"name\": \"type\",\n        \"setter\": \"InputSetter\"\n      }\n    ]\n  }\n}\n```\n\nprops 字段是入料模块扫描自动填入的类型，用户可以通过 configure 节点进行配置通过 override 节点对属性的声明重新定义，setter 就是注册在引擎中的 setter。\n\n为物料配置引擎内置的 setter 时，均可以使用对应 setter 的高级功能，对应功能参考“全部内置设置器”章节下的对应 setter 文章。\n\n### 对高级功能的配置如下：\n\n例如我们需要在 NumberSetter 中配置 units 属性，可以在 asset.json 中声明。\n\n```json\n\"configure\": {\n  \"component\": {\n    \"isContainer\": true,\n    \"nestingRule\": {\n      \"parentWhitelist\": [\n        \"NextP\"\n      ]\n    }\n  },\n  \"props\": [\n    {\n      \"name\": \"width\",\n      \"title\": \"宽度\",\n      \"initialValue\": \"auto\",\n      \"defaultValue\": \"auto\",\n      \"condition\": {\n        \"type\": \"JSFunction\",\n        \"value\": \"() => false\"\n      },\n      \"setter\": {\n        \"componentName\": \"NumberSetter\",\n        \"props\": {\n          \"units\": [\n            {\n              \"type\": \"px\",\n              \"list\": true\n            },\n            {\n              \"type\": \"%\",\n              \"list\": true\n            }\n          ]\n        }\n      }\n    },\n  ],\n  \"supports\": {\n    \"style\": true\n  }\n},\n```\n\n## 自定义设置器\n### 编写 AltStringSetter\n\n我们编写一个简单的 Setter，它的功能如下：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01fQ4GLd1RzrPSdULiw_!!6000000002183-2-tps-720-90.png)\n\n**代码如下：**\n```tsx\nimport * as React from \"react\";\nimport { Input } from \"@alifd/next\";\nimport \"./index.scss\";\n\ninterface AltStringSetterProps {\n  // 当前值\n  value: string;\n  // 默认值\n  defaultValue: string;\n  // setter 唯一输出\n  onChange: (val: string) => void;\n  // AltStringSetter 特殊配置\n  placeholder: string;\n}\n\nexport default class AltStringSetter extends React.PureComponent<AltStringSetterProps> {\n  // 声明 Setter 的 title\n \tstatic displayName = 'AltStringSetter';\n\n  componentDidMount() {\n    const { onChange, value, defaultValue } = this.props;\n    if (value == undefined && defaultValue) {\n      onChange(defaultValue);\n    }\n  }\n\n  render() {\n    const { onChange, value, placeholder } = this.props;\n    return (\n      <Input\n        value={value}\n        placeholder={placeholder || \"\"}\n        onChange={(val: any) => onChange(val)}\n      ></Input>\n    );\n  }\n}\n```\n\n#### setter 和 setter/plugin 之间的联动\n\n我们采用 emit 来进行相互之前的通信，首先我们在 A setter 中进行事件注册：\n\n```javascript\nimport { event } from '@alilc/lowcode-engine';\n\ncomponentDidMount() {\n\t\t// 这里由于面板上会有多个 setter，这里我用 field.id 来标记 setter 名\n    this.emitEventName = `${SETTER_NAME}-${this.props.field.id}`;\n    event.on(`${this.emitEventName}.bindEvent`, this.bindEvent);\n}\n\nbindEvent = (eventName) => {\n  // do someting\n}\n\ncomponentWillUnmount() {\n  // setter 是以实例为单位的，每个 setter 注销的时候需要把事件也注销掉，避免事件池过多\n  event.off(`${this.emitEventName}.bindEvent`, this.bindEvent);\n}\n```\n\n在 B setter 中触发事件，来完成通信：\n\n```javascript\nimport { event } from '@alilc/lowcode-engine';\n\nbindFunction = () => {\n  const { field, value } = this.props;\n  // 这里展示的和插件进行通信，事件规则是插件名 + 方法\n  event.emit('eventBindDialog.openDialog', field.name, this.emitEventName);\n}\n```\n\n#### 修改同级 props 的其他属性值\n\nsetter 本身只影响其中一个 props 的值，如果需要影响其他组件的 props 的值，需要使用 field 的 props：\n\n```javascript\nbindFunction = () => {\n    const { field, value } = this.props;\n    const propsField = field.parent;\n\t\t// 获取同级其他属性 showJump 的值\n    const otherValue = propsField.getPropValue('showJump');\n    // set 同级其他属性 showJump 的值\n    propsField.setPropValue('showJump', false);\n}\n```\n\n### 注册 AltStringSetter\n\n我们需要在低代码引擎中注册 Setter，这样就可以通过 AltStringSetter 的名字在物料中使用了。\n\n```typescript\nimport AltStringSetter from './AltStringSetter';\nconst registerSetter = window.AliLowCodeEngine.setters.registerSetter;\nregisterSetter('AltStringSetter', AltStringSetter);\n```\n\n### 物料中使用\n\n我们需要将目标组件的属性值类型值配置到物料资源配置文件中，其中核心配置如下：\n\n```json\n{\n  \"props\": [\n    {\n      \"name\": \"type\",\n      \"setter\": \"AltStringSetter\"\n    }\n  ]\n}\n```\n\n在物料中的相关配置如下：\n\n```json\n{\n  \"componentName\": \"Message\",\n  \"title\": \"Message\",\n  \"configure\": {\n    \"props\": [\n      {\n        \"name\": \"type\",\n        \"setter\": \"AltStringSetter\"\n      }\n    ]\n  }\n}\n```"
  },
  {
    "path": "docs/docs/guide/expand/editor/summary.md",
    "content": "---\ntitle: 编辑态扩展简述\nsidebar_position: 0\n---\n## 扩展点简述\n\n我们可以从 Demo 的项目中看到页面中有很多的区块：\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01WkdvNi1TamxZblYFA_!!6000000002399-2-tps-3840-2160.png)\n这些功能点背后都是可扩展项目，如下图所示：\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01wZLOzm24hmnMTwXdF_!!6000000007423-2-tps-3838-1914.png)\n\n- 插件定制：可以配置低代码编辑器的功能和面板\n- 物料定制：可以配置能够拖入的物料\n- 操作辅助区定制：可以配置编辑器画布中的操作辅助区功能\n- 设置器定制：可以配置编辑器中组件的配置表单\n\n我们从可扩展项目的视角，可以把低代码引擎架构理解为下图：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01fhZ3Q11hwE7RwSq7g_!!6000000004341-2-tps-3840-2160.png)\n（注：引擎内核中大量数据交互的细节被简化，这张图仅仅强调编辑器和外部扩展的交互）\n\n## 配置扩展点\n\n### 配置物料\n通过配置注入物料，这里的配置是物料中心根据物料资产包协议生成的，后面“物料扩展”章节会有详细说明。\n```typescript\nimport { material } from '@alilc/lowcode-engine';\n// 假设您已把物料配置在本地\nimport assets from './assets.json';\n\n// 静态加载 assets\nmaterial.setAssets(assets);\n```\n\n也可以通过异步加载物料中心上的物料。\n```typescript\nimport { material, plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\n// 动态加载 assets\nplugins.register((ctx: IPublicModelPluginContext) => {\n  return {\n    name: 'ext-assets',\n    async init() {\n      try {\n        // 将下述链接替换为您的物料即可。无论是通过 utils 从物料中心引入，还是通过其他途径如直接引入物料描述\n        const res = await window.fetch('https://fusion.alicdn.com/assets/default@0.1.95/assets.json')\n        const assets = await res.text()\n        material.setAssets(assets)\n      } catch (err) {\n        console.error(err)\n      }\n    },\n  }\n}).catch(err => console.error(err));\n```\n\n### 配置插件\n可以通过 npm 包的方式引入社区插件，配置如下所示：\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\nimport PluginIssueTracker from '@alilc/lowcode-plugin-issue-tracker';\n\n// 注册一个提 issue 组件到您的编辑器中，方位默认在左栏下侧\nplugins.register(PluginIssueTracker)\n  .catch(err => console.error(err));\n```\n后续“插件扩展”章节会详细说明。\n\n### 配置设置器\n低代码引擎默认内置了设置器（详见“配置设置器”章节）。您可以通过 npm 包的方式引入自定义的设置器，配置如下所示：\n```typescript\nimport { setters } from '@alilc/lowcode-engine';\n// 假设您自定义了一个 setter\nimport MuxMonacoEditorSetter from './components/setters/MuxMonacoEditorSetter';\n\n// 注册设置器\nsetters.registerSetter({\n  MuxMonacoEditorSetter: {\n    component: MuxMonacoEditorSetter,\n    title: 'Textarea',\n    condition: (field) => {\n      const v = field.getValue()\n      return typeof v === 'string'\n    },\n  },\n});\n```\n后续“设置器扩展”章节会详细说明。\n\n> 本章节所有可扩展配置内容在 demo 中均可找到：[https://github.com/alibaba/lowcode-demo/tree/main/demo-general](https://github.com/alibaba/lowcode-demo/tree/main/demo-general)\n"
  },
  {
    "path": "docs/docs/guide/expand/editor/theme.md",
    "content": "---\ntitle: 主题色扩展\nsidebar_position: 9\n---\n\n## 简介\n\n主题色扩展允许用户定制多样的设计器主题，增加界面的个性化和品牌识别度。\n\n## 设计器主题色定制\n\n在 CSS 的根级别定义主题色变量可以确保这些变量在整个应用中都可用。例如：\n\n```css\n:root {\n  --color-brand: rgba(0, 108, 255, 1); /* 主品牌色 */\n  --color-brand-light: rgba(25, 122, 255, 1); /* 浅色品牌色 */\n  --color-brand-dark: rgba(0, 96, 229, 1); /* 深色品牌色 */\n}\n\n```\n\n将样式文件引入到你的设计器中，定义的 CSS 变量就可以改变设计器的主题色了。\n\n### 主题色变量\n\n以下是低代码引擎设计器支持的主题色变量列表，以及它们的用途说明：\n\n#### 品牌相关颜色\n\n- `--color-brand`: 主品牌色\n- `--color-brand-light`: 浅色品牌色\n- `--color-brand-dark`: 深色品牌色\n\n#### Icon 相关颜色\n\n- `--color-icon-normal`: 默认状态\n- `--color-icon-light`: icon light 状态\n- `--color-icon-hover`: 鼠标悬停状态\n- `--color-icon-active`: 激活状态\n- `--color-icon-reverse`: 反色状态\n- `--color-icon-disabled`: 禁用状态\n- `--color-icon-pane`: 面板颜色\n\n#### 线条和文本颜色\n\n- `--color-line-normal`: 线条颜色\n- `--color-line-darken`: 线条颜色(darken)\n- `--color-title`: 标题颜色\n- `--color-text`: 文字颜色\n- `--color-text-dark`: 文字颜色(dark)\n- `--color-text-light`: 文字颜色(light)\n- `--color-text-reverse`: 反色情况下，文字颜色\n- `--color-text-disabled`: 禁用态文字颜色\n\n#### 菜单颜色\n- `--color-context-menu-text`: 菜单项颜色\n- `--color-context-menu-text-hover`: 菜单项 hover 颜色\n- `--color-context-menu-text-disabled`: 菜单项 disabled 颜色\n\n#### 字段和边框颜色\n\n- `--color-field-label`: field 标签颜色\n- `--color-field-text`: field 文本颜色\n- `--color-field-placeholder`: field placeholder 颜色\n- `--color-field-border`: field 边框颜色\n- `--color-field-border-hover`: hover 态下，field 边框颜色\n- `--color-field-border-active`: active 态下，field 边框颜色\n- `--color-field-background`: field 背景色\n\n#### 状态颜色\n\n- `--color-success`: success 颜色\n- `--colo-success-dark`: success 颜色(dark)\n- `--color-success-light`: success 颜色(light)\n- `--color-warning`: warning 颜色\n- `--color-warning-dark`: warning 颜色(dark)\n- `--color-warning-light`: warning 颜色(light)\n- `--color-information`: information 颜色\n- `--color-information-dark`: information 颜色(dark)\n- `--color-information-light`: information 颜色(light)\n- `--color-error`: error 颜色\n- `--color-error-dark`: error 颜色(dark)\n- `--color-error-light`: error 颜色(light)\n- `--color-purple`: purple 颜色\n- `--color-brown`: brown 颜色\n\n#### 区块背景色\n\n- `--color-block-background-normal`: 区块背景色\n- `--color-block-background-light`: 区块背景色(light)。\n- `--color-block-background-shallow`: 区块背景色 shallow\n- `--color-block-background-dark`: 区块背景色(dark)\n- `--color-block-background-disabled`: 区块背景色(disabled)\n- `--color-block-background-active`: 区块背景色(active)\n- `--color-block-background-active-light`: 区块背景色(active light)\n- `--color-block-background-warning`: 区块背景色(warning)\n- `--color-block-background-error`: 区块背景色(error)\n- `--color-block-background-success`: 区块背景色(success)\n- `--color-block-background-deep-dark`: 区块背景色(deep-dark)，作用于多个组件同时拖拽的背景色。\n\n#### 引擎相关颜色\n\n- `--color-canvas-detecting-background`: 画布组件 hover 时遮罩背景色。\n\n#### 其他区域背景色\n\n- `--color-layer-mask-background`: 拖拽元素时，元素原来位置的遮罩背景色\n- `--color-layer-tooltip-background`: tooltip 背景色\n- `--color-pane-background`: 面板背景色\n- `--color-background`: 设计器主要背景色\n- `--color-top-area-background`: topArea 背景色，优先级大于 `--color-pane-background`\n- `--color-left-area-background`: leftArea 背景色，优先级大于 `--color-pane-background`\n- `--color-toolbar-background`: toolbar 背景色，优先级大于 `--color-pane-background`\n- `--color-workspace-left-area-background`: 应用级 leftArea 背景色，优先级大于 `--color-pane-background`\n- `--color-workspace-top-area-background`: 应用级 topArea 背景色，优先级大于 `--color-pane-background`\n- `--color-workspace-sub-top-area-background`: 应用级二级 topArea 背景色，优先级大于 `--color-pane-background`\n\n#### 其他变量\n\n- `--workspace-sub-top-area-height`: 应用级二级 topArea 高度\n- `--top-area-height`: 顶部区域的高度\n- `--workspace-sub-top-area-margin`: 应用级二级 topArea margin\n- `--workspace-sub-top-area-padding`: 应用级二级 topArea padding\n- `--workspace-left-area-width`: 应用级 leftArea width\n- `--left-area-width`: leftArea width\n- `--simulator-top-distance`: simulator 距离容器顶部的距离\n- `--simulator-bottom-distance`:  simulator 距离容器底部的距离\n- `--simulator-left-distance`: simulator 距离容器左边的距离\n- `--simulator-right-distance`: simulator 距离容器右边的距离\n- `--toolbar-padding`: toolbar 的 padding\n- `--toolbar-height`: toolbar 的高度\n- `--pane-title-height`: 面板标题高度\n- `--pane-title-font-size`: 面板标题字体大小\n- `--pane-title-padding`: 面板标题边距\n- `--context-menu-item-height`: 右键菜单项高度\n\n\n\n### 低代码引擎生态主题色定制\n\n插件、物料、设置器等生态为了支持主题色需要对样式进行改造，需要对生态中的样式升级为 css 变量。例如：\n\n```css\n/* before */\nbackground: #006cff;\n\n/* after */\nbackground: var(--color-brand, #006cff);\n\n```\n\n这里 `var(--color-brand, #默认色)` 表示使用 `--color-brand` 变量，如果该变量未定义，则使用默认颜色（#默认色）。\n\n### fusion 物料进行主题色扩展\n\n如果使用了 fusion 组件时，可以通过 [fusion 平台](https://fusion.design/) 进行主题色定制。在平台上，您可以选择不同的主题颜色，并直接应用于您的 fusion 组件，这样可以无缝地集成到您的应用设计中。"
  },
  {
    "path": "docs/docs/guide/expand/runtime/_category_.json",
    "content": "{\n  \"label\": \"扩展运行时\",\n  \"position\": 2,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/guide/expand/runtime/codeGeneration.md",
    "content": "---\ntitle: 使用出码功能\nsidebar_position: 1\n---\n\n## 出码简述\n所谓出码，即将低代码编排出的 schema 进行解析并转换成最终可执行的代码的过程。\n## 出码的适用范围\n出码是为了更高效的运行和更灵活地定制渲染，相对而言，基于 Schema 的运行时渲染，有着能实时响应内容的变化和接入成本低的优点，但是也存在着实时解析运行的性能开销比较大和包大小比较大的问题，而且无法自由地进行扩展二次开发，功能自由度受到一定程度限制。\n当然，出码也会存在一些限制：一方面需要额外的接入成本，另一方面通常需要额外的生成代码和打包构建的时间，难以做到基于 Schema 的运行时渲染那样保存即预览的效果。\n\n所以不是所有场景都建议做出码，一般来说以下 3 个场景可以考虑使用出码进行优化。\n\n### 场景一：想要极致的打开速度，降低 LCP/FID\n这种场景比较常见的是 C 端应用，比如手淘上的页面和手机钉钉上的页面，要求能够尽快得响应用户操作，不要出现卡死的情况。当一个流入协议大小比较大的时候，前端进行解析时的开销也比较大。如果能把这部分负担转移到编译时去完成的话，前端依赖包大小就会减少许多。从而也提升了加载速度，降低了带宽消耗。页面越简单，这其中的 gap 就会越明显。\n\n### 场景二：老项目 + 新需求，想用搭建产出\n这是一个很常见的场景，毕竟迁移或者重构都是有一个过程的，阿里的业务都是一边跑一边换发动机。在这种场景中，我们不可能要求使用运行时方案来做实现，因为运行时是一个项目级别的能力，最好是项目中统一使用他这一种方式，保证体验的一致性与连贯性。所以我们可以只在低代码平台上搭建新的业务页面，然后通过出码模块导出这些页面的源码，连同一些全局依赖模块，一起 Merge 到老项目中。完成开发体验的优化。\n\n### 场景三：协议不能描述部分代码逻辑（协议功能不足或特别定制化的逻辑）\n当我们发现一些逻辑诉求不能在目前协议中很好地表达的时候，这其实是项目复杂度较高的一个信号。比较好的方式就是将低代码研发和源码研发结合起来。这种模式下最大的诉求点之一就是，需要将搭建的内容输出为可读性和确定性都比较良好的代码模块。这也就是出码模块需要支持好的使用场景了。\n\n## 如何使用\n### 1) 通过命令行快速体验\n\n欢迎使用命令行工具快速体验：`npx @alilc/lowcode-code-generator -i example-schema.json -o generated -s icejs3`\n\n--其中 example-schema.json 可以从[这里下载](https://alifd.alicdn.com/npm/@alilc/lowcode-code-generator@latest/example-schema.json)\n\n### 2) 通过设计器插件快速体验\n\n1. 安装依赖： `npm install --save @alilc/lowcode-plugin-code-generator`\n2. 注册插件：\n\n```typescript\nimport { plugins } from '@alilc/lowcode-engine';\nimport CodeGenPlugin from '@alilc/lowcode-plugin-code-generator';\n\n// 在你的初始化函数中：\nawait plugins.register(CodeGenPlugin);\n\n// 如果您不希望自动加上出码按钮，则可以这样注册\nawait plugins.register(CodeGenPlugin, { disableCodeGenActionBtn: true });\n```\n\n然后运行你的低代码编辑器项目即可 -- 在设计器的右上角会出现一个“出码”按钮，点击即可在浏览器中出码并预览。\n\n### 3）服务端出码接入\n\n此代码生成器一开始就是为服务端出码设计的，你可以直接这样来在 node.js 环境中使用：\n\n1. 安装依赖： `npm install --save @alilc/lowcode-code-generator`\n2. 引入代码生成器：\n\n```javascript\nimport CodeGenerator from '@alilc/lowcode-code-generator';\n```\n\n3. 创建项目构建器：\n\n```javascript\nconst projectBuilder = CodeGenerator.solutions.icejs();\n```\n\n4. 生成代码\n\n```javascript\nconst project = await projectBuilder.generateProject(\n  schema, // 编排搭建出来的 schema\n);\n```\n\n5. 将生成的代码写入到磁盘中 (也可以生成一个 zip 包)\n\n```javascript\n// 写入磁盘\nawait CodeGenerator.publishers.disk().publish({\n  project, // 上一步生成的 project\n  outputPath: '/path/to/your/output/dir', // 输出目录\n  projectSlug: 'your-project-slug', // 项目标识\n});\n\n// 写入到 zip 包\nawait CodeGenerator.publishers.zip().publish({\n  project, // 上一步生成的 project\n  outputPath: '/path/to/your/output/dir', // 输出目录\n  projectSlug: 'your-project-slug', // 项目标识 -- 对应生成 your-project-slug.zip 文件\n});\n```\n\n注：一般来说在服务端出码可以跟 github/gitlab, CI 和 CD 流程等一起串起来使用，通常用于优化性能。\n\n### 4）浏览器中出码接入\n\n随着现在电脑性能和浏览器技术的发展，出码其实已经不必非得在服务端做了，借助于 Web Worker 特性，可以在浏览器中进行出码：\n\n1. 安装依赖： `npm install --save @alilc/lowcode-code-generator`\n2. 引入代码生成器：\n\n```javascript\nimport * as CodeGenerator from '@alilc/lowcode-code-generator/standalone-loader';\n```\n\n3. 【可选】提前初始化代码生成器：\n\n```javascript\n// 提前初始化下，这样后面用的时候更快 (这个 init 内部会提前准备好创建 worker 的一些资源)\nawait CodeGenerator.init();\n```\n\n4. 出码\n\n```javascript\nconst result = await CodeGenerator.generateCode({\n  solution: 'icejs', // 出码方案 (目前内置有 icejs、icejs3 和 rax )\n  schema, // 编排搭建出来的 schema\n});\n\nconsole.log(result); // 出码结果 (默认是递归结构描述的，可以传 flattenResult: true 以生成扁平结构的结果)\n```\n\n注：一般来说在浏览器中出码适合做即时预览功能。\n\n### 5）自定义出码\n前端框架灵活多变，默认内置的出码方案很难满足所有人的需求，好在此代码生成器支持非常灵活的插件机制 -- 内置功能大多都是通过插件完成的（在 `src/plugins`下），比如：\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01CEl2Hq1omnH0UCyGF_!!6000000005268-2-tps-457-376.png)\n\n所以您可以通过添加自己的插件或替换掉默认内置的插件来实现您的自定义功能。\n为了方便自定义出码方案，出码模块还提供自定义出码方案的脚手架功能，即执行下面脚本即可生成一个自定义出码方案：\n```shell\nnpx @alilc/lowcode-code-generator init-solution <your-solution-name>\n```\n里面内置了一个示例的插件 (在 `src/plugins/example.ts`中)，您可以根据注释引导来完善相关插件，从而组合生成您的专属出码方案 (`src/index.ts`)。您所生成的出码方案可以发布成 NPM 包，从而能按上文 1~4 中的使用方案进行使用。\n"
  },
  {
    "path": "docs/docs/guide/expand/runtime/renderer.md",
    "content": "---\ntitle: 使用渲染模块\nsidebar_position: 0\n---\n## 快速使用\n渲染依赖于 schema 和 components。其中 schema 和 components 需要一一对应，schema 中使用到的组件都需要在 components 中进行声明，否则无法正常渲染。\n### 简单示例\n\n```jsx\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport ReactDOM from 'react-dom';\nimport { Button } from '@alifd/next';\n\nconst schema = {\n  componentName: 'Page',\n  props: {},\n  children: [\n    {\n      componentName: 'Button',\n      props: {\n        type: 'primary',\n        style: {\n          color: '#2077ff'\n        },\n      },\n      children: '确定',\n    },\n  ],\n};\n\nconst components = {\n  Button,\n};\n\nReactDOM.render((\n  <ReactRenderer\n    schema={schema}\n    components={components}\n  />\n), document.getElementById('root'));\n```\n\n####\n### 项目使用示例\n> [设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html)\n> 项目代码完整示例：[https://github.com/alibaba/lowcode-demo](https://github.com/alibaba/lowcode-demo)\n\n**step 1：在设计器中获取组件列表**\n```typescript\nimport { material, project } from '@alilc/lowcode-engine';\nconst packages = material.getAssets().packages\n```\n**step 2：在设计器中获取当前配置页面的 schema**\n```typescript\nimport { material, project } from '@alilc/lowcode-engine';\n\nconst schema = project.exportSchema();\n```\n\n\n**step 3：以某种方式存储 schema 和 packages**\n这里用 localStorage 作为存储示例，真实项目中使用数据库或者其他存储方式。\n```typescript\nwindow.localStorage.setItem(\n  'projectSchema',\n  JSON.stringify(project.exportSchema())\n);\nconst packages = await filterPackages(material.getAssets().packages);\nwindow.localStorage.setItem(\n  'packages',\n  JSON.stringify(packages)\n);\n```\n**step 4：预览时，获取存储的 schema 和 packages**\n```typescript\nconst packages = JSON.parse(window.localStorage.getItem('packages') || '');\nconst projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || '');\nconst { componentsMap: componentsMapArray, componentsTree } = projectSchema;\n```\n**step 5：通过整合 schema 和 packages 信息，进行渲染**\n```typescript\nimport ReactDOM from 'react-dom';\nimport React, { useState } from 'react';\nimport { Loading } from '@alifd/next';\nimport { buildComponents, assetBundle, AssetLevel, AssetLoader } from '@alilc/lowcode-utils';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport { injectComponents } from '@alilc/lowcode-plugin-inject';\n\nconst SamplePreview = () => {\n  const [data, setData] = useState({});\n\n  async function init() {\n    // 渲染前置处理，初始化项目 schema 和资产包为渲染模块所需的 schema prop 和 components prop\n    const packages = JSON.parse(window.localStorage.getItem('packages') || '');\n    const projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || '');\n    const { componentsMap: componentsMapArray, componentsTree } = projectSchema;\n    const componentsMap: any = {};\n    componentsMapArray.forEach((component: any) => {\n      componentsMap[component.componentName] = component;\n    });\n    const schema = componentsTree[0];\n\n    const libraryMap = {};\n    const libraryAsset = [];\n    packages.forEach(({ package: _package, library, urls, renderUrls }) => {\n      libraryMap[_package] = library;\n      if (renderUrls) {\n        libraryAsset.push(renderUrls);\n      } else if (urls) {\n        libraryAsset.push(urls);\n      }\n    });\n\n    const vendors = [assetBundle(libraryAsset, AssetLevel.Library)];\n\n    const assetLoader = new AssetLoader();\n    await assetLoader.load(libraryAsset);\n    const components = await injectComponents(buildComponents(libraryMap, componentsMap));\n\n    setData({\n      schema,\n      components,\n    });\n  }\n\n  const { schema, components } = data;\n\n  if (!schema || !components) {\n    init();\n    return <Loading fullScreen />;\n  }\n\n  return (\n    <div className=\"lowcode-plugin-sample-preview\">\n      <ReactRenderer\n        className=\"lowcode-plugin-sample-preview-content\"\n        schema={schema}\n        components={components}\n      />\n    </div>\n  );\n};\n\nReactDOM.render(<SamplePreview />, document.getElementById('ice-container'));\n\n```\n### 国际化示例\n```typescript\nclass Demo extends PureComponent {\n  static displayName = 'renderer-demo';\n  render() {\n    return (\n      <div className=\"demo\">\n        <ReactRenderer\n          key={schema.fileName}\n          schema={schema}\n          components={components}\n          appHelper={{\n            utils,\n            constants\n          }}\n          locale=\"zh-CN\"\n          messages={{\n            \"hello\": \"你好\",\n            \"china\": \"中国\"\n          }}\n        />\n      </div>\n    );\n  }\n}\n```\n\n## API\n\n| 参数 | 说明 | 类型 | 必选 |\n| --- | --- | --- | --- |\n| schema | 符合[搭建协议](https://lowcode-engine.cn/lowcode)的数据 | Object | 是 |\n| components | 组件依赖的实例 | Object | 是 |\n| componentsMap | 组件的配置信息 | Object | 否 |\n| appHelper | 渲染模块全局上下文 | Object | 否 |\n| designMode | 设计模式，可选值：extend、border、preview | String | 否 |\n| suspended | 是否挂起 | Boolean | 否 |\n| onCompGetRef | 组件 ref 回调（schema, ref）=> {} | Function | 否 |\n| onCompGetCtx | 组件 ctx 更新回调 (schema, ctx) => {} | Function | 否 |\n| rendererName | 渲染类型，标识当前模块是以什么类型进行渲染的 | string | 否 |\n| customCreateElement | 自定义创建 element 的钩子\n(Component, props, children) => {} | Function | 否 |\n| notFoundComponent | 当组件找不到时，可以通过这个参数自定义展示文案。 | Component | 否 |\n| thisRequiredInJSE | 为 true 的情况下 JSExpression 仅支持通过 this 来访问。假如需要兼容原来的 'state.xxx'，则设置为 false，推荐使用 true。 | Boolean | 否 |\n| locale | 国际化语言类型 | string | 否 |\n| messages | 国际化语言对象 | Object | 否 |\n\n\n### schema\n\n搭建基础协议数据，渲染模块将基于 schema 中的内容进行实时渲染。\n\n### messages\n国际化内容，需要配合 locale 使用\nmessages 格式示例：\n```typescript\n{\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n}\n```\n\n### locale\n当前语言类型\n示例：'zh-CN' | 'en-US'\n\n### components\n\n渲染模块渲染页面需要用到的组件依赖的实例，`components` 对象中的 Key 需要和搭建 schema 中的`componentName` 字段对应。\n\n### componentsMap\n\n> 在生产环境下不需要设置。\n\n\n配置规范参见[《低代码引擎搭建协议规范》](https://lowcode-engine.cn/lowcode)，主要在搭建场景中使用，用于提升用户搭建体验。\n\n- 属性配置校验：用户可以配置组件特定属性的 `propTypes`，在搭建场景中用户输入的属性值不满足 `propType` 配置时，渲染模块会将当前属性设置为 `undefined`，避免组件抛错导致编辑器崩溃；\n- `isContainer` 标记：当组件被设置为容器组件且当前容器组件内没有其他组件时，用户可以通过拖拽方式将组件直接添加到容器组件内部；\n- `parentRule` 校验：当用户使用的组件未出现在组件配置的 `parentRule` 组件内部时，渲染模块会使用 `visualDom` 组件进行占位，避免组件抛错的同时在下钻编辑场景也能够不阻塞用户配置，典型的场景如`Step.Item`、`Table.Column`、`Tab.Item` 等等。\n\n### appHelper\n\nappHelper 主要用于设置渲染模块的全局上下文，目前 appHelper 支持设置以下上下文：\n\n- `utils`：全局公共函数\n- `constants`：全局常量\n- `location`：react-router 的 `location` 实例\n- `history`：react-router 的 `history` 实例\n\n设置了 appHelper 以后，上下文会直接挂载到容器组件的 this 上，用户可以在搭建协议中的 function 及变量表达式场景使用上下文，具体使用方式如下所示：\n**schema：**\n\n```javascript\nexport default {\n  \"componentName\": \"Page\",\n  \"fileName\": \"test\",\n  \"props\": {},\n  \"children\": [{\n    \"componentName\": \"Div\",\n    \"props\": {},\n    \"children\": [{\n      \"componentName\": \"Text\",\n      \"props\": {\n        \"text\": {\n        \t\"type\": \"JSExpression\",\n          \"value\": \"this.location.pathname\"\n        }\n      }\n    }, {\n      \"componentName\": \"Button\",\n      \"props\": {\n        \"type\": \"primary\",\n        \"style\": {\n          \"marginLeft\": 10\n        },\n        \"onClick\": {\n        \t\"type\": \"JSExpression\",\n          \"value\": \"function onClick(e) { this.utils.xxx(this.constants.yyy);}\"\n        }\n      },\n      \"children\": \"click me\"\n    }]\n  }]\n}\n```\n\n```typescript\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport ReactDOM from 'react-dom';\nimport { Button } from '@alifd/next';\nimport schema from './schema'\n\nconst components = {\n  Button,\n};\n\nReactDOM.render((\n  <ReactRenderer\n    schema={schema}\n    components={components}\n\t\tappHelper={{\n\t\t\tutils: {\n        xxx: () => {}\n      }\n    }}\n  />\n), document.getElementById('root'));\n```\n### designMode\n\n> 在生产环境下不需要设置。\n\n\ndesignMode 属性主要在搭建场景中使用，主要有以下作用：\n\n- 当 `designMode` 改变时，触发当前 schema 中所有组件重新渲染\n- 当 `designMode` 设置为 `design` 时，渲染模块会为 `Dialog`、`Overlay` 等初始状态无 dom 渲染的组件外层包裹一层 div，使其在画布中能够展示边框供用户选中\n\n### suspended\n\n渲染模块是否挂起，当设置为 `true` 时，渲染模块最外层容器的 `shouldComponentUpdate`将始终返回 false，在下钻编辑或者多引擎渲染的场景会用到该参数。\n\n### onCompGetRef\n\n组件 ref 的回调，在搭建场景下编排模块可以根据该回调获取组件实例并实现生命周期注入或者组件 DOM 操作等功能，回调函数主要包含两个参数：\n\n- `schema`：当前组件的 schema 模型结构\n- `ref`：当前组件的 ref 实例\n\n### onCompGetCtx\n组件 ctx 更新的回调，在组件每次 render 渲染周期我们都会为组件构造新的上下文环境，因此该回调函数会在组件每次 render 过程中触发，主要包含两个参数：\n\n- `schema`：当前组件的 schema 模型结构\n- `ctx`：当前组件的上下文信息，主要包含以下内容：\n   - `page`：当前页面容器实例\n   - `this`: 当前组件所属的容器组件实例\n   - `item`/`index`: 循环上下文（属性 key 可以根据 loopArgs 进行定制）\n   - `form`: 表单上下文\n\n### rendererName\n渲染类型，标识当前模块是以什么类型进行渲染的\n\n- `LowCodeRenderer`: 低代码组件\n- `PageRenderer`: 页面\n\n### customCreateElement\n自定义创建 element 的钩子，用于在渲染前后对组件进行一些处理，包括但不限于增加 props、删除部分 props。主要包含三个参数：\n\n- `Component`：要渲染的组件\n- `props`：要渲染的组件的 props\n- `children`：要渲染的组件的子元素\n\n### thisRequiredInJSE\n> 版本 >= 1.0.11\n\n默认值：true\n为 true 的情况下 JSExpression 仅支持通过 this 来访问。假如需要兼容原来的 'state.xxx'，则设置为 false，推荐使用 true。\n"
  },
  {
    "path": "docs/docs/guide/quickStart/_category_.json",
    "content": "{\n  \"label\": \"入门\",\n  \"position\": 0,\n  \"collapsed\": false,\n  \"collapsible\": true\n}\n"
  },
  {
    "path": "docs/docs/guide/quickStart/demo.md",
    "content": "---\ntitle: 试用低代码引擎 Demo\nsidebar_position: 2\n---\n## 访问地址\n\n低代码引擎的 Demo 可以通过如下永久链接访问到：\n\n[设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html)\n\n> 注意我们会经常更新 demo，所以您可以通过上述链接得到最新版地址。\n\n\n## 低代码引擎 Demo 功能概览\n\n我们可以从 Demo 的项目中看到页面中有很多的区块：\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01vlxdTD28c4JZcebbf_!!6000000007952-2-tps-3840-2160.png)\n\n它主要包含这些功能点：\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01QITHRY1sQaWzlvJv9_!!6000000005761-2-tps-3840-2160.png)\n\n### 顶部：操作区\n\n- 右侧：撤回和重做、保存到本地、重置页面、预览、异步加载资源\n### 左侧：面板与操作区\n- 大纲面板：可以调整页面内的组件树结构\n- 物料面板：可以查找组件，并在此拖动组件到编辑器画布中\n- 源码面板：可以编辑页面级别的 JavaScript 代码和 CSS 配置\n- 提交 Issue：可以给引擎开发提 bug\n- Schema 编辑：可以编辑页面的底层数据\n- 中英文切换：可以切换编辑器的语言\n\n### 中部：可视化页面编辑画布区域\n- 点击组件在右侧面板中能够显示出对应组件的属性配置选项\n- 拖拽修改组件的排列顺序\n- 将组件拖拽到容器类型的组件中\n- 复制组件：点击组件右上角的复制按钮\n- 删除组件：点击组件右上角的 X 或者直接使用 `Delete` 键\n\n### 右侧：组件级别配置\n- 选中的组件：从页面开始一直到当前选中的组件位置，点击对应的名称可以切换到对应的组件上\n- 选中组件的配置：当前组件的大类目选项，根据组件类型不同，包含如下子类目：\n  - 属性：组件的基础属性值设置\n  - 样式：组件的样式配置\n  - 事件：绑定组件对外暴露的事件\n  - 高级：循环、条件渲染与 key 设置\n\n## 深入使用低代码引擎 Demo\n\n我们在低代码引擎 Demo 中直接内置了产品使用文档，对常见场景中的使用进行了向导，它的入口如下：\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01YU2LYS29YEbuLTtLL_!!6000000008079-2-tps-3070-1650.png)\n\n如果暂时没有看到对应的产品使用文档，可以通过此永久链接直接访问：[https://lowcode-engine.cn/site/docs/demoUsage/intro](https://lowcode-engine.cn/site/docs/demoUsage/intro)\n"
  },
  {
    "path": "docs/docs/guide/quickStart/intro.md",
    "content": "---\ntitle: 简介\nsidebar_position: 1\n---\n\n# 阿里低代码引擎简介\n\n## 低代码介绍\n\n零代码、低代码的概念在整个全球行业内已经流行了很长一段时间。通常意义上的低代码定义会有三个关键点：\n\n1. 一个用于生产软件的可视化编辑器\n2. 中间包含了一些用于组装的物料，可以通过编排、组合和配置它们以生成丰富的功能或表现\n3. 最后的实施结果是成本降低\n\n通常情况下低代码平台会具备以下的几个能力：\n\n- **可视化页面搭建**，通过简单的拖拽完成应用页面开发，对前端技能没有要求或不需要特别专业的了解；\n- **可视化模型设计**，与业务相关的数据存储变得更容易理解，甚至大多数简单场景可以做到表单即模型，模型字段的类型更加业务化；\n- **可视化流程设计**，不管是业务流程还是审批流程，都可以通过简单的点线连接来进行配置；\n- **可视化报表及数据分析**，BI 数据分析能力成为标配，随时随地通过拖拽选择来定义自定义分析报表；\n- **可视化服务与数据开放、集成**，具备与其他系统互联互通的配置；\n- **权限、角色设置标准化和业务化**，通过策略规则配置来将数据、操作的权限进行精细化管理；\n- **无需关心服务器、数据库等底层运维、计算设施设备、网络等等复杂技术概念**，具备安全、性能的统一解决方案，开发者只需要专注于业务本身；\n\n有了上面这些，你会发现即使是个技术小白，只要你了解业务，就能不受束缚的完成大多数业务应用的搭建。但低代码本身也不仅仅是为技术小白准备的。在实践中，低代码因为通过组件化、模块化的思路让业务的抽象更加容易，而且在扩展及配置化上带来了更加新鲜的模式探索，技术人员的架构设计成本和实施成本也就降了很多。\n\n市面上常见的低代码产品[可以看 Golden 的梳理](https://golden.com/wiki/No-code_%2F_low-code_development-NMGMEA6)。\n\n## 低代码引擎介绍\n\n**低代码引擎是一款为低代码平台开发者提供的，具备强大定制扩展能力的低代码设计器研发框架。**\n\n下面简单描述定义中的子部分：\n\n**低代码设计器**\n现如今低代码平台越来越多，而每一个低代码平台中都会有的一个能力就是搭建和配置页面、模块的页面，这个页面我们称为设计器。例如，下图是中后台低代码平台的设计器。\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01sXuwkK1j8sg4S53Dx_!!6000000004504-2-tps-1682-969.png)\n设计器承载着低代码平台的核心功能，包括入料、编排、组件配置、画布渲染等等。由于其功能多，打磨精细难，也是低代码平台建设最耗时的地方。\n\n**定制扩展能力**\n\n什么是扩展能力呢，一方面我们可以快速拥有一份标准的低代码设计器，另外一方面如果有业务独特的功能需要，我们可以不用看它的源码、不用关心其实现，可以使用 API、插件等方式快速完成能力的开发。\n而低代码引擎对于设计器的扩展能力支持基本上覆盖了低代码设计器的所有功能点。下图是针对标准的设计器提供了扩展功能的区域。\n![](https://img.alicdn.com/imgextra/i1/O1CN01ZVgAE31wltQ4BVnCe_!!6000000006349-2-tps-3838-1914.png)\n**低代码设计器研发框架**\n\n低代码引擎的核心是设计器，通过扩展、周边生态等可以产出各式各样的设计器。它不是一套可以适合所有人的低代码平台，而是帮助低代码平台的开发者，快速生产低代码平台的工具。\n\n## 寻找适合您的低代码解决方案\n\n帮助用户根据个人或企业需求选择合适的低代码产品。\n\n| 特性/产品        | 低代码引擎                               | Lab平台                                  | UIPaaS                                      |\n|-----------------|-----------------------------------------|-----------------------------------------|--------------------------------------------|\n| **适用用户**    | 前端开发者                               | 需要快速搭建应用/页面的用户              | 企业用户，需要大规模部署低代码解决方案的组织 |\n| **产品特点**    | 设计器研发框架，适合定制开发            | 低代码平台, 可视化操作界面，易于上手                | 低代码平台孵化器，企业级功能                |\n| **使用场景**    | 定制和开发低代码平台的设计器部分        | 通过可视化, 快速开发应用或页面                  | 帮助具有一定规模软件研发团队的的企业低成本定制低代码平台        |\n| **产品关系**    | 开源产品                                 | 基于UIPaaS技术实现, 展示了UIPaaS的部分能力                      | 提供完整的低代码平台解决方案，商业产品                |\n| **收费情况**    | 免费                                     | 可免费使用（有额度限制），不提供私有化部署售卖 | 仅提供私有化部署售卖                        |\n| **官方网站**    | [低代码引擎官网](https://lowcode-engine.cn/) | [Lab平台官网](https://lab.lowcode-engine.cn/) | [UIPaaS官网](https://uipaas.net/)          |\n\n*注：请根据您的具体需求和条件选择合适的产品。如需更详细的信息，请访问各产品的官方网站。*\n"
  },
  {
    "path": "docs/docs/guide/quickStart/start.md",
    "content": "---\nsidebar_position: 3\ntitle: 快速开始\n---\n\n## 前置知识\n\n我们假定你已经对 HTML 和 JavaScript 都比较熟悉了。即便你之前使用其他编程语言，你也可以跟上这篇教程的。除此之外，我们假定你也已经熟悉了一些编程的概念，例如，函数、对象、数组，以及 class 的一些内容。\n\n如果你想回顾一下 JavaScript，你可以阅读[这篇教程](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript)。注意，我们也用到了一些 ES6（较新的 JavaScript 版本）的特性。在这篇教程里，我们主要使用了[箭头函数（arrow functions）](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions)、[class](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes)、[let](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let) 语句和 [const](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/const) 语句。你可以使用 [Babel REPL](https://babeljs.io/repl/#?presets=react&code_lz=MYewdgzgLgBApgGzgWzmWBeGAeAFgRgD4AJRBEAGhgHcQAnBAEwEJsB6AwgbgChRJY_KAEMAlmDh0YWRiGABXVOgB0AczhQAokiVQAQgE8AkowAUAcjogQUcwEpeAJTjDgUACIB5ALLK6aRklTRBQ0KCohMQk6Bx4gA) 在线预览 ES6 的编译结果。\n\n## 环境准备\n\n### WSL（Windows 电脑）\n\nWindow 环境需要使用 WSL 在 windows 下进行低代码引擎相关的开发。安装教程 ➡️ [WSL 安装教程](https://docs.microsoft.com/zh-cn/windows/wsl/install)。<br />**对于 Window 环境来说，之后所有需要执行命令的操作都是在 WSL 终端执行的。**\n\n### Node\n\nnode 版本推荐 16.18.0。\n\n#### 查看 Node 版本\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01oCZKNz290LIu8YUTk_!!6000000008005-2-tps-238-70.png)\n\n#### 通过 n 来管理 node 版本\n\n可以安装 [n](https://www.npmjs.com/package/n) 来管理和变更 node 版本。\n\n##### 安装 n\n\n```bash\nnpm install -g n\n```\n\n##### 变更 node 版本\n\n```bash\nn 14.17.0\n```\n\n### React\n\n低代码引擎的扩展能力都是基于 React 来研发的，在继续阅读之前最好有一定的 React 基础，React 学习教程 ➡️ [React 快速开始教程](https://zh-hans.reactjs.org/docs/getting-started.html)。\n\n### 下载 Demo\n\n可以前往 github（<https://github.com/alibaba/lowcode-demo>）将 DEMO 下载到本地。\n\n#### git clone\n\n##### HTTPS\n\n需要使用到 git 工具\n\n```bash\ngit clone https://github.com/alibaba/lowcode-demo.git\n```\n\n##### SSH\n\n需要配置 SSH key，如果没有配置可以\n\n```bash\ngit clone git@github.com:alibaba/lowcode-demo.git\n```\n\n#### 下载 Zip 包\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01iYC7E11phaNwLFUrN_!!6000000005392-2-tps-3584-1794.png)\n\n### 选择一个 demo 项目\n\n在 以 `demo-general` 为例：\n\n```bash\ncd demo-general\n```\n\n### 安装依赖\n\n在 `lowcode-demo/demo-general` 目录下执行：\n\n```bash\nnpm install\n```\n\n### 启动 demo\n\n在 `lowcode-demo/demo-general` 目录下执行：\n\n```bash\nnpm run start\n```\n\n之后就可以通过 [http://localhost:5556/](http://localhost:5556/) 来访问我们的 DEMO 了。\n\n## 认识 Demo\n\n我们的 Demo 是一个**低代码平台的设计器**。它是一个低代码平台中最重要的一环，用户可以在这里通过拖拽、配置、写代码等等来完成一个页面的开发。由于用户的人群不同、场景不同、诉求不同等等，这个页面的功能就会有所差异。\n\n这里记住**设计器**这个词，它描述的就是下面的这个页面，后面我们会经常看到它。\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN014nYXgF20pKrQIG2zV_!!6000000006898-2-tps-3584-1808.png)\n\n### 场景介绍\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01nnP60l1dqUhUiNSx6_!!6000000003787-2-tps-2852-1156.png)\n\nDemo 根据**不同的设计器所需要的物料不同**，分为了下面的 8 个场景：\n\n- 综合场景\n- 基础 fusion 组件\n- 基础 fusion 组件 + 单自定义组件\n- 基础 antd 组件\n- 自定义初始化引擎\n- 扩展节点操作项\n- 基于 next 实现的高级表单低代码物料\n- antd 高级组件 + formily 表单组件\n\n可以点开不同的场景，看看他们使用的物料。\n![](https://img.alicdn.com/imgextra/i1/O1CN01EU2jRN1wUwlal17WK_!!6000000006312-2-tps-3110-1974.png)\n\n### 目录介绍\n\n仓库下每个 demo-xxx-xxx 目录都是一个可独立运行的 demo 工程，分别对应到刚刚介绍的场景。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01ztxv5Y1mJozBsLdni_!!6000000004934-2-tps-696-958.png)\n\n不同场景的目录结构实际上都是类似的，这里我们主要介绍一下综合场景的目录结构即可。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01A50oW522S5zg2eDUH_!!6000000007118-2-tps-732-1384.png)\n\n介绍下其中主要的内容\n\n- 设计器入口文件 `src/index.ts` 这个文件做了下述几个事情：\n  - 通过 plugins.register 注册各种插件，包括官方插件 (已发布 npm 包形式的插件) 和 `plugins` 目录下内置的示例插件\n  - 通过 init 初始化低代码设计器\n- plugins 目录，存放的都是示例插件，方便用户从中看到一个插件是如何实现的\n- services 目录，模拟数据请求、提供默认 schema、默认资产包等，此目录下内容在真实项目中应替换成真实的与服务端交互的服务。\n- 预览页面入口文件 `preview.tsx`\n\n剩下的各位看官可以通过源码来进一步了解。\n\n做了这些事情之后，我们的低代码设计器就已经有了基本的能力了。也就是最开始我们看到的这样。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01YJVcOd1PiL1am6bz2_!!6000000001874-2-tps-3248-1970.png)\n\n接下来我们就根据我们自己的诉求通过对设计器进行扩展，改动成我们需要的设计器功能。\n\n## 开发一个插件\n\n### 方式 1：在 DEMO 中直接新增插件\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01pXpSRs1QvRyut2EE3_!!6000000002038-2-tps-718-1144.png)\n\n可以在 demo/sample-plugins 直接新增插件，这里我新增的插件目录是 plugin-demo。并且新增了 index.tsx 文件，将下面的代码粘贴到 index.tsx 中。\n\n```javascript\nimport * as React from 'react';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nconst LowcodePluginPluginDemo = (ctx: IPublicModelPluginContext) => {\n  return {\n    // 插件对外暴露的数据和方法\n    exports() {\n      return {\n        data: '你可以把插件的数据这样对外暴露',\n        func: () => {\n          console.log('方法也是一样');\n        },\n      };\n    },\n    // 插件的初始化函数，在引擎初始化之后会立刻调用\n    init() {\n      // 你可以拿到其他插件暴露的方法和属性\n      // const { data, func } = ctx.plugins.pluginA;\n      // func();\n\n      // console.log(options.name);\n\n      // 往引擎增加面板\n      ctx.skeleton.add({\n        area: 'leftArea',\n        name: 'LowcodePluginPluginDemoPane',\n        type: 'PanelDock',\n        props: {\n          description: 'Demo',\n        },\n        content: <div>这是一个 Demo 面板</div>,\n      });\n\n      ctx.logger.log('打个日志');\n    },\n  };\n};\n\n// 插件名，注册环境下唯一\nLowcodePluginPluginDemo.pluginName = 'LowcodePluginPluginDemo';\nLowcodePluginPluginDemo.meta = {\n  // 依赖的插件（插件名数组）\n  dependencies: [],\n  engines: {\n    lowcodeEngine: '^1.0.0', // 插件需要配合 ^1.0.0 的引擎才可运行\n  },\n};\n\nexport default LowcodePluginPluginDemo;\n```\n\n在 src/index.ts 中新增下面代码\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01pNTr4N1kldoYZRzgI_!!6000000004724-2-tps-1976-1250.png)\n\n这样在我们的设计器中就新增了一个 Demo 面板。\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01wtPIOV1TQiFLz5Vkf_!!6000000002377-2-tps-3584-1806.png)\n\n### 方式 2：在新的仓库下开发插件\n\n初始化\n\n```bash\nnpm init @alilc/element your-plugin-name\n```\n\n选择设计器插件（plugin）\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01sA6sYW1tijqVeQCuq_!!6000000005936-2-tps-730-214.png)\n\n根据操作完善信息\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01BzM1Jb1RcxbiJ0tJi_!!6000000002133-2-tps-866-218.png)\n\n插件项目就初始化完成了\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01iVIAXD1XVWsOdKttI_!!6000000002929-2-tps-3584-2020.png)\n\n在插件项目下安装依赖\n\n```bash\nnpm install\n```\n\n启动项目\n\n```bash\nnpm run start\n```\n\n调试项目\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01A4vPqC1xbeAqNxBRM_!!6000000006462-2-tps-3584-1936.png)\n\n在 Demo 中调试项目\n\n在 build.json 下面新增 \"inject\": true，就可以在 [https://lowcode-engine.cn/demo/demo-general/index.html?debug](https://lowcode-engine.cn/demo/demo-general/index.html?debug) 页面下进行调试了。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01uqSmrX1oqupxeGH1m_!!6000000005277-2-tps-3584-2020.png)\n\n## 开发一个自定义物料\n\n### 初始化物料\n\n```bash\nnpm init @alilc/element your-material-demo\n```\n\n选择组件/物料栏\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN01qVJQvG1Yhj2PJhhvk_!!6000000003091-2-tps-824-208.png)\n\n配置其他信息\n\n![image.png](https://img.alicdn.com/imgextra/i3/O1CN017fFT8O1IVmrLYg87F_!!6000000000899-2-tps-800-248.png)\n\n这样我们就初始化好了一个 React 物料。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN01SU2xn91TZPlzcARVI_!!6000000002396-2-tps-3584-2020.png)\n\n### 启动并调试物料\n\n#### 安装依赖\n\n```bash\nnpm i\n```\n\n#### 启动\n\n```bash\nnpm run lowcode:dev\n```\n\n我们就可以通过 [http://localhost:3333/](http://localhost:3333/) 看到我们的研发的物料了。\n\n![image.png](https://img.alicdn.com/imgextra/i4/O1CN01JqoHqc1z7zlSWFYJD_!!6000000006668-2-tps-3584-1790.png)\n\n#### 在 Demo 中调试\n\n```bash\nnpm i @alilc/build-plugin-alt\n```\n\n修改 build.lowcode.js\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01K7u7ci1KCfYlBj2yf_!!6000000001128-2-tps-1388-1046.png)\n\n如图，新增如下代码\n\n```javascript\n[\n  '@alilc/build-plugin-alt',\n  {\n    type: 'component',\n    inject: true,\n    library,\n    // 配置要打开的页面，在注入调试模式下，不配置此项的话不会打开浏览器\n    // 支持直接使用官方 demo 项目：https://lowcode-engine.cn/demo/index.html\n    openUrl: 'https://lowcode-engine.cn/demo/index.html?debug',\n  },\n],\n```\n\n我们重新启动项目，就可以在 Demo 中找到我们的自定义组件。\n\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN0166WywE26Lv7NuJMus_!!6000000007646-2-tps-3584-1812.png)\n\n### 发布\n\n首先进行构建\n\n```bash\nnpm run lowcode:build\n```\n\n发布组件\n\n```bash\nnpm publish\n```\n\n这里我发布的组件是 [my-material-demo](https://www.npmjs.com/package/my-material-demo)。在发布之后我们就会有两个重要的文件：\n\n- 低代码描述：[https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js](https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js)\n- 组件代码：[https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js](https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js)\n\n我们也可以从 [https://unpkg.com/my-material-demo@0.1.0/build/lowcode/assets-prod.json](https://unpkg.com/my-material-demo@0.1.0/build/lowcode/assets-prod.json) 找到我们的资产包描述。\n\n```bash\n{\n  \"packages\": [\n    {\n      \"package\": \"my-material-demo\",\n      \"version\": \"0.1.0\",\n      \"library\": \"BizComp\",\n      \"urls\": [\n        \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js\",\n        \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.css\"\n      ],\n      \"editUrls\": [\n        \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/view.js\",\n        \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/view.css\"\n      ],\n      \"advancedUrls\": {\n        \"default\": [\n          \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js\",\n          \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.css\"\n        ]\n      },\n      \"advancedEditUrls\": {}\n    }\n  ],\n  \"components\": [\n    {\n      \"exportName\": \"MyMaterialDemoMeta\",\n      \"npm\": {\n        \"package\": \"my-material-demo\",\n        \"version\": \"0.1.0\"\n      },\n      \"url\": \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js\",\n      \"urls\": {\n        \"default\": \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js\"\n      },\n      \"advancedUrls\": {\n        \"default\": [\n          \"https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js\"\n        ]\n      }\n    }\n  ],\n}\n```\n\n### 使用\n\n我们将刚刚发布的组件的 assets-prod.json 的内容放到 demo 的 src/universal/assets.json 中。\n\n> 最好放到最后，防止因为资源加载顺序问题导致出现报错。\n\n如图，新增 packages 配置\n![image.png](https://img.alicdn.com/imgextra/i1/O1CN018dnIB91XHmzeTrq3n_!!6000000002899-2-tps-3584-2020.png)\n\n如图，新增 components 配置\n\n![image.png](https://img.alicdn.com/imgextra/i2/O1CN01UNp89s1vQXKyfsFaL_!!6000000006167-2-tps-3584-2020.png)\n\n这时候再启动 DEMO 项目，就会有新的低代码物料了。接下来就按照你们的需求，继续扩展物料吧。\n\n## 总结\n\n这里只是简单的介绍了一些低代码引擎的基础能力，带大家简单的对低代码 DEMO 进行扩展，定制一些新的功能。低代码引擎的能力还有很多很多，可以继续去探索更多的功能。\n"
  },
  {
    "path": "docs/docs/participate/code-specification.md",
    "content": "---\ntitle: 编码规约\nsidebar_position: 5\n---\n\n编码规约\n---\n\n### 命名\n\n - 使用 `PascalCase` 为类型命名\n - 使用 `I` 做为接口名前缀\n - 使用 `PascalCase` 为枚举值命名\n - 使用 `camelCase` 为函数命名\n - 使用 `camelCase` 为属性或本地变量命名\n - 不要为私有属性名添加 `_` 前缀\n - 尽可能使用完整的单词拼写命名\n - 文件夹/文件命名统一使用小写 `get-custom-data.ts`\n\n### 组件\n\n - 一个文件对应一个组件或类\n\n### 类型\n\n - 不要随意导出类型/函数，除非你要在不同的组件中共享它\n - 不要在全局命名空间内定义类型/值\n - 共享的类型应该在 `types.ts` 里定义\n - 在一个文件里，类型定义应该出现在顶部\n - interface 和 type 很类似，原则上能用 interface 实现，就用 interface , 如果不能才用 type\n\n### 注释\n\n - 为函数，接口，枚举类型和类使用 JSDoc 风格的注释\n\n### 字符串\n\n - 使用单引号 `''`\n\n### 单元测试\n\n - 单元测试文件根据文件目录结构来放置\n"
  },
  {
    "path": "docs/docs/participate/flow.md",
    "content": "---\ntitle: 研发协作流程\nsidebar_position: 2\n---\n## 代码风格\n引擎项目配置了 eslint 和 stylelint，在每次 git commit 前都会检查代码风格，假如有报错，请修改后再提交。（**严禁 -n 提交，-n 也逃脱不了 github workflow 的 lint 检查，放弃吧，骚年~**）\n\n## 测试机制\n每次提交代码前，务必本地跑一次单元测试，通过后再提交 MR。\n\n假如涉及新的功能，需要**补充相应的单元测试**，目前引擎核心模块的单测覆盖率都在 80%+，假如降低了覆盖率，将会不予以通过。\n\n跑单测流程：\n\n1. 项目根目录下执行 npm run build\n2. 只改了一个包，比如 designer，则在 designer 目录下，执行 npm test\n3. （or）改了多个包，则在根目录下执行 npm test\n## commit 风格\n几点要求：\n\n1. commit message 格式遵循 [ConvensionalCommits](https://www.conventionalcommits.org/en/v1.0.0/#summary)\n\n   <img src=\"https://img.alicdn.com/imgextra/i3/O1CN01M9UzVM1iqYpyxECdV_!!6000000004464-2-tps-2070-594.png\" width=\"700\"/>\n2. 请按照一个 bugfix / feature 对应一个 commit，假如不是，请 rebase 后再提交 MR，不要一堆无用的、试验性的 commit。\n\n好处：从引擎的整体 commit 历史来看，会很清晰，**每个 commit 完成一件确定的事，changelog 也能自动生成**。另外，假如因为某个 commit 导致了 bug，也很容易通过 rebase drop 等方式快速修复。\n\n## 分支用途\n\n- main 分支，最稳定的分支，跟 npm latest 包的内容保持一致\n- develop 分支，开发分支，拥有最新的、已经验证过的 feature / bugfix，Pull Request 的**目标合入分支**\n- release 分支\n   - 正式发布分支，命名规则为 release/x.y.z，一般从 develop 拉出来进行发布，x.y.z 为待发布的版本号\n   - beta 发布分支，命名规则为 release/x.y.z-beta(\\.\\d+)?，可以快速验证修改，发布 npm beta 版本。\n\n验证通过后，因为 beta 发布分支上会存在无用的 commit（比如 lerna 修改 package.json 这种），所以不直接 PR 到 develop，而是从 develop 拉分支，从 beta 发布分支 cherry pick 有用的 commit 到新分支，然后 PR 到 develop。\n\n## 引擎发布机制\n\n日常迭代先从 develop 拉分支，然后自测、单测通过后，提交 PR 到 develop 分支，由发布负责人基于 develop 拉 release/1.0.z 分支~\n\n### 版本规划\n\n> 此处是理想节奏，实际情况可能会有调整\n\n- 日常迭代 2 周，一般月中或月底，发版日两天前发最后一个 beta 版本，原则上不接受新 pr，灰度 2 天后，发正式版。\n- 特殊情况紧急迭代随时发\n- 大 Feature 迭代，每年 2 - 4 次\n\n\n### 发布步骤\n> **发布需要权限，如果提 PR 之后着急发布可以**[**加入贡献者交流群**](../participate/#核心贡献者交流)**。**\n\n#### 发正式版\n步骤如下（以发布 1.0.0 版本为例）：\n\n1. git checkout develop\n   ```bash\n   git checkout develop\n   ```\n2. 创建 release 分支\n   ```bash\n   git checkout -b release/1.0.0\n   ```\n3. build\n   ```bash\n   npm run build\n   ```\n4. 发布到 npm\n   ```bash\n   npm run pub\n   ```\n5. 同步到 tnpm 源 & alifd CDN & uipaas CDN（此步骤将发布在 npm 源的包同步到阿里内网源，因为 alifd cdn 将依赖内网 npm 源）\n   ```bash\n   tnpm run sync\n   tnpm run syncOss\n   ```\n6. 更新[发布日志](https://github.com/alibaba/lowcode-engine/releases)\n7. 合并 release/x.x.x 到 main 分支\n8. 合并 main 分支到 develop 分支\n\n如果是发布 beta 版本，步骤如下（以发布 1.0.1 版本为例）：\n\n#### 发某 y 位版本首个 beta，如 1.1.0-beta.0\n1. 拉 develop 分支\n   ```bash\n   git checkout develop\n   ```\n   更新到最新（如需）\n   ```bash\n   git pull\n   ```\n2. 拉 release 分支，此处以 1.1.0 版本做示例\n   ```bash\n   git checkout -b release/1.1.0-beta\n   git push --set-upstream origin release/1.1.0-beta\n   ```\n3. build\n   ```bash\n   npm run build\n   ```\n4. 发布，此处需有 @alilc scope 发包权限\n   ```bash\n   npm run pub:preminor\n   ```\n5. 同步到 tnpm 源 & alifd CDN & uipaas CDN\n   ```bash\n   tnpm run sync\n   tnpm run syncOss\n   ```\n\n#### 发某 z 位版本首个 beta，如 1.0.1-beta.0\n1. 拉 develop 分支\n   ```bash\n   git checkout develop\n   ```\n   更新到最新（如需）\n   ```bash\n   git pull\n   ```\n2. 拉 release 分支，此处以 1.0.1 版本做示例\n   ```bash\n   git checkout -b release/1.0.1-beta\n   git push --set-upstream origin release/1.0.1-beta\n   ```\n3. build\n   ```bash\n   npm run build\n   ```\n4. 发布，此处需有 @alilc scope 发包权限\n   ```bash\n   npm run pub:prepatch\n   ```\n5. 同步到 tnpm 源 & alifd CDN & uipaas CDN\n   ```bash\n   tnpm run sync\n   tnpm run syncOss\n   ```\n\n#### 发某版本非首个 beta，如 1.0.1-beta.0 -> 1.0.1-beta.1\n1. 切换到 release 分支\n   ```bash\n   git checkout release/1.0.1-beta\n   ```\n2. 更新到 develop 分支最新代码\n   ```bash\n   git rebase origin/develop\n   ```\n3. build\n   ```bash\n   npm run build\n   ```\n4. 发布，此处需有 @alilc scope 发包权限 ***此处命令与发首个 beta 时有变化***\n   ```bash\n   npm run pub:prerelease\n   ```\n5. 同步到 tnpm 源 & alifd CDN & uipaas CDN\n   ```bash\n   tnpm run sync\n   tnpm run syncOss\n   ```\n\n\n\n## DEMO 发布机制\n1. **修改版本号**\n   手动修改 package.json 的版本号\n2. **build**\n   ```bash\n   npm run build\n   ```\n3. publish（此步骤需要 npm 发包权限）\n   ```bash\n   npm run pub\n   ```\n   如发 beta 版\n   ```bash\n   npm publish --tag beta\n   ```\n4. 同步到 tnpm 源 & alifd CDN & uipaas CDN\n   ```bash\n   tnpm run sync\n   tnpm run syncOss\n   ```\n\n**官网生效**\n需要在通过阿里内部系统更新 demo 版本\n"
  },
  {
    "path": "docs/docs/participate/index.md",
    "content": "---\ntitle: 参与贡献\nsidebar_position: 0\n---\n\n### 环境准备\n\n开发 LowcodeEngine 需要 Node.js 16+。\n\n推荐使用 nvm 管理 Node.js，避免权限问题的同时，还能够随时切换当前使用的 Node.js 的版本。\n\n### 贡献低代码引擎\n\n#### clone 项目\n\n```\ngit clone git@github.com:alibaba/lowcode-engine.git\ncd lowcode-engine\n```\n\n#### 安装依赖并构建\n\n```\nnpm install && npm run setup\n```\n\n#### 调试环境配置\n\n本质上是将 demo 页面引入的几个 js/css 代理到 engine 项目，可以使用趁手的代理工具，这里推荐 [XSwitch](https://chrome.google.com/webstore/detail/xswitch/idkjhjggpffolpidfkikidcokdkdaogg?hl=en-US)。\n\n本地开发代理规则如下：\n```json\n{\n  \"proxy\": [\n    [\n      \"https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js\",\n      \"http://localhost:5555/js/AliLowCodeEngine.js\"\n    ],\n    [\n      \"https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css\",\n      \"http://localhost:5555/css/AliLowCodeEngine.css\"\n    ],\n    [\n      \"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js\",\n      \"http://localhost:5555/js/ReactSimulatorRenderer.js\"\n    ],\n    [\n      \"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css\",\n      \"http://localhost:5555/css/ReactSimulatorRenderer.css\"\n    ]\n  ]\n}\n```\n\n#### 开发\n\n```\nnpm start\n```\n\n选择一个环境进行调试，例如[低代码引擎在线 DEMO](https://lowcode-engine.cn/demo/demo-general/index.html)\n\n开启代理之后，就可以进行开发调试了。\n\n\n### 贡献低代码引擎文档\n\n#### 开发文档\n\n在 lowcode-engine 目录下执行下面命令\n```\ncd docs\n\nnpm start\n```\n\n#### 维护方式\n- 官方文档通过 github 管理文档源，官网文档与[主仓库 develop 分支](https://github.com/alibaba/lowcode-engine/tree/develop/docs)保持同步。\n- 点击每篇文档下发的 `编辑此页` 可直接定位到 github 中位置。\n- 欢迎 PR，文档 PR 也会作为贡献者贡献，会用于贡献度统计。\n- **文档同步到官方网站由官方人员进行操作**，如有需要可以通过 issue 或 贡献者群与相关人员沟通。\n- 为了提供更好的阅读和使用体验，文档中的图片文件会定期转换成可信的 CDN 地址。\n\n#### 文档格式\n\n本项目文档参考[文档编写指南](https://github.com/sparanoid/chinese-copywriting-guidelines)。\n\n使用 vscode 进行编辑的朋友可以安装 vscode 插件 [huacnlee.autocorrect](https://github.com/huacnlee/autocorrect) 辅助文档 lint。\n\n\n### 贡献低代码引擎生态\n\n相关源码详见[NPM 包对应源码位置汇总](/site/docs/guide/appendix/npms)\n\n开发调试方式详见[低代码生态脚手架 & 调试机制](/site/docs/guide/expand/editor/cli)\n\n### 发布\n\nPR 被合并之后，我们会尽快发布相关的正式版本或者 beta 版本。\n\n### 加入 Contributor 群\n提交过 Bugfix 或 Feature 类 PR 的同学，如果有兴趣一起参与维护 LowcodeEngine，我们提供了一个核心贡献者交流群。\n\n1. 可以通过[填写问卷](https://survey.taobao.com/apps/zhiliao/4YEtu9gHF)的方式，参与到其中。\n2. 填写问卷后加微信号 `wxidvlalalalal` （注明 github id）我们会拉你到群里。\n\n如果你不知道可以贡献什么，可以到源码里搜 TODO 或 FIXME 找找。\n\n为了使你能够快速上手和熟悉贡献流程，我们这里有个列表 [good first issues](https://github.com/alibaba/lowcode-engine/issues?q=is:open+is:issue+label:%22good+first+issue%22)，里面有相对没那么笼统的漏洞，从这开始是个不错的选择。\n\n### PR 提交注意事项\n\n- lowcode-engine 仓库建议从 develop 创建分支，PR 指向 develop 分支。\n- 其他仓库从 main 分支创建分支，PR 指向 main 分支\n- 如果你修复了 bug 或者添加了代码，而这些内容需要测试，请添加测试！\n- 确保通过测试套件（yarn test）。\n- 请签订贡献者许可证协议（Contributor License Agreement）。\n   > 如已签署 CLA 仍被提示需要签署，[解决办法](/site/docs/faq/faq021)"
  },
  {
    "path": "docs/docs/participate/meet.md",
    "content": "---\ntitle: 开源社区例会\nsidebar_position: 0\n---\n\n## **简介**\n\n低代码引擎开源社区致力于共同推动低代码技术的发展和创新。本社区汇集了低代码技术领域的开发者、技术专家和行业观察者，通过定期的例会来交流思想、分享经验、讨论新技术，并探索低代码技术的未来发展方向。\n\n## 参与要求\n\n为了确保例会的质量和效果，我们建议以下人员参加：\n\n- **已参与低代码引擎贡献的成员**：那些对低代码引擎有实际贡献的社区成员。\n- **参考贡献指南**：可查阅[贡献指南](https://lowcode-engine.cn/site/docs/participate/)获取更多信息。\n- **提供过优秀建议的成员**：那些在过去为低代码引擎提供过有价值建议的成员。\n\n## **时间周期**\n\n- **周期性**：月例会\n\n### **特别说明**\n\n- 例会周期可根据成员反馈进行调整。如果讨论的议题较多，可增加例会频率；若议题较少，单次例会可能取消。若多次取消，可能会暂停例会。\n\n## **例会流程**\n\n### **准备阶段**\n\n- **定期确定议题**：会前一周确定下一次会议的议题。\n- **分发会议通知**：提前发送会议时间、议程和参与方式。\n\n### **会议阶段**\n\n- **开场和介绍**：简短开场和自我介绍，特别是新成员加入时。\n- **议题讨论**：按照议程进行议题讨论，每个议题分配一定时间，并留足够时间供讨论和提问。\n- **记录要点和决定**：记录讨论要点、决策和任何行动事项。\n\n### **后续阶段**\n\n- **分享会议纪要**：会后将会议纪要和行动计划分发给所有成员。\n- **执行和跟进**：根据会议中的讨论和决策执行相关任务，并在下次会议中进行跟进汇报。\n\n## **开源例会议题**\n\n开源例会议题包括但不限于：\n\n- **共建低代码行业发展**：探讨通过开源社区合作加速低代码行业发展。\n- **改进建议和反馈收集**：讨论社区成员对低代码引擎的使用体验和改进建议。\n- **前端技术与低代码的结合**：针对前端开发者，讨论将前端技术与低代码引擎结合的方式。\n- **低代码业务场景和经验分享**：邀请社区成员分享低代码引擎的实际应用经验。\n- **低代码技术原理介绍**：深入理解低代码引擎的技术原理和实现方式。\n- **低代码引擎的最新进展**：分享低代码引擎的最新进展，包括新版本发布和新功能实现等。\n- **低代码技术的未来展望**：讨论低代码技术的未来发展方向。\n- **最新低代码平台功能和趋势分析**：分享和讨论当前低代码平台的新功能、趋势和发展方向。"
  },
  {
    "path": "docs/docs/specs/assets-spec.md",
    "content": "---\ntitle: 《低代码引擎资产包协议规范》\nsidebar_position: 2\n---\n## 1 介绍\n\n### 1.1 本协议规范涉及的问题域\n\n- 定义本协议版本号规范\n- 定义本协议中每个子规范需要被支持的 Level\n- 定义本协议相关的领域名词\n- 定义低代码资产包协议版本号规范（A）\n- 定义低代码资产包协议组件及依赖资源描述规范（A）\n- 定义低代码资产包协议组件描述资源加载规范（A）\n- 定义低代码资产包协议组件在面板展示规范（AA）\n\n### 1.2 协议草案起草人\n\n- 撰写：金禅、璿玑、彼洋\n- 审阅：力皓、絮黎、光弘、戊子、潕量、游鹿\n\n### 1.3 版本号\n\n1.1.0\n\n### 1.4 协议版本号规范（A）\n\n本协议采用语义版本号，版本号格式为 `major.minor.patch` 的形式。\n\n- major 是大版本号：用于发布不向下兼容的协议格式修改\n- minor 是小版本号：用于发布向下兼容的协议功能新增\n- patch 是补丁号：用于发布向下兼容的协议问题修正\n\n### 1.5 协议中子规范 Level 定义\n\n| 规范等级 | 实现要求                                                     |\n| -------- | ------------------------------------------------------------ |\n| A        | 基础规范，低代码引擎核心层支持；                             |\n| AA       | 推荐规范，由低代码引擎官方插件、setter 支持。                |\n| AAA      | 参考规范，需由基于引擎的上层搭建平台支持，实现可参考该规范。 |\n\n### 1.6 名词术语\n\n- **资产包**: 低代码引擎加载资源的动态数据集合，主要包含组件及其依赖的资源、组件低代码描述、动态插件/设置器资源等。\n\n### 1.7 背景\n\n根据低代码引擎的实现，一个组件要在引擎上渲染和配置，需要提供组件的 umd 资源以及组件的`低代码描述`，并且组件通常都是以集合的形式被引擎消费的；除了组件之外，还有组件的依赖资源、引擎的动态插件/设置器等资源也需要注册到引擎中；因此我们定义了“低代码资产包”这个数据结构，来描述引擎所需加载的动态资源的集合。\n\n### 1.8 受众\n\n本协议适用于使用“低代码引擎”构建搭建平台的开发者，通过本协议的定义来进行资源的分类和加载。阅读及使用本协议，需要对低代码搭建平台的交互和实现有一定的了解，对前端开发相关技术栈的熟悉也会有帮助，协议中对通用的前端相关术语不会做进一步的解释说明。\n\n## 2 协议结构\n\n协议最顶层结构如下，包含 7 方面的描述内容：\n\n- version { String } 当前协议版本号\n- packages { Array } 低代码编辑器中加载的资源列表\n- components { Array } 所有组件的描述协议列表\n- sort { Object } 用于描述组件面板中的 tab 和 category\n- plugins { Array } 设计器插件描述协议列表\n- setters { Array } 设计器中设置器描述协议列表\n- extConfig { Object } 平台自定义扩展字段\n\n### 2.1 version (A)\n\n定义当前协议 schema 的版本号；\n\n| 根属性名称 | 类型   | 说明       | 变量支持 | 默认值 |\n| ---------- | ------ | ---------- | -------- | ------ |\n| version    | String | 协议版本号 | -        | 1.1.0  |\n\n### 2.2 packages (A)\n\n定义低代码编辑器中加载的资源列表，包含公共库和组件 (库) cdn 资源等；\n\n| 字段                 | 字段描述                                                        | 字段类型      | 规范等级 | 备注                                                                                                     |\n| -------------------- | --------------------------------------------------------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------- |\n| packages[].id?       | 资源唯一标识                                                    | String        | A        | 资源唯一标识，如果为空，则以 package 为唯一标识                                                          |\n| packages[].title?    | 资源标题                                                        | String        | A        | 资源标题                                                                                                 |\n| packages[].package   | npm 包名                                                        | String        | A        | 组件资源唯一标识                                                                                         |\n| packages[].version   | npm 包版本号                                                    | String        | A        | 组件资源版本号                                                                                           |\n| packages[].type      | 资源包类型                                                      | String        | AA       | 取值为: proCode（源码）、lowCode（低代码，默认为 proCode                                                 |\n| packages[].schema    | 低代码组件 schema 内容                                          | object        | AA       | 取值为: proCode（源码）、lowCode（低代码）                                                               |\n| packages[].deps      | 当前资源包的依赖资源的唯一标识列表                              | Array<String\\> | A        | 唯一标识为 id 或者 package 对应的值                                                                      |\n| packages[].library   | 作为全局变量引用时的名称，用来定义全局变量名                    | String        | A        | 低代码引擎通过该字段获取组件实例                                                                         |\n| packages[].editUrls  | 组件编辑态视图打包后的 CDN url 列表，包含 js 和 css             | Array<String\\> | A        | 低代码引擎编辑器会加载这些 url                                                                           |\n| packages[].urls      | 组件渲染态视图打包后的 CDN url 列表，包含 js 和 css             | Array<String\\> | AA       | 低代码引擎渲染模块会加载这些 url                                                                         |\n| packages[].advancedEditUrls | 组件多个编辑态视图打包后的 CDN url 列表集合，包含 js 和 css     | Object        | AAA      | 上层平台根据特定标识提取某个编辑态的资源，低代码引擎编辑器会加载这些资源，优先级高于 packages[].editUrls |\n| packages[].advancedUrls     | 组件多个端的渲染态视图打包后的 CDN url 列表集合，包含 js 和 css | Object        | AAA      | 上层平台根据特定标识提取某个渲染态的资源， 低代码引擎渲染模块会加载这些资源，优先级高于 packages[].urls  |\n| packages[].external  | 当前资源在作为其他资源的依赖，在其他依赖打包时时是否被排除了(同 webpack 中 external 概念)                            | Boolean       | AAA      | 某些资源会被单独提取出来，是其他依赖的前置依赖，根据这个字段决定是否提前加载该资源                       |\n| packages[].loadEnv   | 指定当前资源加载的环境                                          | Array<String\\> | AAA      | 主要用于指定 external 资源加载的环境，取值为 design(设计态)、runtime(预览态) 中的一个或多个               |\n| packages[].exportSourceId     | 标识当前 package 内容是从哪个 package 导出来的   | String | AAA       | 此时 urls 无效 |\n| packages[].exportSourceLibrary     | 标识当前 package 是从 window 上的哪个属性导出来的   | String | AAA       | exportSourceId 的优先级高于exportSourceLibrary ,此时 urls 无效 |\n| packages[].async     | 标识当前 package 资源加载在 window.library 上的是否是一个异步对象   | Boolean | A       | async 为 true 时，需要通过 await 才能拿到真正内容 |\n| packages[].exportMode     | 标识当前 package 从其他 package 的导出方式   | String | A       | 目前只支持 `\"functionCall\"`, exportMode等于 `\"functionCall\"` 时，当前package 的内容以函数的方式从其他 package 中导出，具体导出接口如: (library: string, packageName: string, isRuntime?: boolean) => any | Promise<any\\>, library 为当前 package 的 library, packageName 为当前的包名，返回值为当前 package 的导出内容  |\n\n描述举例：\n\n```json\n{\n  \"packages\": [\n    {\n      \"title\": \"fusion 组件库\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.23.0\",\n      \"urls\": [\n        \"https://g.alicdn.com/code/lib/alifd__next/1.23.18/next.min.css\",\n        \"https://g.alicdn.com/code/lib/alifd__next/1.23.18/next-with-locales.min.js\"\n      ],\n      \"library\": \"Next\"\n    },\n    {\n      \"title\": \"Fusion 精品组件库\",\n      \"package\": \"@alife/fusion-ui\",\n      \"version\": \"0.1.5\",\n      \"editUrls\": [\n        \"https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/build/lowcode/view.js\",\n        \"https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/build/lowcode/view.css\"\n      ],\n      \"urls\": [\n        \"https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/dist/FusionUI.js\",\n        \"https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/dist/FusionUI.css\"\n      ],\n      \"library\": \"FusionUI\"\n    },\n    {\n      \"title\": \"低代码组件 A\",\n      \"id\": \"lcc-a\",\n      \"version\": \"0.1.5\",\n      \"type\": \"lowCode\",\n      \"schema\": {\n        \"componentsMap\": [\n          {\n            \"package\": \"@ali/vc-text\",\n            \"componentName\": \"Text\",\n            \"version\": \"4.1.1\"\n          }\n        ],\n        \"utils\": [\n          {\n            \"name\": \"dataSource\",\n            \"type\": \"npm\",\n            \"content\": {\n              \"package\": \"@ali/vu-dataSource\",\n              \"exportName\": \"dataSource\",\n              \"version\": \"1.0.4\"\n            }\n          }\n        ],\n        \"componentsTree\": [\n          {\n            \"defaultProps\": {\n              \"content\": \"这是默认值\"\n            },\n            \"methods\": {\n              \"__initMethods__\": {\n                \"compiled\": \"function (exports, module) { /*set actions code here*/ }\",\n                \"source\": \"function (exports, module) { /*set actions code here*/ }\",\n                \"type\": \"js\"\n              }\n            },\n            \"loopArgs\": [\"item\", \"index\"],\n            \"props\": {\n              \"mobileSlot\": {\n                \"type\": \"JSBlock\",\n                \"value\": {\n                  \"children\": [\n                    {\n                      \"condition\": true,\n                      \"hidden\": false,\n                      \"isLocked\": false,\n                      \"conditionGroup\": \"\",\n                      \"componentName\": \"Text\",\n                      \"id\": \"node_ockxiczf4m2\",\n                      \"title\": \"\",\n                      \"props\": {\n                        \"maxLine\": 0,\n                        \"showTitle\": false,\n                        \"behavior\": \"NORMAL\",\n                        \"content\": {\n                          \"en-US\": \"Title\",\n                          \"zh-CN\": \"页面标题\",\n                          \"type\": \"i18n\"\n                        },\n                        \"__style__\": {},\n                        \"fieldId\": \"text_kxiczgj4\"\n                      }\n                    }\n                  ],\n                  \"componentName\": \"Slot\",\n                  \"props\": {\n                    \"slotName\": \"mobileSlot\",\n                    \"slotTitle\": \"mobile 容器\"\n                  }\n                }\n              },\n              \"className\": \"component_k8e4naln\",\n              \"useDevice\": false,\n              \"fieldId\": \"symbol_k8bnubw4\"\n            },\n            \"condition\": true,\n            \"children\": [\n              {\n                \"condition\": true,\n                \"loopArgs\": [null, null],\n                \"componentName\": \"Text\",\n                \"id\": \"node_ockxiczf4m4\",\n                \"props\": {\n                  \"maxLine\": 0,\n                  \"showTitle\": false,\n                  \"behavior\": \"NORMAL\",\n                  \"content\": {\n                    \"variable\": \"props.content\",\n                    \"type\": \"variable\",\n                    \"value\": {\n                      \"use\": \"zh-CN\",\n                      \"en-US\": \"Tips content\",\n                      \"zh-CN\": \"这是一个低代码组件\",\n                      \"type\": \"i18n\"\n                    }\n                  },\n                  \"fieldId\": \"text_kxid1d9n\"\n                }\n              }\n            ],\n            \"propTypes\": [\n              {\n                \"defaultValue\": \"这是默认值\",\n                \"name\": \"content\",\n                \"title\": \"文本内容\",\n                \"type\": \"string\"\n              }\n            ],\n            \"componentName\": \"Component\",\n            \"id\": \"node_k8bnubvz\",\n            \"state\": {}\n          }\n        ]\n      },\n      \"library\": \"LCCA\"\n    },\n    {\n      \"title\": \"多端组件库\",\n      \"package\": \"@ali/atest1\",\n      \"version\": \"1.23.0\",\n      \"advancedUrls\": {\n        \"default\": [\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css\",\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/main.3354663.js\"\n        ],\n        \"mobile\": [\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css\",\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/main.mobile.3354663.js\"\n        ],\n        \"rax\": [\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css\",\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/main.rax.3354663.js\"\n        ]\n      },\n      \"advancedEditUrls\": {\n        \"design\": [\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css\",\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/editView.design.js\"\n        ],\n        \"default\": [\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css\",\n          \"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/editView.js\"\n        ]\n      },\n      \"library\": \"Atest1\"\n    },\n    {\n      \"library\":\"UiPaaSServerless3\",\n      \"advancedUrls\":{\n          \"default\":[\n              \"https://g.alicdn.com/legao-comp/serverless3/1.1.0/env-staging-d224466e-0614-497d-8cd5-e4036dc50b70/main.js\"\n          ]\n      },\n      \"id\":\"UiPaaSServerless3-view\",\n      \"type\":\"procode\",\n      \"version\":\"1.0.0\"\n    },\n    {\n      \"package\":\"react-color\",\n      \"library\":\"ReactColor\",\n      \"id\":\"react-color\",\n      \"type\":\"procode\",\n      \"version\":\"2.19.3\",\n      \"async\":true,\n      \"exportMode\":\"functionCall\",\n      \"exportSourceId\":\"UiPaaSServerless3-view\"\n    }\n  ]\n}\n```\n\n### 2.3 components (A)\n\n定义资产包中包含的所有组件的低代码描述的集合，分为“ComponentDescription”和“RemoteComponentDescription”(详见 2.6 TypeScript 定义)：\n\n- ComponentDescription: 符合“组件描述协议”的数据，详见物料规范中`2.2.2 组件描述协议`部分；\n- RemoteComponentDescription 是将一个或多个 ComponentDescription 构建打包的 js 资源的描述，在浏览器中加载该资源后可获取到其中包含的每个组件的 ComponentDescription 的具体内容；\n\n### 2.4 sort (AA)\n\n定义组件列表分组\n\n| 根属性名称        | 类型     | 说明                                                                                         | 变量支持 | 默认值                                   |\n| ----------------- | -------- | -------------------------------------------------------------------------------------------- | -------- | ---------------------------------------- |\n| sort.groupList    | String[] | 组件分组，用于组件面板 tab 展示                                                              | -        | ['精选组件', '原子组件']                 |\n| sort.categoryList | String[] | 组件面板中同一个 tab 下的不同区间用 category 区分，category 的排序依照 categoryList 顺序排列 | -        | ['通用', '数据展示', '表格类', '表单类'] |\n\n### 2.5 plugins (AAA)\n\n自定义设计器插件列表\n\n| 根属性名称            | 类型      | 说明                 | 变量支持 | 默认值 |\n| --------------------- | --------- | -------------------- | -------- | ------ |\n| plugins[].name        | String    | 插件名称             | -        | -      |\n| plugins[].title       | String    | 插件标题             | -        | -      |\n| plugins[].description | String    | 插件描述             | -        | -      |\n| plugins[].docUrl      | String    | 插件文档地址         | -        | -      |\n| plugins[].screenshot  | String    | 插件截图地址         | -        | -      |\n| plugins[].tags        | String[]  | 插件标签分类         | -        | -      |\n| plugins[].keywords    | String[]  | 插件检索关键字       | -        | -      |\n| plugins[].reference   | Reference | 插件引用的资源包信息 | -        | -      |\n\n### 2.6 setters (AAA)\n\n自定义设置器列表\n\n| 根属性名称            | 类型      | 说明                   | 变量支持 | 默认值 |\n| --------------------- | --------- | ---------------------- | -------- | ------ |\n| setters[].name        | String    | 设置器组件名称         | -        | -      |\n| setters[].title       | String    | 设置器标题             | -        | -      |\n| setters[].description | String    | 设置器描述             | -        | -      |\n| setters[].docUrl      | String    | 设置器文档地址         | -        | -      |\n| setters[].screenshot  | String    | 设置器截图地址         | -        | -      |\n| setters[].tags        | String[]  | 设置器标签分类         | -        | -      |\n| setters[].keywords    | String[]  | 设置器检索关键字       | -        | -      |\n| setters[].reference   | Reference | 设置器引用的资源包信息 | -        | -      |\n\n### 2.7 extConfig (AAA)\n\n定义平台相关的扩展内容，用于存放平台自身实现的一些私有协议，以允许存量平台能够平滑地迁移至标准协议。extConfig 是一个 key-value 结构的对象，协议不会规定 extConfig 中的字段名称以及类型，完全自定义\n\n### 2.8 TypeScript 定义\n\n_组件低代码描述相关部分字段含义详见物料规范中`2.2.2 组件描述协议`部分；_\n\n```TypeScript\n\n/**\n * 资产包协议\n */\nexport interface Assets {\n  /**\n   * 资产包协议版本号\n   */\n  version: string;\n  /**\n   * 资源列表\n   */\n  packages?: Array<Package>;\n  /**\n   * 所有组件的描述协议集合\n   */\n  components: Array<ComponentDescription|RemoteComponentDescription>;\n  /**\n   * 低代码编辑器插件集合\n   */\n  plugins?: Array<PluginDescription>;\n  /**\n   * 低代码设置器集合\n   */\n  setters?: Array<SetterDescription>;\n  /**\n   * 平台扩展配置\n   */\n  extConfig?: AssetsExtConfig;\n  /**\n   * 用于描述组件面板中的 tab 和 category\n   */\n  sort: ComponentSort;\n}\n\nexport interface AssetsExtConfig{\n  [index: string]: any;\n}\n\n/**\n * 描述组件面板中的 tab 和 category 排布\n */\nexport interface ComponentSort {\n  /**\n   * 用于描述组件面板的 tab 项及其排序，例如：[\"精选组件\", \"原子组件\"]\n   */\n  groupList?: String[];\n  /**\n   * 组件面板中同一个 tab 下的不同区间用 category 区分，category 的排序依照 categoryList 顺序排列；\n   */\n  categoryList?: String[];\n}\n\n/**\n * 定义资产包依赖信息\n */\nexport interface Package {\n  /**\n   * 唯一标识\n   */\n  id: string;\n  /**\n   * 包名\n   */\n  package: string;\n  /**\n   * 包版本号\n   */\n  version: string;\n  /**\n   * 资源类型\n   */\n  type: string;\n  /**\n   * 组件渲染态视图打包后的 CDN url 列表，包含 js 和 css\n   */\n  urls?: string[] | any;\n  /**\n   * 组件多个渲染态视图打包后的 CDN url 列表，包含 js 和 css，优先级高于 urls\n   */\n  advancedUrls?: ComplexUrls;\n  /**\n   * 组件编辑态视图打包后的 CDN url 列表，包含 js 和 css\n   */\n  editUrls?: string[] | any;\n  /**\n   * 组件多个编辑态视图打包后的 CDN url 列表，包含 js 和 css，优先级高于 editUrls\n   */\n  advancedEditUrls?: ComplexUrls;\n  /**\n   * 低代码组件的 schema 内容\n   */\n  schema?: ComponentSchema;\n  /**\n   * 当前资源所依赖的其他资源包的 id 列表\n   */\n  deps?: string[];\n  /**\n   * 指定当前资源加载的环境\n   */\n  loadEnv?: LoadEnv[];\n  /**\n   * 当前资源是否是 external 资源\n   */\n  external?: boolean;\n  /**\n   * 作为全局变量引用时的名称，和 webpack output.library 字段含义一样，用来定义全局变量名\n   */\n  library: string;\n  /**\n   * 组件描述导出名字，可以通过 window[exportName] 获取到组件描述的 Object 内容；\n   */\n  exportName?: string;\n  /**\n   * 标识当前 package 资源加载在 window.library 上的是否是一个异步对象\n   */\n  async?: boolean;\n  /**\n   * 标识当前 package 从其他 package 的导出方式\n   */\n  exportMode?: string;\n  /**\n   * 标识当前 package 内容是从哪个 package 导出来的\n   */\n  exportSourceId?: string;\n  /**\n   * 标识当前 package 是从 window 上的哪个属性导出来的\n   */\n  exportSourceLibrary?: string;\n}\n\n\n/**\n * 复杂 urls 结构，同时兼容简单结构和多模态结构\n */\nexport type ComplexUrls = string[] | MultiModeUrls;\n\n/**\n * 多模态资源\n */\nexport interface MultiModeUrls {\n  /**\n   * 默认的资源 url\n   */\n  default: string[];\n  /**\n   * 其他模态资源的 url\n   */\n  [index: string]: string[];\n}\n\n\n/**\n * 资源加载环境种类\n */\nexport enum LoadEnv {\n  /**\n   * 设计态\n   */\n\tdesign = \"design\",\n  /**\n   * 运行态\n   */\n  runtime = \"runtime\"\n}\n\n/**\n * 低代码设置器描述\n */\nexport type SetterDescription = PluginDescription;\n\n/**\n * 低代码插件器描述\n */\nexport interface PluginDescription {\n  /**\n   * 插件名称\n   */\n  name: string;\n  /**\n   * 插件标题\n   */\n  title: string;\n  /**\n   * 插件类型\n   */\n  type?: string;\n  /**\n   * 插件描述\n   */\n  description?: string;\n  /**\n   * 插件文档地址\n   */\n  docUrl: string;\n  /**\n   * 插件截图\n   */\n  screenshot: string;\n  /**\n   * 插件相关的标签\n   */\n  tags?: string[];\n  /**\n   * 插件关键字\n   */\n  keywords?: string[];\n  /**\n   * 插件引用的资源信息\n   */\n  reference: Reference;\n}\n\n/**\n * 资源引用信息，Npm 的升级版本，\n */\nexport interface Reference {\n  /**\n   * 引用资源的 id 标识\n   */\n  id?: string;\n  /**\n   * 引用资源的包名\n   */\n  package?: string;\n  /**\n   * 引用资源的导出对象中的属性值名称\n   */\n  exportName: string;\n  /**\n   * 引用 exportName 上的子对象\n   */\n  subName: string;\n  /**\n   * 引用的资源主入口\n   */\n  main?: string;\n  /**\n   * 是否从引用资源的导出对象中获取属性值\n   */\n  destructuring: boolean;\n  /**\n   * 资源版本号\n   */\n  version: string;\n}\n\n\n/**\n * 低代码片段\n *\n * 内容为组件不同状态下的低代码 schema (可以有多个)，用户从组件面板拖入组件到设计器时会向页面 schema 中插入 snippets 中定义的组件低代码 schema\n */\nexport interface Snippet {\n  title: string;\n  screenshot?: string;\n  schema: ElementJSON;\n}\n\n/**\n * 组件低代码描述\n */\nexport interface ComponentDescription {\n  componentName: string;\n  title: string;\n  description?: string;\n  docUrl: string;\n  screenshot: string;\n  icon?: string;\n  tags?: string[];\n  keywords?: string[];\n  devMode?: 'proCode' | 'lowCode';\n  npm: Npm;\n  props: Prop[];\n  configure: Configure;\n  /**\n   * 多模态下的组件描述, 优先级高于 configure\n   */\n  advancedConfigures: MultiModeConfigures;\n  snippets: Snippet[];\n  group: string;\n  category: string;\n  priority: number;\n  /**\n   * 组件引用的资源信息\n   */\n  reference: Reference;\n}\n\nexport interface MultiModeConfigures {\n  default: Configure;\n  [index: string]: Configure;\n}\n\n/**\n * 远程物料描述\n */\nexport interface RemoteComponentDescription {\n  /**\n   * 组件描述导出名字，可以通过 window[exportName] 获取到组件描述的 Object 内容；\n   */\n  exportName?: string;\n  /**\n   * 组件描述的资源链接；\n   */\n  url?: string;\n  /**\n   * 组件多模态描述的资源信息，优先级高于 url\n   */\n  advancedUrls?: ComplexUrl;\n  /**\n   * 组件(库)的 npm 信息；\n   */\n  package?: {\n    npm?: string;\n  };\n}\n\nexport type ComplexUrl = string | MultiModeUrl\n\nexport interface MultiModeUrl {\n  default: string;\n  [index: string]: string;\n}\n\nexport interface ComponentSchema {\n  version: string;\n  componentsMap: ComponentsMap;\n  componentsTree: [ComponentTree];\n  i18n: I18nMap;\n  utils: UtilItem[];\n}\n\n```\n\n`ComponentSchema` 的定义见[低代码业务组件描述](./material-spec.md#221-组件规范)\n"
  },
  {
    "path": "docs/docs/specs/lowcode-spec.md",
    "content": "---\ntitle: 《低代码引擎搭建协议规范》\nsidebar_position: 0\n---\n\n## 1 介绍\n\n### 1.1 本协议规范涉及的问题域\n\n- 定义本协议版本号规范\n- 定义本协议中每个子规范需要被支持的 Level\n- 定义本协议相关的领域名词\n- 定义搭建基础协议版本号规范（A）\n- 定义搭建基础协议组件映射关系规范（A）\n- 定义搭建基础协议组件树描述规范（A）\n- 定义搭建基础协议国际化多语言支持规范（AA）\n- 定义搭建基础协议无障碍访问规范（AAA）\n\n\n### 1.2 协议草案起草人\n\n- 撰写：月飞、康为、林熠\n- 审阅：大果、潕量、九神、元彦、戊子、屹凡、金禅、前道、天晟、戊子、游鹿、光弘、力皓\n\n\n### 1.3 版本号\n\n1.1.0\n\n### 1.4 协议版本号规范（A）\n\n本协议采用语义版本号，版本号格式为 `major.minor.patch` 的形式。\n\n- major 是大版本号：用于发布不向下兼容的协议格式修改\n- minor 是小版本号：用于发布向下兼容的协议功能新增\n- patch 是补丁号：用于发布向下兼容的协议问题修正\n\n\n### 1.5 协议中子规范 Level 定义\n\n| 规范等级 | 实现要求                                                                           |\n| -------- | ---------------------------------------------------------------------------------- |\n| A        | 强制规范，必须实现；违反此类规范的协议描述数据将无法写入物料中心，不支持流通。     |\n| AA       | 推荐规范，推荐实现；遵守此类规范有助于业务未来的扩展性和跨团队合作研发效率的提升。 |\n| AAA      | 参考规范，根据业务场景实际诉求实现；是集团层面鼓励的技术实现引导。                 |\n\n\n### 1.6 名词术语\n\n#### 1.6.1 物料系统名词\n\n- **基础组件（Basic Component）**：前端领域通用的基础组件，阿里巴巴前端委员会官方指定的基础组件库是 Fusion Next/AntD。\n- **图表组件（Chart Component）**：前端领域通用的图表组件，有代表性的图表组件库有 BizCharts。\n- **业务组件（Business Component）**：业务领域内基于基础组件之上定义的组件，可能会包含特定业务域的交互或者是业务数据，对外仅暴露可配置的属性，且必须发布到公域（如阿里 NPM）；在同一个业务域内可以流通，但不需要确保可以跨业务域复用。\n  - **低代码业务组件（Low-Code Business Component）**：通过低代码编辑器搭建而来，有别于源码开发的业务组件，属于业务组件中的一种类型，遵循业务组件的定义；同时低代码业务组件还可以通过低代码编辑器继续多次编辑。\n- **布局组件（Layout Component）**：前端领域通用的用于实现基础组件、图表组件、业务组件之间各类布局关系的组件，如三栏布局组件。\n- **区块（Block）**：通过低代码搭建的方式，将一系列业务组件、布局组件进行嵌套组合而成，不对外提供可配置的属性。可通过 区块容器组的包裹，实现区块内部具备有完整的样式、事件、生命周期管理、状态管理、数据流转机制。能独立存在和运行，可通过复制 schema 实现跨页面、跨应用的快速复用，保障功能和数据的正常。\n- **页面（Page）**：由组件 + 区块组合而成。由页面容器组件包裹，可描述页面级的状态管理和公共函数。\n- **模板（Template）**：特定垂直业务领域内的业务组件、区块可组合为单个页面，或者是再配合路由组合为多个页面集，统称为模板。\n\n\n#### 1.6.2 低代码搭建系统名词\n\n- **搭建编辑器**：使用可视化的方式实现页面搭建，支持组件 UI 编排、属性编辑、事件绑定、数据绑定，最终产出符合搭建基础协议规范的数据。\n   - **属性面板**：低代码编辑器内部用于组件、区块、页面的属性编辑、事件绑定、数据绑定的操作面板。\n   - **画布面板**：低代码编辑器内部用于 UI 编排的操作面板。\n   - **大纲面板**：低代码编辑器内部用于页面组件树展示的面板。\n- **编辑器框架**：搭建编辑器的基础框架，包含主题配置机制、插件机制、setter 控件机制、快捷键管理、扩展点管理等底层基础设施。\n- **入料模块**：专注于物料接入，能自动扫描、解析源码组件，并最终产出一份符合《低代码引擎物料协议规范》的 Schema JSON。\n- **编排模块**：专注于 Schema 可视化编排，以可视化的交互方式提供页面结构编排服务，并最终产出一份符合《低代码搭建基础协议规范》的 Schema JSON。\n- **渲染模块**：专注于将 Schema JSON 渲染为 UI 界面，最终呈现一个可交互的页面。\n- **出码模块 Schema2Code**：专注于通过 Schema JSON 生成高质量源代码，将符合《低代码搭建基础协议规范》的 Schema JSON 数据分别转化为面向 React / Rax / 阿里小程序等终端可渲染的代码。\n- **事件绑定**：是指为某个组件的某个事件绑定相关的事件处理动作，比如为某个组件的**点击事件**绑定**一段处理函数**或**响应动作**（比如弹出对话框），每个组件可绑定的事件由该组件自行定义。\n- **数据绑定**：是指为某个组件的某个属性绑定用于该属性使用的数据。\n- **生命周期**: 一般指某个对象的生老病死，本文中指某个实体（组件、容器、区块等等）的创建、加载、显示、销毁等关键生命阶段的统称。\n\n### 1.7 背景\n\n- **协议目标**：通过约束低代码引擎的搭建协议规范，让上层低代码编辑器的产出物（低代码业务组件、区块、应用）保持一致性，可跨低代码研发平台进行流通而提效，亦不阻碍集团业务间融合的发展。 \n- **协议通**：\n  - 协议顶层结构统一\n    - 协议 schema 具备有完整的描述能力，包含版本、国际化、组件树、组件映射关系等；\n    - 顶层属性 key、value 值的格式，必须保持一致；\n  - 组件树描述统一\n    - 源码组件描述；\n    - 页面、区块、低代码业务组件这三种容器组件的描述；\n    - 数据流描述，包含数据请求、数据状态管理、数据绑定描述；\n    - 事件描述，包含统一事件上下文、统一搭建 API；\n- **物料通**：指在相同领域内的不同搭建产品，可直接使用的物料。比如模版、区块、组件；\n\n### 1.8 受众\n\n本协议适用于所有使用低代码搭建平台来开发页面或组件的开发者，以及围绕此协议的相关工具或工程化方案的开发者。阅读及使用本协议，需要对低代码搭建平台的交互和实现有一定的了解，对前端开发相关技术栈的熟悉也会有帮助，协议中对通用的前端相关术语不会做进一步的解释说明。\n\n### 1.9 使用范围\n\n本协议描述的是低代码搭建平台产物（应用、页面、区块、组件）的 schema 结构，以及实现其数据状态更新（内置 api)、能力扩展、国际化等方面完整，只在低代码搭建场景下可用；\n\n### 1.10 协议目标\n\n一套面向开发者的 schema 规范，用于规范化约束搭建编辑器的输出，以及渲染模块和出码模块的输入，将搭建编辑器、渲染模块、出码模块解耦，保障搭建编辑器、渲染模块、出码模块的独立升级。\n\n### 1.11 设计说明\n\n- **语义化**：语义清晰，简明易懂，可读性强。\n- **渐进性描述**：搭建的本质是通过 源码组件 进行嵌套组合，从小往大、依次组合生成 组件、区块、页面，最终通过云端构建生成 应用 的过程。因此在搭建基础协议中，我们需要知道如何去渐进性的描述组件、区块、页面、应用这 4 个实体概念。\n- **生成标准源码**：明确每一个属性与源码对应的转换关系，可生成跟手写无差异的高质量标准源代码。\n- **可流通性**：产物能在不同搭建产品中流通，不涉及任何私域数据存储。\n- **面向多端**：不能仅面向 React，还有小程序等多端。\n- **支持国际化&无障碍访问标准的实现**\n\n\n## 2 协议结构\n\n协议最顶层结构如下：\n\n- version { String } 当前协议版本号\n- componentsMap { Array } 组件映射关系\n- componentsTree { Array } 描述模版/页面/区块/低代码业务组件的组件树\n- utils { Array } 工具类扩展映射关系\n- i18n { Object } 国际化语料\n- constants { Object } 应用范围内的全局常量\n- css { string } 应用范围内的全局样式\n- config: { Object } 当前应用配置信息\n- meta: { Object } 当前应用元数据信息\n- dataSource: { Array } 当前应用的公共数据源\n- router: { Object } 当前应用的路由配置信息\n- pages: { Array } 当前应用的所有页面信息\n\n描述举例：\n\n```json\n{\n  \"version\": \"1.0.0\",                  // 当前协议版本号\n  \"componentsMap\": [{                  // 组件描述\n    \"componentName\": \"Button\",\n    \"package\": \"@alifd/next\",\n    \"version\": \"1.0.0\",\n    \"destructuring\": true,\n    \"exportName\": \"Select\",\n    \"subName\": \"Button\"\n  }],\n  \"utils\": [{\n    \"name\": \"clone\",\n    \"type\": \"npm\",\n    \"content\": {\n      \"package\": \"lodash\",\n      \"version\": \"0.0.1\",\n      \"exportName\": \"clone\",\n      \"subName\": \"\",\n      \"destructuring\": false,\n      \"main\": \"/lib/clone\"\n    }\n  }, {\n    \"name\": \"moment\",\n    \"type\": \"npm\",\n    \"content\": {\n      \"package\": \"@alifd/next\",\n      \"version\": \"0.0.1\",\n      \"exportName\": \"Moment\",\n      \"subName\": \"\",\n      \"destructuring\": true,\n      \"main\": \"\"\n    }\n  }],\n  \"componentsTree\": [{                 // 描述内容，值类型 Array\n    \"id\": \"page1\",\n    \"componentName\": \"Page\",           // 单个页面，枚举类型 Page|Block|Component\n    \"fileName\": \"Page1\",\n    \"props\": {},\n    \"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n    \"children\": [{\n      \"componentName\": \"Div\",\n      \"props\": {\n        \"className\": \"\"\n      },\n      \"children\": [{\n        \"componentName\": \"Button\",\n        \"props\": {\n          \"prop1\": 1234,               // 简单 json 数据\n          \"prop2\": [{                  // 简单 json 数据\n            \"label\": \"选项 1\",\n            \"value\": 1\n          }, {\n            \"label\": \"选项 2\",\n            \"value\": 2\n          }],\n          \"prop3\": [{\n            \"name\": \"myName\",\n            \"rule\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"/\\w+/i\"\n            }\n          }],\n          \"valueBind\": {               // 变量绑定\n            \"type\": \"JSExpression\",\n            \"value\": \"this.state.user.name\"\n          },\n          \"onClick\": {                 // 动作绑定\n            \"type\": \"JSFunction\",\n            \"value\": \"function(e) { console.log(e.target.innerText) }\"\n          },\n          \"onClick2\": {                // 动作绑定 2\n            \"type\": \"JSExpression\",\n            \"value\": \"this.submit\"\n          }\n        }\n      }]\n    }]\n  }],\n  \"constants\": {\n    \"ENV\": \"prod\",\n    \"DOMAIN\": \"xxx.com\"\n  },\n  \"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n  \"config\": {                                          // 当前应用配置信息\n    \"sdkVersion\": \"1.0.3\",                             // 渲染模块版本\n    \"historyMode\": \"hash\",                             // 不推荐，推荐在 router 字段中配置\n    \"targetRootID\": \"J_Container\",\n    \"layout\": {\n      \"componentName\": \"BasicLayout\",\n      \"props\": {\n        \"logo\": \"...\",\n        \"name\": \"测试网站\"\n      },\n    },\n    \"theme\": {\n      // for Fusion use dpl defined\n      \"package\": \"@alife/theme-fusion\",\n      \"version\": \"^0.1.0\",\n      // for Antd use variable\n      \"primary\": \"#ff9966\"\n    }\n  },\n  \"meta\": {                                           // 应用元数据信息，key 为业务自定义\n    \"name\": \"demo 应用\",                               // 应用中文名称，\n    \"git_group\": \"appGroup\",                          // 应用对应 git 分组名\n    \"project_name\": \"app_demo\",                       // 应用对应 git 的 project 名称\n    \"description\": \"这是一个测试应用\",                   // 应用描述\n    \"spma\": \"spa23d\",                                 // 应用 spm A 位信息\n    \"creator\": \"月飞\",\n    \"gmt_create\": \"2020-02-11 00:00:00\",              // 创建时间\n    \"gmt_modified\": \"2020-02-11 00:00:00\",            // 修改时间\n    ...\n  },\n  \"i18n\": {\n    \"zh-CN\": {\n      \"i18n-jwg27yo4\": \"你好\",\n      \"i18n-jwg27yo3\": \"中国\"\n    },\n    \"en-US\": {\n      \"i18n-jwg27yo4\": \"Hello\",\n      \"i18n-jwg27yo3\": \"China\"\n    }\n  },\n  \"router\": {\n    \"baseUrl\": \"/\",\n    \"historyMode\": \"hash\",                             // 浏览器路由：browser  哈希路由：hash\n    \"routes\": [\n      {\n        \"path\": \"home\",\n        \"page\": \"page1\"\n      }\n    ]\n  },\n  \"pages\": [\n    {\n      \"id\": \"page1\",\n      \"treeId\": \"page1\"\n    }\n  ]\n}\n```\n\n### 2.1 协议版本号（A）\n\n定义当前协议 schema 的版本号，不同的版本号对应不同的渲染 SDK，以保障不同版本搭建协议产物的正常渲染；\n\n\n| 根属性名称 | 类型   | 说明       | 变量支持 | 默认值 |\n| ---------- | ------ | ---------- | -------- | ------ |\n| version    | String | 协议版本号 | -        | 1.0.0  |\n\n\n描述示例：\n\n```javascript\n{\n  \"version\": \"1.0.0\"\n}\n```\n\n### 2.2 组件映射关系（A）\n\n协议中用于描述 componentName 到公域组件映射关系的规范。\n\n\n| 参数            | 说明                   | 类型                      | 变量支持 | 默认值 |\n| --------------- | ---------------------- | ------------------------- | -------- | ------ |\n| componentsMap[] | 描述组件映射关系的集合 | **ComponentMap**[] | -        | null   |\n\n**ComponentMap 结构描述**如下：\n\n| 参数          | 说明                                                                                                   | 类型    | 变量支持 | 默认值 |\n| ------------- | ------------------------------------------------------------------------------------------------------ | ------- | -------- | ------ |\n| componentName | 协议中的组件名，唯一性，对应包导出的组件名，是一个有效的 **JS 标识符**，而且是大写字母打头 | String  | -        | -      |\n| package       | npm 公域的 package name                                                                                  | String  | -        | -      |\n| version       | package version                                                                                        | String  | -        | -      |\n| destructuring | 使用解构方式对模块进行导出                                                                                                   | Boolean | -        | -      |\n| exportName    | 包导出的组件名                                                                                         | String  | -        | -      |\n| subName       | 下标子组件名称                                                                                         | String  | -        |        |\n| main          | 包导出组件入口文件路径                                                                                 | String  | -        | -      |\n\n\n描述示例：\n\n```json\n{\n  \"componentsMap\": [{\n    \"componentName\": \"Button\",\n    \"package\": \"@alifd/next\",\n    \"version\": \"1.0.0\",\n    \"destructuring\": true\n  }, {\n    \"componentName\": \"MySelect\",\n    \"package\": \"@alifd/next\",\n    \"version\": \"1.0.0\",\n    \"destructuring\": true,\n    \"exportName\": \"Select\"\n  }, {\n    \"componentName\": \"ButtonGroup\",\n    \"package\": \"@alifd/next\",\n    \"version\": \"1.0.0\",\n    \"destructuring\": true,\n    \"exportName\": \"Button\",\n    \"subName\": \"Group\"\n  }, {\n    \"componentName\": \"RadioGroup\",\n    \"package\": \"@alifd/next\",\n    \"version\": \"1.0.0\",\n    \"destructuring\": true,\n    \"exportName\": \"Radio\",\n    \"subName\": \"Group\"\n  }, {\n    \"componentName\": \"CustomCard\",\n    \"package\": \"@ali/custom-card\",\n    \"version\": \"1.0.0\"\n  }, {\n    \"componentName\": \"CustomInput\",\n    \"package\": \"@ali/custom\",\n    \"version\": \"1.0.0\",\n    \"main\": \"/lib/input\",\n    \"destructuring\": true,\n    \"exportName\": \"Input\"\n  }]\n}\n```\n\n出码结果：\n\n```javascript\n// 使用解构方式，destructuring is true.\nimport { Button } from '@alifd/next';\n\n// 使用解构方式，且 exportName 和 componentName 不同\nimport { Select as MySelect } from '@alifd/next';\n\n// 使用解构方式，并导出其子组件\nimport { Button } from '@alifd/next';\nconst ButtonGroup = Button.Group;\n\nimport { Radio } from '@alifd/next';\nconst RadioGroup = Radio.Group;\n\n// 不使用解构方式进行导出\nimport CustomCard from '@ali/custom-card';\n\n// 使用特定路径进行导出\nimport { Input as CustomInput } from '@ali/custom/lib/input';\n\n```\n\n\n### 2.3 组件树描述（A）\n\n\n协议中用于描述搭建出来的组件树结构的规范，整个组件树的描述由**组件结构**&**容器结构**两种结构嵌套构成。\n\n- 组件结构：描述单个组件的名称、属性、子集的结构；\n- 容器结构：描述单个容器的数据、自定义方法、生命周期的结构，用于将完整页面进行模块化拆分。\n\n与源码对应的转换关系如下：\n\n- 组件结构：转换成一个 .jsx 文件内 React Class 类 render 函数返回的 **jsx** 代码。\n- 容器结构：将转换成一个标准文件，如 React 的 jsx 文件，export 一个 React Class，包含生命周期定义、自定义方法、事件属性绑定、异步数据请求等。\n\n#### 2.3.1 基础结构描述 (A)\n\n此部分定义了组件结构、容器结构的公共基础字段。\n\n> 阅读时可先跳到后续章节，待需要时回来参考阅读\n\n##### 2.3.1.1 Props 结构描述\n\n| 参数        | 说明         | 类型   | 支持变量 | 默认值 | 备注                                  |\n| ----------- | ------------ | ------ | -------- | ------ | ------------------------------------- |\n| id          | 组件 ID       | String | ✅        | -      | 系统属性                              |\n| className   | 组件样式类名 | String | ✅        | -      | 系统属性，支持变量表达式              |\n| style       | 组件内联样式 | Object | ✅        | -      | 系统属性，单个内联样式属性值          |\n| ref         | 组件 ref 名称  | String | ✅        | -      | 可通过 `this.$(ref)` 获取组件实例 |\n| extendProps | 组件继承属性 | 变量   | ✅        | -      | 仅支持变量绑定，常用于继承属性对象    |\n| ...         | 组件私有属性 | -      | -        | -      |                                       |\n\n##### 2.3.1.2 css/less/scss 样式描述\n\n| 参数          | 说明                                                                       | 类型   | 支持变量 | 默认值 |\n| ------------- | -------------------------------------------------------------------------- | ------ | -------- | ------ |\n| css/less/scss | 用于描述容器组件内部节点的样式，对应生成一个独立的样式文件，不支持 @import | String | -        | null   |\n\n描述示例：\n\n```json\n{\n  \"css\": \"body {font-size: 12px;} .table { width: 100px; }\"\n}\n```\n\n##### 2.3.1.3 ComponentDataSource 对象描述\n\n| 参数        | 说明                   | 类型                                   | 支持变量 | 默认值 | 备注                                                                                                        |\n| ----------- | ---------------------- | -------------------------------------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------- |\n| list[]     | 数据源列表             | **ComponentDataSourceItem**[] | -        | -      | 成为为单个请求配置, 内容定义详见 [ComponentDataSourceItem 对象描述](#2314-componentdatasourceitem-对象描述) |\n| dataHandler | 所有请求数据的处理函数 | Function                               | -        | -      | 详见 [dataHandler Function 描述](#2317-datahandler-function 描述)                                           |\n\n##### 2.3.1.4 ComponentDataSourceItem 对象描述\n\n| 参数           | 说明                         | 类型                                                 | 支持变量 | 默认值                      | 备注                                                                                                                                                                 |\n| -------------- | ---------------------------- | ---------------------------------------------------- | -------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| id             | 数据请求 ID 标识               | String                                               | -        | -                           |                                                                                                                                                                      |\n| isInit         | 是否为初始数据               | Boolean                                              | ✅        | true                        | 值为 true 时，将在组件初始化渲染时自动发送当前数据请求                                                                                                                 |\n| isSync         | 是否需要串行执行             | Boolean                                              | ✅        | false                       | 值为 true 时，当前请求将被串行执行                                                                                                                                     |\n| type           | 数据请求类型                 | String                                               | -        | fetch                       | 支持四种类型：fetch/mtop/jsonp/custom                                                                                                                                |\n| shouldFetch    | 本次请求是否可以正常请求     | (options: ComponentDataSourceItemOptions) => boolean | -        | ```() => true```            | function 参数参考 [ComponentDataSourceItemOptions 对象描述](#2315-componentdatasourceitemoptions-对象描述)                                                           |\n| willFetch      | 单个数据结果请求参数处理函数 | Function                                             | -        | options => options          | 只接受一个参数（options），返回值作为请求的 options，当处理异常时，使用原 options。也可以返回一个 Promise，resolve 的值作为请求的 options，reject 时，使用原 options |\n| requestHandler | 自定义扩展的外部请求处理器   | Function                                             | -        | -                           | 仅 type='custom' 时生效                                                                                                                                               |\n| dataHandler    | request 成功后的回调函数     | Function                                             | -        | `response => response.data`| 参数：请求成功后 promise 的 value 值                                                                                                                                 ||\n| errorHandler   | request 失败后的回调函数     | Function                                             | -        | -                           | 参数：请求出错 promise 的 error 内容                                                                                                                                 |\n| options {}     | 请求参数                     | **ComponentDataSourceItemOptions**| -        | -                           | 每种请求类型对应不同参数，详见 | 每种请求类型对应不同参数，详见 [ComponentDataSourceItemOptions 对象描述](#2315-componentdatasourceitemoptions-对象描述)                                              |\n\n**关于 dataHandler 于 errorHandler 的细节说明：**\n\nrequest 返回的是一个 promise，dataHandler 和 errorHandler 遵循 Promise 对象的 then 方法，实际使用方式如下：\n\n```ts\n// 伪代码\ntry {\n  const result = await request(fetchConfig).then(dataHandler, errorHandler);\n  dataSourceItem.data = result;\n  dataSourceItem.status = 'success';\n} catch (err) {\n  dataSourceItem.error = err;\n  dataSourceItem.status = 'error';\n}\n```\n**注意：**\n- dataHandler 和 errorHandler 只会走其中的一个回调\n- 它们都有修改 promise 状态的机会，意味着可以修改当前数据源最终状态\n- 最后返回的结果会被认为是当前数据源的最终结果，如果被 catch 了，那么会认为数据源请求出错\n- dataHandler 会有默认值，考虑到返回结果入参都是 response 完整对象，默认值会返回 `response.data`，errorHandler 没有默认值\n\n\n##### 2.3.1.5 ComponentDataSourceItemOptions 对象描述\n\n| 参数    | 说明         | 类型    | 支持变量 | 默认值 | 备注                                                                                                        |\n| ------- | ------------ | ------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------- |\n| uri     | 请求地址     | String  | ✅        | -      |                                                                                                             |\n| params  | 请求参数     | Object  | ✅        | {}     | 当前数据源默认请求参数（在运行时会被实际的 load 方法的参数替换，如果 load 的 params 没有则会使用当前 params) |\n| method  | 请求方法     | String  | ✅        | GET    |                                                                                                             |\n| isCors  | 是否支持跨域 | Boolean | ✅        | true   | 对应 `credentials = 'include'`                                                                              |\n| timeout | 超时时长     | Number  | ✅        | 5000   | 单位 ms                                                                                                      |\n| headers | 请求头信息   | Object  | ✅        | -      | 自定义请求头                                                                                                |\n\n\n\n##### 2.3.1.6 ComponentLifeCycles 对象描述\n\n生命周期对象，schema 面向多端，不同 DSL 有不同的生命周期方法：\n\n- React：对于中后台 PC 物料，已明确使用 React 作为最终渲染框架，因此提案采用 [React16 标准生命周期方法](https://reactjs.org/docs/react-component.html)标准来定义生命周期方法，降低理解成本，支持生命周期如下：\n  - constructor(props, context) \n    - 说明：初始化渲染时执行，常用于设置 state 值。\n  - render() \n    - 说明：执行于容器组件 React Class 的 render 方法最前，常用于计算变量挂载到 this 对象上，供 props 上属性绑定。此 render() 方法不需要设置 return 返回值。\n  - componentDidMount()\n    - 说明：组件已加载\n  - componentDidUpdate(prevProps, prevState, snapshot)\n    - 说明：组件已更新\n  - componentWillUnmount()\n    - 说明：组件即将从 DOM 中移除\n  - componentDidCatch(error, info)\n    - 说明：组件捕获到异常\n\n该对象由一系列 key-value 组成，key 为生命周期方法名，value 为 JSFunction 的描述，详见下方示例：\n\n```json\n{\n  \"componentDidMount\": {              // key 为上文中 React 的生命周期方法名\n    \"type\": \"JSFunction\",             // type 目前仅支持 JSFunction\n    \"value\": \"function() {\\           // value 为 javascript 函数\n      console.log('did mount');\\\n    }\"\n  },\n  \"componentWillUnmount\": {\n    \"type\": \"JSFunction\",\n    \"value\": \"function() {\\\n      console.log('will unmount');\\\n    }\"\n  }\n  ...\n},\n```\n\n\n##### 2.3.1.7 dataHandler Function 描述\n\n- 参数：为 dataMap 对象，包含字段如下：\n  - key: 数据 id\n  - value: 单个请求结果\n- 返回值：数据对象 data，将会在渲染引擎和 schemaToCode 中通过调用 `this.setState(...)` 将返回的数据对象生效到 state 中；支持返回一个 Promise，通过 `resolve（返回数据）`，常用于串行发送请求场景。\n\n##### 2.3.1.8 ComponentPropDefinition 对象描述\n\n| 参数         | 说明       | 类型           | 支持变量 | 默认值    | 备注                                                                                                              |\n| ------------ | ---------- | -------------- | -------- | --------- | ----------------------------------------------------------------------------------------------------------------- |\n| name         | 属性名称   | String         | -        | -         |                                                                                                                   |\n| propType     | 属性类型   | String\\|Object | -        | -         | 具体值内容结构，参考《低代码引擎物料协议规范》内的“2.2.2.3 组件属性信息”中描述的**基本类型**和**复合类型** |\n| description  | 属性描述   | String         | -        | ''        |                                                                                                                   |\n| defaultValue | 属性默认值 | Any            | -        | undefined | 当 defaultValue 和 defaultProps 中存在同一个 prop 的默认值时，优先使用 defaultValue。                             |\n\n范例：\n```json\n{\n  \"propDefinitions\": [{\n    \"name\": \"title\",\n    \"propType\": \"string\",\n    \"defaultValue\": \"Default Title\"\n  }, {\n    \"name\": \"onClick\",\n    \"propType\": \"func\"\n  }]\n  ...\n},\n```\n\n#### 2.3.2 组件结构描述（A）\n\n对应生成源码开发体系中 render 函数返回的 jsx 代码，主要描述有以下属性：\n\n\n| 参数          | 说明                   | 类型             | 支持变量 | 默认值            | 备注                                                                                                       |\n| ------------- | ---------------------- | ---------------- | -------- | ----------------- | ---------------------------------------------------------------------------------------------------------- |\n| id            | 组件唯一标识           | String           | -        |                   | 可选，组件 id 由引擎随机生成（UUID），并保证唯一性，消费方为上层应用平台，在组件发生移动等场景需保持 id 不变 |\n| componentName | 组件名称               | String           | -        | Div               | 必填，首字母大写，同 [componentsMap](#22-组件映射关系 a) 中的要求                                           |\n| props {}      | 组件属性对象           | **Props**| -        | {}                | 必填，详见 | 必填，详见 [Props 结构描述](#2311-props-结构描述)                                                          |\n| condition     | 渲染条件               | Boolean          | ✅        | true              | 选填，根据表达式结果判断是否渲染物料；支持变量表达式                                                       |\n| loop          | 循环数据               | Array            | ✅        | -                 | 选填，默认不进行循环渲染；支持变量表达式                                                                   |\n| loopArgs      | 循环迭代对象、索引名称 | [String, String] |          | [\"item\", \"index\"] | 选填，仅支持字符串                                                                                         |\n| children      | 子组件                 | Array            |          |                   | 选填，支持变量表达式                                                                                       |\n\n\n描述举例：\n\n```json\n{\n  \"componentName\": \"Button\",\n  \"props\": {\n    \"className\": \"btn\",\n    \"style\": {\n      \"width\": 100,\n      \"height\": 20\n    },\n    \"text\": \"submit\",\n    \"onClick\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function(e) {\\\n        console.log('btn click')\\\n      }\"\n    }\n  },\n  \"condition\": {\n    \"type\": \"JSExpression\",\n    \"value\": \"!!this.state.isshow\"\n  },\n  \"loop\": [],\n  \"loopArgs\": [\"item\", \"index\"],\n  \"children\": []\n}\n```\n\n\n#### 2.3.3 容器结构描述 (A) \n\n容器是一类特殊的组件，在组件能力基础上增加了对生命周期对象、自定义方法、样式文件、数据源等信息的描述。包含**低代码业务组件容器 Component**、**区块容器 Block**、**页面容器 Page** 3 种。主要描述有以下属性：\n\n- 组件类型：componentName\n- 文件名称：fileName\n- 组件属性：props\n- state 状态管理：state\n- 生命周期 Hook 方法：lifeCycles\n- 自定义方法设置：methods\n- 异步数据源配置：dataSource\n- 条件渲染：condition\n- 样式文件：css/less/scss\n\n\n详细描述：\n\n| 参数            | 说明                       | 类型                                                                                                       | 支持变量 | 默认值 | 备注                                                                                                                          |\n| --------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |\n| componentName   | 组件名称                   | 枚举类型，包括`'Page'` （代表页面容器）、`'Block'` （代表区块容器）、`'Component'` （代表低代码业务组件容器） | -        | 'Div'    | 必填，首字母大写                                                                                                              |\n| fileName        | 文件名称                   | String                                                                                                     | -        | -      | 必填，英文                                                                                                                    |\n| props { }       | 组件属性对象               | **Props**                                                                                                  | -        | {}     | 必填，详见 [Props 结构描述](#2311-props-结构描述)                                                                             |\n| static          | 低代码业务组件类的静态对象 |                                                                                                            |          |        |                                                                                                                               |\n| defaultProps    | 低代码业务组件默认属性     | Object                                                                                                     | -        | -      | 选填，仅用于定义低代码业务组件的默认属性                                                                                      |\n| propDefinitions | 低代码业务组件属性类型定义 | **ComponentPropDefinition**[]                                                                       | -        | -      | 选填，仅用于定义低代码业务组件的属性数据类型。详见 [ComponentPropDefinition 对象描述](#2318-componentpropdefinition-对象描述) |\n| condition       | 渲染条件                   | Boolean                                                                                                    | ✅        | true   | 选填，根据表达式结果判断是否渲染物料；支持变量表达式                                                                          |\n| state           | 容器初始数据               | Object                                                                                                     | ✅        | -      | 选填，支持变量表达式                                                                                                          |\n| children        | 子组件                     | Array                                                                                                      | -        |        | 选填，支持变量表达式                                                                                                          |\n| css/less/scss   | 样式属性                   | String                                                                                                     | ✅        | -      | 选填，详见 [css/less/scss 样式描述](#2312-csslessscss 样式描述)                                                               |\n| lifeCycles      | 生命周期对象               | **ComponentLifeCycles**                                                                                    | -        | -      | 详见 [ComponentLifeCycles 对象描述](#2316-componentlifecycles-对象描述)                                                       |\n| methods         | 自定义方法对象             | Object                                                                                                     | -        | -      | 选填，对象成员为函数类型                                                                                                      |\n| dataSource {}   | 数据源对象                 | **ComponentDataSource**| -        | -      | 选填，异步数据源，详见                                                  | -        | -      | 选填，异步数据源，详见 [ComponentDataSource 对象描述](#2313-componentdatasource-对象描述)                                     |\n\n\n\n#### 完整描述示例\n\n描述示例 1：（正常 fetch/mtop/jsonp 请求）：\n\n```json\n{\n  \"componentName\": \"Block\",\n  \"fileName\": \"block-1\",\n  \"props\": {\n    \"className\": \"luna-page\",\n    \"style\": {\n      \"background\": \"#dd2727\"\n    }\n  },\n  \"children\": [{\n    \"componentName\": \"Button\",\n    \"props\": {\n      \"text\": {\n        \"type\": \"JSExpression\",\n        \"value\": \"this.state.btnText\"\n      }\n    }\n  }],\n  \"state\": {\n    \"btnText\": \"submit\"\n  },\n  \"css\": \"body {font-size: 12px;}\",\n  \"lifeCycles\": {\n    \"componentDidMount\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function() {\\\n        console.log('did mount');\\\n      }\"\n    },\n    \"componentWillUnmount\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function() {\\\n        console.log('will unmount');\\\n      }\"\n    }\n  },\n  \"methods\": {\n    \"testFunc\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function() {\\\n        console.log('test func');\\\n      }\"\n    }\n  },\n  \"dataSource\": {\n    \"list\": [{\n      \"id\": \"list\",\n      \"isInit\": true,\n      \"type\": \"fetch/mtop/jsonp\",\n      \"options\": {\n        \"uri\": \"\",\n        \"params\": {},\n        \"method\": \"GET\",\n        \"isCors\": true,\n        \"timeout\": 5000,\n        \"headers\": {}\n      },\n      \"dataHandler\": {\n        \"type\": \"JSFunction\",\n        \"value\": \"function(data, err) {}\"\n      }\n    }],\n    \"dataHandler\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function(dataMap) { }\"\n    }\n  },\n  \"condition\": {\n    \"type\": \"JSExpression\",\n    \"value\": \"!!this.state.isShow\"\n  }\n}\n```\n\n描述示例 2：（自定义扩展请求处理器类型）：\n\n```json\n{\n  \"componentName\": \"Block\",\n  \"fileName\": \"block-1\",\n  \"props\": {\n    \"className\": \"luna-page\",\n    \"style\": {\n      \"background\": \"#dd2727\"\n    }\n  },\n  ...\n  \"dataSource\": {\n    \"list\": [{\n      \"id\": \"list\",\n      \"isInit\": true,\n      \"type\": \"custom\",\n      \"requestHandler\": {\n        \"type\": \"JSFunction\",\n        \"value\": \"this.utils.hsfHandler\"\n      },\n      \"options\": {\n        \"uri\": \"hsf://xxx\",\n        \"param1\": \"a\",\n        \"param2\": \"b\",\n        ...\n      },\n      \"dataHandler\": {\n        \"type\": \"JSFunction\",\n        \"value\": \"function(data, err) { }\"\n      }\n    }],\n    \"dataHandler\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function(dataMap) { }\"\n    }\n  }\n}\n```\n\n#### 2.3.4 属性值类型描述（A）\n\n在上述**组件结构**和**容器结构**描述中，每一个属性所对应的值，除了传统的 JS 值类型（String、Number、Object、Array、Boolean）外，还包含有**节点类型**、**事件函数类型**、**变量类型**等多种复杂类型；接下来将对于复杂类型的详细描述方式进行详细介绍。\n\n##### 2.3.4.1 节点类型（A）\n\n通常用于描述组件的某一个属性为 **ReactNode** 或 **Function-Return-ReactNode** 的场景。该类属性的描述均以 **JSSlot** 的方式进行描述，详细描述如下：\n\n**ReactNode** 描述：\n\n| 参数  | 说明       | 值类型                | 默认值   | 备注                                                           |\n| ----- | ---------- | --------------------- | -------- | -------------------------------------------------------------- |\n| type  | 值类型描述 | String                | 'JSSlot' | 固定值                                                         |\n| value | 具体的值   | NodeSchema \\| NodeSchema[] | null     | 内容为 NodeSchema 类型，详见[组件结构描述](#232-组件结构描述（A）) |\n\n\n举例描述：如 **Card** 的 **title** 属性\n\n```json\n{\n  \"componentName\": \"Card\",\n  \"props\": {\n    \"title\": {\n      \"type\": \"JSSlot\",\n      \"value\": [{\n        \"componentName\": \"Icon\",\n        \"props\": {}\n      },{\n        \"componentName\": \"Text\",\n        \"props\": {}\n      }]\n    },\n    ...\n  }\n}\n\n```\n\n\n**Function-Return-ReactNode** 描述：\n\n| 参数   | 说明       | 值类型                | 默认值   | 备注                                                           |\n| ------ | ---------- | --------------------- | -------- | -------------------------------------------------------------- |\n| type   | 值类型描述 | String                | 'JSSlot' | 固定值                                                         |\n| value  | 具体的值   | NodeSchema \\| NodeSchema[] | null     | 内容为 NodeSchema 类型，详见[组件结构描述](#232-组件结构描述 a) |\n| params | 函数的参数 | String[]     | null     | 函数的入参，其子节点可以通过 `this[参数名]` 来获取对应的参数。 |\n\n\n举例描述：如 **Table.Column** 的 **cell** 属性\n\n```json\n{\n  \"componentName\": \"TabelColumn\",\n  \"props\": {\n    \"cell\": {\n      \"type\": \"JSSlot\",\n      \"params\": [\"value\", \"index\", \"record\"],\n      \"value\": [{\n        \"componentName\": \"Input\",\n        \"props\": {}\n      }]\n    },\n    ...\n  }\n}\n\n```\n\n##### 2.3.4.2 事件函数类型（A）\n\n协议内的事件描述，主要包含**容器结构**的**生命周期**和**自定义方法**，以及**组件结构**的**事件函数类属性**三类。所有事件函数的描述，均以 **JSFunction** 的方式进行描述，保留与原组件属性、生命周期（React / 小程序）一致的输入参数，并给所有事件函数 binding 统一一致的上下文（当前组件所在容器结构的 **this** 对象）。\n\n**事件函数类型**的属性值描述如下：\n\n```json\n{\n  \"type\": \"JSFunction\",\n  \"value\": \"function onClick(){\\\n    console.log(123);\\\n  }\"\n}\n```\n\n描述举例：\n\n```json\n{\n  \"componentName\": \"Block\",\n  \"fileName\": \"block1\",\n  \"props\": {},\n  \"state\": {\n    \"name\": \"lucy\"\n  },\n  \"lifeCycles\": {\n    \"componentDidMount\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function() {\\\n        console.log('did mount');\\\n      }\"\n    },\n    \"componentWillUnmount\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function() {\\\n        console.log('will unmount');\\\n      }\"\n    }\n  },\n  \"methods\": {\n    \"getNum\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function() {\\\n        console.log('名称是：' + this.state.name)\\\n      }\"\n    }\n  },\n  \"children\": [{\n    \"componentName\": \"Button\",\n    \"props\": {\n      \"text\": \"按钮\",\n      \"onClick\": {\n        \"type\": \"JSFunction\",\n        \"value\": \"function(e) {\\\n          console.log(e.target.innerText);\\\n        }\"\n      }\n    }\n  }]\n}\n```\n\n##### 2.3.4.3 变量类型（A）\n\n在上述**组件结构** 或**容器结构**中，有多个属性的值类型是支持变量类型的，通常会通过变量形式来绑定某个数据，所有的变量表达式均通过 JSExpression 表达式，上下文与事件函数描述一致，表达式内通过 **this** 对象获取上下文；\n\n变量**类型**的属性值描述如下：\n\n\n- return 数字类型\n\n  ```json\n  {\n    \"type\": \"JSExpression\",\n    \"value\": \"this.state.num\"\n  }\n  ```\n- return 数字类型\n\n  ```json\n  {\n    \"type\": \"JSExpression\",\n    \"value\": \"this.state.num - this.state.num2\"\n  }\n  ```\n- return \"8 万\" 字符串类型\n\n  ```json\n  {\n    \"type\": \"JSExpression\",\n    \"value\": \"`${this.state.num}万`\"\n  }\n  ```\n- return \"8 万\" 字符串类型\n\n  ```json\n  {\n    \"type\": \"JSExpression\",\n    \"value\": \"this.state.num + '万'\"\n  }\n  ```\n- return 13 数字类型\n\n  ```json\n  {\n    \"type\": \"JSExpression\",\n    \"value\": \"getNum(this.state.num, this.state.num2)\"\n  }\n  ```\n- return true 布尔类型\n\n  ```json\n  {\n    \"type\": \"JSExpression\",\n    \"value\": \"this.state.num > this.state.num2\"\n  }\n  ```\n\n描述举例：\n\n```json\n{\n  \"componentName\": \"Block\",\n  \"fileName\": \"block1\",\n  \"props\": {},\n  \"state\": {\n    \"num\": 8,\n    \"num2\": 5\n  },\n  \"methods\": {\n    \"getNum\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function(a, b){\\\n        return a + b;\\\n      }\"\n    }\n  },\n  \"children\": [{\n    \"componentName\": \"Button\",\n    \"props\": {\n      \"text\": {\n        \"type\": \"JSExpression\",\n        \"value\": \"this.getNum(this.state.num, this.state.num2) + '万'\"\n      }\n    },\n    \"condition\": {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.state.num > this.state.num2\"\n    }\n  }]\n}\n```\n\n##### 2.3.4.4 国际化多语言类型（AA）\n\n协议内的一些文本值内容，我们希望是和协议全局的国际化多语言语料是关联的，会按照全局国际化语言环境的不同使用对应的语料。所有国际化多语言值均以 **i18n** 结构描述。这样可以更为清晰且结构化得表达使用场景。\n\n**国际化多语言类型**的属性值类型描述如下：\n\n```typescript\ntype Ti18n = {\n  type: 'i18n';\n  key: string; // i18n 结构中字段的 key 标识符\n  params?: Record<string, JSDataType | JSExpression>; // 模版型 i18n 文案的入参，JSDataType 指代传统 JS 值类型\n}\n```\n\n其中 `key` 对应协议 `i18n` 内容的语料键值，`params` 为语料为字符串模板时的变量内容。\n\n假设协议已加入如下 i18n 内容：\n```json\n{\n  \"i18n\": {\n    \"zh-CN\": {\n      \"i18n-jwg27yo4\": \"你好\",\n      \"i18n-jwg27yo3\": \"{name}博士\"\n    },\n    \"en-US\": {\n      \"i18n-jwg27yo4\": \"Hello\",\n      \"i18n-jwg27yo3\": \"Doctor {name}\"\n    }\n  }\n}\n```\n\n**国际化多语言类型**简单范例：\n\n```json\n{\n  \"type\": \"i18n\",\n  \"key\": \"i18n-jwg27yo4\"\n}\n```\n\n**国际化多语言类型**模板范例：\n\n```json\n{\n  \"type\": \"i18n\",\n  \"key\": \"i18n-jwg27yo3\",\n  \"params\": {\n    \"name\": \"Strange\"\n  }\n}\n```\n\n描述举例：\n\n```json\n{\n  \"componentName\": \"Button\",\n  \"props\": {\n    \"text\": {\n      \"type\": \"i18n\",\n      \"key\": \"i18n-jwg27yo4\"\n    }\n  }\n}\n```\n\n\n#### 2.3.5 上下文 API 描述（A）\n\n在上述**事件类型描述**和**变量类型描述**中，在函数或 JS 表达式内，均可以通过 **this** 对象获取当前组件所在容器（React Class）的实例化对象，在搭建场景下的渲染模块和出码模块实现上，统一约定了该实例化 **this** 对象下所挂载的最小 API 集合，以保障搭建协议具备有一致的**数据流**和**事件上下文**。 \n\n##### 2.3.5.1 容器 API：\n\n| 参数                                | 说明                                    | 类型                         | 备注                                                                                                           |\n| ----------------------------------- | --------------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------- |\n| **this {}**                         | 当前区块容器的实例对象                  | Class Instance               | -                                                                                                              |\n| *this*.state                        | 三种容器实例的数据对象 state            | Object                       | -                                                                                                              |\n| *this*.setState(newState, callback) | 三种容器实例更新数据的方法              | Function                     | 这个 setState 通常会异步执行，详见下文 [setState](#setstate)                                                   |\n| *this*.customMethod()               | 三种容器实例的自定义方法                | Function                     | -                                                                                                              |\n| *this*.dataSourceMap {}             | 三种容器实例的数据源对象 Map             | Object                       | 单个请求的 id 为 key, value 详见下文 [DataSourceMapItem 结构描述](#datasourcemapitem-结构描述)                     |\n| *this*.reloadDataSource()           | 三种容器实例的初始化异步数据请求重载    | Function                     | 返回 \\<Promise\\>                                                                                               |\n| **this.page {}**                    | 当前页面容器的实例对象                  | Class Instance               |                                                                                                                |\n| *this.page*.props                   | 读取页面路由，参数等相关信息            | Object                       | query 查询参数 { key: value } 形式；path 路径；uri 页面唯一标识；其它扩展字段                            |\n| *this.page*.xxx                     | 继承 this 对象所有 API                     |                              | 此处 `xxx` 代指 `this.page` 中的其他 API                                                                          |\n| **this.component {}**               | 当前低代码业务组件容器的实例对象        | Class Instance               |                                                                                                                |\n| *this.component*.props              | 读取低代码业务组件容器的外部传入的 props | Object                       |                                                                                                                |\n| *this.component*.xxx                | 继承 this 对象所有 API                     |                              | 此处 `xxx` 代指 `this.component` 中的其他 API                                                                     |\n| **this.$(ref)**                     | 获取组件的引用（单个）                    | Component Instance           | `ref` 对应组件上配置的 `ref` 属性，用于唯一标识一个组件；若有同名的，则会返回第一个匹配的。                    |\n| **this.$$(ref)**                    | 获取组件的引用（所有同名的）              | Array of Component Instances | `ref` 对应组件上配置的 `ref` 属性，用于唯一标识一个组件；总是返回一个数组，里面是所有匹配 `ref` 的组件的引用。 |\n\n##### setState\n\n`setState()` 将对容器 `state` 的更改排入队列，并通知低代码引擎需要使用更新后的 `state` 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式。\n\n请将 `setState()` 视为请求而不是立即更新组件的命令。为了更好的感知性能，低代码引擎会延迟调用它，然后通过一次传递更新多个组件。低代码引擎并不会保证 state 的变更会立即生效。\n\n`setState()`并不总是立即更新组件，它会批量推迟更新。这使得在调用用 `setState()` 后立即读取 `this.state` 成为了隐患。为了消除隐患，请使用 `setState` 的回调函数（`setState(updater, callback)`），`callback` 将在应用更新后触发。即，如下例所示：\n\n```js\nthis.setState(newState, () => {\n  // 在这里更新已经生效了\n  // 可以通过 this.state 拿到更新后的状态\n  console.log(this.state);\n});\n\n// ⚠注意：这里拿到的并不是更新后的状态，这里还是之前的状态\nconsole.log(this.state);\n```\n\n如需基于之前的 `state` 来设置当前的 `state`，则可以将传递一个 `updater` 函数：`(state, props) => newState`，例如：\n\n```js\nthis.setState((prevState) => ({ count: prevState.count + 1 }));\n```\n\n为了方便更新部分状态，`setState` 会将 `newState` 浅合并到新的 `state` 上。\n\n\n##### DataSourceMapItem 结构描述\n\n| 参数         | 说明                       | 类型      | 备注                                                                                                                           |\n| ------------ | -------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| load(params) | 调用单个数据源             | Function  | 当前参数 params 会替换 [ComponentDataSourceItemOptions 对象描述](#2315-componentdatasourceitemoptions-对象描述)中的 params 内容 |\n| status       | 获取单个数据源上次请求状态 | String    | loading、loaded、error、init                                                                                                   |\n| data         | 获取上次请求成功后的数据   | Any       |                                                                                                                                |\n| error        | 获取上次请求失败的错误对象 | Error 对象 |                                                                                                                                |\n\n备注：如果组件没有在区块容器内，而是直接在页面内，那么 `this === this.page`\n\n\n##### 2.3.5.2 循环数据 API\n\n获取在循环场景下的数据对象。举例：上层组件设置了 loop 循环数据，且设置了 `loopArgs：[\"item\", \"index\"]`，当前组件的属性表达式或绑定的事件函数中，可以通过 this 上下文获取所在循环的数据环境；默认值为 `['item','index']` ，如有多层循环，需要自定义不同 loopArgs，同样通过 `this[自定义循环别名]` 获取对应的循环数据和序号；\n\n\n| 参数       | 说明                              | 类型   | 可选值 |\n| ---------- | --------------------------------- | ------ | ------ |\n| this.item  | 获取当前 index 对应的循环体数据； | Any    | -      |\n| this.index | 当前物料在循环体中的 index        | Number | -      |\n\n### 2.4 工具类扩展描述（AA）\n\n用于描述物料开发过程中，自定义扩展或引入的第三方工具类（例如：lodash 及 moment），增强搭建基础协议的扩展性，提供通用的工具类方法的配置方案及调用 API。\n\n| 参数               | 说明               | 类型                                                                                                             | 支持变量 | 默认值 |\n| ------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------- | -------- | ------ |\n| utils[]           | 工具类扩展映射关系 | **UtilItem**[]                                                                                          | -        |        |\n| *UtilItem*.name    | 工具类扩展项名称   | String                                                                                                           | -        |        |\n| *UtilItem*.type    | 工具类扩展项类型   | 枚举， `'npm'` （代表公网 npm 类型） / `'tnpm'` （代表阿里巴巴内部 npm 类型） / `'function'` （代表 Javascript 函数类型） | -        |        |\n| *UtilItem*.content | 工具类扩展项内容   | [ComponentMap 类型](#22-组件映射关系 a) 或 [JSFunction](#2432事件函数类型 a)                                        | -        |        |\n\n描述示例：\n\n```javascript\n{\n  utils: [{\n    name: 'clone',\n    type: 'npm',\n    content: {\n      package: 'lodash',\n      version: '0.0.1',\n      exportName: 'clone',\n      subName: '',\n      destructuring: false,\n      main: '/lib/clone'\n    }\n  }, {\n    name: 'moment',\n    type: 'npm',\n    content: {\n      package: '@alifd/next',\n      version: '0.0.1',\n      exportName: 'Moment',\n      subName: '',\n      destructuring: true,\n      main: ''\n    }\n  }, {\n    name: 'recordEvent',\n    type: 'function',\n    content: {\n      type: 'JSFunction',\n      value: \"function(logkey, gmkey, gokey, reqMethod) {\\n  goldlog.record('/xxx.event.' + logkey, gmkey, gokey, reqMethod);\\n}\"\n    }\n  }]\n}\n```\n\n出码结果：\n\n```javascript\nimport clone from 'lodash/lib/clone';\nimport { Moment } from '@alifd/next';\n\nexport const recordEvent = function(logkey, gmkey, gokey, reqMethod) {\n  goldlog.record('/xxx.event.' + logkey, gmkey, gokey, reqMethod);\n}\n\n...\n```\n\n扩展的工具类，用户可以通过统一的上下文 this.utils 方法获取所有扩展的工具类或自定义函数，例如：this.utils.moment、this.utils.clone。搭建协议中的使用方式如下所示：\n\n```javascript\n{\n  componentName: 'Div',\n  props: {\n    onClick: {\n      type: 'JSFunction,\n      value: 'function(){ this.utils.clone(this.state.data); }'\n    }\n  }\n}\n```\n\n### 2.5 国际化多语言支持（AA）\n\n协议中用于描述国际化语料和组件引用国际化语料的规范，遵循集团国际化中台关于国际化语料规范定义。\n\n\n| 参数 | 说明           | 类型   | 可选值 | 默认值 |\n| ---- | -------------- | ------ | ------ | ------ |\n| i18n | 国际化语料信息 | Object | -      | null   |\n\n\n描述示例：\n\n```json\n{\n  \"i18n\": {\n    \"zh-CN\": {\n      \"i18n-jwg27yo4\": \"你好\",\n      \"i18n-jwg27yo3\": \"中国\"\n    },\n    \"en-US\": {\n      \"i18n-jwg27yo4\": \"Hello\",\n      \"i18n-jwg27yo3\": \"China\"\n    }\n  }\n}\n```\n\n使用举例：\n\n```json\n{\n  \"componentName\": \"Button\",\n  \"props\": {\n    \"text\": {\n      \"type\": \"i18n\",\n      \"key\": \"i18n-jwg27yo4\"\n    }\n  }\n}\n```\n\n```json\n{\n  \"componentName\": \"Button\",\n  \"props\": {\n    \"text\": \"按钮\",\n    \"onClick\": {\n      \"type\": \"JSFunction\",\n      \"value\": \"function() {\\\n        console.log(this.i18n('i18n-jwg27yo4'));\\\n      }\"\n    }\n  }\n}\n```\n\n使用举例（已废弃）\n```json\n{\n  \"componentName\": \"Button\",\n  \"props\": {\n    \"text\": {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.i18n['i18n-jwg27yo4']\"\n    }\n  }\n}\n```\n\n### 2.6 应用范围内的全局常量（AA）\n\n用于描述在整个应用内通用的全局常量，比如请求 API 的域名、环境等。\n\n### 2.7 应用范围内的全局样式（AA）\n\n用于描述在应用范围内的全局样式，比如 reset.css 等。\n\n### 2.8 当前应用配置信息（AA）\n\n用于描述当前应用的配置信息，比如当前应用的 Shell/Layout、主题等。\n\n> 注意：该字段为扩展字段，消费方式由各自场景自己决定，包括运行时和出码。\n\n### 2.9 当前应用元数据信息（AA）\n\n用于描述当前应用的元数据信息，比如当前应用的名称、Git 信息、版本号等等。\n\n> 注意：该字段为扩展字段，消费方式由各自场景自己决定，包括运行时和出码。\n\n### 2.10 当前应用的公共数据源（AA）\n\n用于描述当前应用的公共数据源，数据结构跟容器结构里的 ComponentDataSource 保持一致。\n在运行时 / 出码使用时，API 和应用级数据源 API 保持一致，都是 `this.dataSourceMap['globalDSName'].load()`\n\n### 2.11 当前应用的路由信息（AA）\n\n用于描述当前应用的路径 - 页面的关系。通过声明路由信息，应用能够在不同的路径里显示对应的页面。\n\n##### 2.11.1 Router （应用路由配置）结构描述\n\n路由配置的结构说明：\n\n| 参数        | 说明                   | 类型                            | 可选值 | 默认值    | 备注   |\n| ----------- | ---------------------- | ------------------------------- | ------ | --------- | ------ |\n| baseName    | 应用根路径             | String                          | -      | '/'       | 选填｜ |\n| historyMode | history 模式           | 枚举类型，包括'browser'、'hash' | -      | 'browser' | 选填｜ |\n| routes      | 路由对象组，路径与页面的关系对照组 | Route[]                         | -      | -         | 必填｜ |\n\n\n##### 2.11.2 Route （路由记录）结构描述\n\n路由记录，路径与页面的关系对照。Route 的结构说明：\n\n| 参数     | 说明                         | 类型                         | 可选值 | 默认值 | 备注                                                                   |\n| -------- | ---------------------------- | ---------------------------- | ------ | ------ | ---------------------------------------------------------------------- |\n| name     | 该路径项的名称               | String                       | -      | -      | 选填                                                                   |\n| path     | 路径                         | String                       | -      | -      | 必填，路径规则详见下面说明                                                                   |\n| query    | 路径的 query 参数            | Object                       | -      | -      | 选填                                                                   |\n| page     | 路径对应的页面 ID            | String                       | -      | -      | 选填，page 与 redirect 字段中必须要有有一个存在                        |\n| redirect | 此路径需要重定向到的路由信息 | String \\| Object \\| Function | -      | -      | 选填，page 与 redirect 字段中必须要有有一个存在，详见下文 **redirect** |\n| meta     | 路由元数据                   | Object                       | -      | -      | 选填                                                                   |\n| children | 子路由                       | Route[]                      | -      | -      | 选填                                                                   |\n\n以上结构仅说明了路由记录需要的必需字段，如果需要更多的信息字段可以自行实现。\n\n关于 **path** 字段的详细说明：\n\n路由记录通常通过声明 path 字段来匹配对应的浏览器 URL 来确认是否满足匹配条件，如 `path=abc` 能匹配到 `/abc` 这个 URL。\n\n> 在声明 path 字段的时候，可省略 `/`，只声明后面的字符，如 `/abc` 可声明为 `abc`。\n\npath（页面路径）是浏览器URL的组成部分，同时大部分网站的 URL 也都受到了 Restful 思想的影响，所以我们也是用类似的形式作为路径的规则基底。\n路径规则是路由配置的重要组成部分，我们希望一个路径配置的基本能力需要支持具体的路径（/xxx）与路径参数 (/:abc）。\n\n以一个 `/one/:two?/three/:four?/:five?` 路径为例，它能够解析以下路径：\n- `/one/three`\n- `/one/:two/three`\n- `/one/three/:four`\n- `/one/three/:five`\n- `/one/:two/three/:four`\n- `/one/:two/three/:five`\n- `/one/three/:four/:five`\n- `/one/:two/three/:four/:five`\n\n更多的路径规则，如路径中的通配符、多次匹配等能力如有需要可自行实现。\n\n关于 **redirect** 字段的详细说明：\n\n**redirect** 字段有三种填入类型，分别是 `String`、`Object`、`Function`：\n1. 字符串(`String`)格式下默认处理为重定向到路径，支持传入 '/xxx'、'/xxx?ab=c'。\n2. 对象(`String`)格式下可传入路由对象，如 { name: 'xxx' }、{ path: '/xxx' }，可重定向到对应的路由对象。\n3. 函数`Function`格式为`(to) => Route`，它的入参为当前路由项信息，支持返回一个 Route 对象或者字符串，存在一些特殊情况，在重定向的时候需要对重定向之后的路径进行处理的情况下，需要使用函数声明。\n\n```json\n{\n  \"redirect\": {\n    \"type\": \"JSFunction\",\n    \"value\": \"(to) => { return { path: '/a', query: { fromPath: to.path } } }\",\n  }\n}\n```\n\n##### 完整描述示例\n\n``` json\n{\n  \"router\": {\n    \"baseName\": \"/\",\n    \"historyMode\": \"hash\",\n    \"routes\": [\n      {\n        \"path\": \"home\",\n        \"page\": \"home\"\n      },\n      {\n        \"path\": \"/*\",\n        \"redirect\": \"notFound\"\n      }\n    ]\n  },\n  \"componentsTree\": [\n    {\n      \"id\": \"home\",\n      ...\n    },\n    {\n      \"id\": \"notFound\",\n      ...\n    }\n  ]\n}\n```\n\n### 2.12 当前应用的页面信息（AA）\n\n用于描述当前应用的页面信息，比如页面对应的低代码搭建内容、页面标题、页面配置等。\n在一些比较复杂的场景下，允许声明一层页面映射关系，以支持页面声明更多信息与配置，同时能够支持不同类型的产物。\n\n| 参数    | 说明                  | 类型   | 可选值 | 默认值 | 备注                                                     |\n| ------- | --------------------- | ------ | ------ | ------ | -------------------------------------------------------- |\n| id      | 页面 id               | String | -      | -      | 必填                                                     |\n| type    | 页面类型              | String | -      | -      | 选填，可用来区分页面的类型                            |\n| treeId  | 对应的低代码树中的 id | String | -      | -      | 选填，页面对应的 componentsTree 中的子项 id            |\n| packageId | 对应的资产包对象      | String | -      | -      | 选填，页面对应的资产包对象，一般用于微应用场景下，当路由匹配到当前页面的时候，会加载 `packageId` 对应的微应用进行渲染。 |\n| meta    | 页面元信息            | Object | -      | -      | 选填，用于描述当前应用的配置信息                      |\n| config  | 页面配置              | Object | -      | -      | 选填，用于描述当前应用的元数据信息                     |\n\n\n#### 2.12.1 微应用（低代码+）相关说明\n\n在开发过程中，我们经常会遇到一些特殊的情况，比如一个低代码应用想要集成一些别的系统的页面或者系统中的一些页面只能是源码开发（与低代码相对的纯工程代码形式），为了满足更多的使用场景，应用级渲染引擎引入了微应用（微前端）的概念，使低代码页面与其他的页面结合成为可能。\n\n微应用对象通过资产包加载，需要暴露两个生命周期方法：\n- mount(container: HTMLElement, props: any)\n  - 说明：微应用挂载到 container（dom 节点）的调用方法，会在渲染微应用时调用\n- unmout(container: HTMLElement, props: any)\n  - 说明：微应用从容器节点（container）卸载的调用方法，会在卸载微应用时调用\n\n> 在微应用的场景下，可能会存在多个页面路由到同一个应用，应用可通过资产包加载，所以需要将对应的页面配置指向对应的微应用（资产包）对象。\n\n**描述示例**\n\n```json\n{\n  \"router\": {\n    \"baseName\": \"/\",\n    \"historyMode\": \"hash\",\n    \"routes\": [\n      {\n        \"path\": \"home\",\n        \"page\": \"home\"\n      },\n      {\n        \"page\": \"guide\",\n        \"page\": \"guide\"\n      },\n      {\n        \"path\": \"/*\",\n        \"redirect\": \"notFound\"\n      }\n    ]\n  },\n  \"pages\": [\n    {\n      \"id\": \"home\",\n      \"treeId\": \"home\",\n      \"meta\": {\n        \"title\": \"首页\"\n      }\n    },\n    {\n      \"id\": \"notFound\",\n      \"treeId\": \"notFound\",\n      \"meta\": {\n        \"title\": \"404页面\"\n      }\n    },\n    {\n      \"id\": \"guide\",\n      \"packagId\": \"microApp\"\n    }\n  ]\n}\n\n// 资产包\n[\n  {\n    \"id\": \"microApp\",\n    \"package\": \"microApp\",\n    \"version\": \"1.23.0\",\n    \"urls\": [\n      \"https://g.alicdn.com/code/lib/microApp.min.css\",\n      \"https://g.alicdn.com/code/lib/microApp.min.js\"\n    ],\n    \"library\": \"microApp\"\n  },\n]\n```\n\n\n## 3 应用描述\n\n### 3.1 文件目录\n\n以下是推荐的应用目录结构，与标准源码 build-scripts 对齐，这里的目录结构是帮助理解应用级协议的设计，不做强约束\n\n```html\n├── META/                          # 低代码元数据信息，用于多分支冲突解决、数据回滚等功能\n├── public/                        # 静态文件，构建时会 copy 到 build/ 目录\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/\n│   ├── components/                # 应用内的低代码业务组件\n│   │   └── guide-component/\n│   │       ├── index.js           # 组件入口\n│   │       ├── components.js      # 组件依赖的其他组件\n│   │       ├── schema.js          # schema 描述\n│   │       └── index.scss         # css 样式\n│   ├── pages/                     # 页面\n│   │   └── home/                  # Home 页面\n│   │       ├── index.js           # 页面入口\n│   │       └── index.scss         # css 样式\n│   ├── layouts/\n│   │   └── basic-layout/          # layout 组件名称\n│   │       ├── index.js           # layout 入口\n│   │       ├── components.js      # layout 组件依赖的其他组件\n│   │       ├── schema.js          # layout schema 描述\n│   │       └── index.scss         # layout css 样式\n│   ├── config/                    # 配置信息\n│   │   ├── components.js          # 应用上下文所有组件\n│   │   ├── routes.js              # 页面路由列表\n│   │   └── app.js                 # 应用配置文件\n│   ├── utils/                     # 工具库\n│   │   └── index.js               # 应用第三方扩展函数\n│   ├── locales/                   # [可选] 国际化资源\n│   │   ├── en-US\n│   │   └── zh-CN\n│   ├── global.scss                # 全局样式\n│   └── index.jsx                  # 应用入口脚本，依赖 config/routes.js 的路由配置动态生成路由；\n├── webpack.config.js              # 项目工程配置，包含插件配置及自定义 webpack 配置等\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.js\n├── .gitignore\n├── .stylelintignore\n└── .stylelintrc.js\n```\n\n### 3.2 应用级别 APIs\n> 下文中 `xxx` 代指任意 API\n#### 3.2.1 路由 Router API\n  - this.location.`xxx` 「不推荐，推荐统一通过 this.router api」\n  - this.history.`xxx` 「不推荐，推荐统一通过 this.router api」\n  - this.match.`xxx` 「不推荐，推荐统一通过 this.router api」\n  - this.router.`xxx`\n\n##### Router 结构说明\n\n| API            | 函数签名                                                                | 说明    |\n| -------------- | ---------------------------------------------------------- | -------------------------------------------------------------- |\n| getCurrentRoute | () => RouteLocation | 获取当前解析后的路由信息，RouteLocation 结构详见下面说明 |\n| push | (target: string \\| Route) => void | 路由跳转方法，跳转到指定的路径或者 Route |\n| replace | (target: string \\| Route) => void | 路由跳转方法，与 `push` 的区别在于不会增加一条历史记录而是替换当前的历史记录 |\n| beforeRouteLeave | (guard: (to: RouteLocation, from: RouteLocation) => boolean \\| Route) => void | 路由跳转前的守卫方法，详见下面说明 |\n| afterRouteChange | (fn: (to: RouteLocation, from: RouteLocation) => void) => void | 路由跳转后的钩子函数，会在每次路由改变后执行 |\n\n##### 3.2.1.1 RouteLocation（路由信息）结构说明\n\n**RouteLocation** 是路由控制器匹配到对应的路由记录后进行解析产生的对象，它的结构如下：\n\n| 参数           | 说明                   | 类型   | 可选值 | 默认值 | 备注   |\n| -------------- | ---------------------- | ------ | ------ | ------ | ------ |\n| path           | 当前解析后的路径       | String | -      | -      | 必填  |\n| hash           | 当前路径的 hash 值，以 # 开头  | String | -      | -      | 必填   |\n| href           | 当前的全部路径         | String | -      | -      | 必填   |\n| params         | 匹配到的路径参数       | Object | -      | -      | 必填   |\n| query          | 当前的路径 query 对象  | Object | -      | -      | 必填，代表当前地址的 search 属性的对象   |\n| name           | 匹配到的路由记录名     | String | -      | -      | 选填   |\n| meta           | 匹配到的路由记录元数据 | Object | -      | -      | 选填   |\n| redirectedFrom | 原本指向向的路由记录         | Route  |  -      | -     | 选填，在重定向到当前地址之前，原先想访问的地址   |\n| fullPath       | 包括 search 和 hash 在内的完整地址 | String | - | - | 选填 |\n\n\n##### beforeRouteLeave\n通过 beforeRouteLeave 注册的路由守卫方法会在每次路由跳转前执行。该方法一般会在应用鉴权，路由重定向等场景下使用。\n\n> `beforeRouteLeave` 只在 `router.push/replace` 的方法调用时生效。\n\n传入守卫的入参为：\n* to: 即将要进入的目标路由(RouteLocation)\n* from: 当前导航正要离开的路由(RouteLocation)\n\n该守卫返回一个 `boolean` 或者路由对象来告知路由控制器接下来的行为。\n* 如果返回 `false`， 则停止跳转\n* 如果返回 `true`，则继续跳转\n* 如果返回路由对象，则重定向至对应的路由\n\n**使用范例：**\n\n```json\n{\n  \"componentsTree\": [{\n    \"componentName\": \"Page\",\n    \"fileName\": \"Page1\",\n    \"props\": {},\n    \"children\": [{\n      \"componentName\": \"Div\",\n      \"props\": {},\n      \"children\": [{\n        \"componentName\": \"Button\",\n        \"props\": {\n          \"text\": \"跳转到首页\",\n          \"onClick\": {\n            \"type\": \"JSFunction\",\n            \"value\": \"function () { this.router.push('/home'); }\"\n          }\n        },\n      }]\n    }],\n  }]\n}\n```\n\n\n#### 3.2.2 应用级别的公共函数或第三方扩展\n   - this.utils.`xxx`\n\n#### 3.2.3 国际化相关 API\n| API            | 函数签名                                                                | 说明                                                                |\n| -------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------ |\n| this.i18n      | (i18nKey: string, params?: { [paramName: string]: string; }) => string | i18nKey 是语料的标识符，params 可选，是用来做模版字符串替换的。返回语料字符串 |\n| this.getLocale | () => string                                                           | 返回当前环境语言 code                                                 |\n| this.setLocale | (locale: string) => void                                               | 设置当前环境语言 code                                                 |\n\n**使用范例：**\n```json\n{\n  \"componentsTree\": [{\n    \"componentName\": \"Page\",\n    \"fileName\": \"Page1\",\n    \"props\": {},\n    \"children\": [{\n      \"componentName\": \"Div\",\n      \"props\": {},\n      \"children\": [{\n        \"componentName\": \"Button\",\n        \"props\": {\n          \"children\": {\n            \"type\": \"JSExpression\",\n            \"value\": \"this.i18n('i18n-hello')\"\n          },\n          \"onClick\": {\n            \"type\": \"JSFunction\",\n            \"value\": \"function () { this.setLocale('en-US'); }\"\n          }\n        },\n      }, {\n        \"componentName\": \"Button\",\n        \"props\": {\n          \"children\": {\n            \"type\": \"JSExpression\",\n            \"value\": \"this.i18n('i18n-chicken', { count: this.state.count })\"\n          },\n        },\n      }]\n    }],\n  }],\n  \"i18n\": {\n    \"zh-CN\": {\n      \"i18n-hello\": \"你好\",\n      \"i18n-chicken\": \"我有{count}只鸡\"\n    },\n    \"en-US\": {\n      \"i18n-hello\": \"Hello\",\n      \"i18n-chicken\": \"I have {count} chicken\"\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/docs/specs/material-spec.md",
    "content": "---\ntitle: 《低代码引擎物料协议规范》\nsidebar_position: 1\n---\n\n## 1 介绍\n\n### 1.1 本协议规范涉及的问题域\n\n- 定义本协议版本号规范\n- 定义本协议中每个子规范需要被支持的 Level\n- 定义中后台物料目录规范（A）\n- 定义中后台物料 API 规范（A）\n- 定义中后台物料入库规范（A）\n- 定义中后台物料国际化多语言支持规范（AA）\n- 定义中后台物料主题配置规范（AAA）\n- 定义中后台物料无障碍访问规范（AAA）\n\n\n### 1.2 协议草案起草人\n\n- 撰写：九神、大果、元彦、戊子、林熠、屹凡、金禅\n- 审阅：潕量、月飞、康为、力皓、荣彬、暁仙、度城、金禅、戊子、林熠、絮黎\n\n### 1.3 版本号\n\n1.0.0\n\n### 1.4 协议版本号规范（A）\n\n本协议采用语义版本号，版本号格式为 `major.minor.patch` 的形式。\n\n- major 是大版本号：用于发布不向下兼容的协议格式修改\n- minor 是小版本号：用于发布向下兼容的协议功能新增\n- patch 是补丁号：用于发布向下兼容的协议问题修正\n\n\n### 1.5 协议中子规范 Level 定义\n\n| 规范等级 | 实现要求                                                                           |\n| -------- | ---------------------------------------------------------------------------------- |\n| A        | 强制规范，必须实现；违反此类规范的协议描述数据将无法写入物料中心，不支持流通。     |\n| AA       | 推荐规范，推荐实现；遵守此类规范有助于业务未来的扩展性和跨团队合作研发效率的提升。 |\n| AAA      | 参考规范，根据业务场景实际诉求实现；是集团层面鼓励的技术实现引导。                 |\n\n\n### 1.6 名词术语\n- **物料**：能够被沉淀下来直接使用的前端能力，一般表现为业务组件、区块、模板。\n- **业务组件（Business Component）**：业务领域内基于基础组件之上定义的组件，可能会包含特定业务域的交互或者是业务数据，对外仅暴露可配置的属性，且必须发布到公域（如阿里 NPM）；在同一个业务域内可以流通，但不需要确保可以跨业务域复用。\n  - **低代码业务组件（Low-Code Business Component）**：通过低代码编辑器搭建而来，有别于源码开发的业务组件，属于业务组件中的一种类型，遵循业务组件的定义；同时低代码业务组件还可以通过低代码编辑器继续多次编辑。\n- **区块（Block）**：通过低代码搭建的方式，将一系列业务组件、布局组件进行嵌套组合而成，不对外提供可配置的属性。可通过区块容器组件的包裹，实现区块内部具备有完整的样式、事件、生命周期管理、状态管理、数据流转机制。能独立存在和运行，可通过复制 schema 实现跨页面、跨应用的快速复用，保障功能和数据的正常。\n- **模板（Template）**：特定垂直业务领域内的业务组件、区块可组合为单个页面，或者是再配合路由组合为多个页面集，统称为模板。\n\n### 1.7 物料规范背景\n目前集团业务融合频繁，而物料规范的不统一给业务融合带来额外的高成本，另一方面集团各个 BU 的前端物料也存在不同程度的重复建设。我们期望通过集团层面的物料通不阻碍业务融合的发展，同时通过集团层面的物料流通来提升物料丰富度，通过丰富物料的复用来提效中后台系统研发，同时也能给新业务场景提供高质量的启动物料。\n\n### 1.8 物料规范定义\n\n- **源码物料规范**：一套面向开发者的目录规范，用于规范化约束开发过程中的代码、文档、接口规范，以方便物料在集团内的流通。\n- **搭建物料规范**：一套面向开发者的 Schema 规范，用于规范化约束开发过程中的代码、文档、接口规范，以方便物料在集团内的流通。\n\n## 2. 物料规范 - 业务组件规范\n\n### 2.1 源码规范\n\n#### 2.1.1 目录规范（A）\n\n\n```\ncomponent                       //  组件名称, 比如 biz-button\n  ├── build                     // 【编译生成】【必选】\n  │   └── index.html            // 【编译生成】【必选】可直接预览文件\n  ├── lib                       // 【编译生成】【必选】\n  │   ├── index.js              // 【编译生成】【必选】js 入口文件\n  │   ├── index.scss            // 【编译生成】【必选】css 入口文件\n  │   └── style.js              // 【编译生成】【必选】js 版本 css 入口文件，方便去重\n  ├── demo                      // 【必选】组件文档目录，可以有多个 md 文件\n  │   └── basic.md              // 【必选】组件文档示例，用于生成组件开发预览，以及生成组件文档\n  ├── src                       // 【必选】组件源码\n  │   ├── index.js              // 【必选】组件出口文件\n  │   └── index.scss            // 【必选】仅包含组件自身样式的源码文件\n  ├── README.md                 // 【必选】组件说明及 API\n  └── package.json              // 【必选】组件 package.json\n```\n\n\n##### README.md\n\n- README.md 应该包含业务组件的源信息、使用说明以及 API，示例如下：\n\n```\n# 按钮                             // 这一行是标题\n\n按钮用于开始一个即时操作。             // 这一行是描述\n\n{这段通过工程能力自动注入, 开发者无需编写\n## 安装方法\nnpm install @alifd/ice-layout -S\n}\n\n## API\n\n| 参数  | 说明 |  类型   |        可选值        | 默认值 |\n| ---- | ---- | ------ | ------------------- | ------ |\n| type | 类型  | String | `primary`、`normal` | `normal` |\n```\n\n\n\n- README.en-US.md（文件命名采取 [bcp47 规范](http://www.rfc-editor.org/rfc/bcp/bcp47.txt)）多语言的情况，可选\n\n```\n# Button\n\nButton use to trigger an action.\n\n{这段通过工程能力自动注入, 开发者无需编写\n## Install\nnpm install @alifd/ice-layout -S\n}\n\n## API\n\n| Param | Description | Type   | Enum                | Default |\n| ----- | ----------- | ------ | ------------------- | ------- |\n| type  | type        | String | `primray`、`normal` | normal  |\n```\n\n##### package.json\n`package.json` 中包含了一些依赖信息和配置信息，示例如下：\n\n```json\n{\n  \"name\": \"@alife/1688-button\",\n  \"description\": \"业务组件描述\",\n  \"version\": \"0.0.1\",\n  \"main\": \"lib/index.js\",\n  \"stylePath\": \"lib/style.js\",    // 【私有字段】样式文件地址，webpack 插件引用\n  \"files\": [\n    \"demo/\",\n    \"lib/\",\n    \"build/\"                      // 存放编译后的 demo，发布前应该编译生成该目录\n  ],\n  \"dependencies\": {\n    \"@alifd/next\": \"1.x\"          // 【可选】可以是一个 util 类型的组件，如果依赖 next，请务必写语义化版本号，不要写*这种\n  },\n  \"devDependencies\": {\n    \"react\": \"^16.5.0\",\n    \"react-dom\": \"^16.5.0\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.5.0\"\n  },\n  \"componentConfig\": {            // 【私有字段】组件配置信息\n    \"name\": \"button\",             // 组件英文名\n    \"title\": \"按钮\",               // 组件中文名\n    \"category\": \"form\"            // 组件分类\n  }\n}\n```\n\n##### src/index.js\n\n包含组件的出口文件，示例如下：\n\n```javascript\nimport Button from './Button.jsx';\nimport ButtonGroup from './ButtonGroup.jsx';\n\nexport const Group = ButtonGroup;  // 子组件推荐写法\n\nexport default Button;\n```\n\n推荐用法\n\n```javascript\nimport Button, { Group } form '@scope/button';\n```\n\n##### src/index.scss\n\n```css\n/* 不引入依赖组件的样式，比如组件 import { Button } from '@alifd/next'; */\n/* 不需要在 index.scss 中引入 @import '~@alifd/next/lib/button/index.scss'; */\n\n/* 如果需要引入主题变量引入此段 */\n@import '~@alifd/next/variables.scss';\n\n/* 组件自身样式 */\n.custom-component {\n  color: $color-brand1-1;\n}\n```\n\n##### demo\ndemo 目录存放的是组件的文档，无文档的业务组件无法带来任何价值，因此 demo 是必选项。demo 目录下的文件采取 markdown 的写法，可以是多个文件，示例（demo/basic.md）如下：\n\ndemo/basic.md\n\n~~~\n---\ntitle: {按钮类型}\norder: {文档的排序，数字，0 最小，从小到大排序}\n---\n\n按钮有三种视觉层次：主按钮、次按钮、普通按钮。不同的类型可以用来区别按钮的重要程度。\n\n:::lang=en-US\n---\ntitle: Container\norder: 3\n---\n\nChange the default container by passing a function to `container`;\nenable `useAbsolute` to use `absolute position` to implement affix component;\n\n:::\n\n```jsx    // 以下建议用英文编写\nimport Button from '@alife/1688-button';\n\nReactDOM.render(<div className=\"test\">\n    <Button type=\"normal\">english</Button>\n</div>, mountNode);\n```\n\n```css\n.test {\n    background: #CCC;\n}\n```\n~~~\n\n#### 2.1.2 API 规范（A)\n\nAPI 是组件的属性解释，给开发者作为组件属性配置的参考。为了保持 API 的一致性，我们制定这个 API 命名规范。对于业界通用的，约定俗成的命名，我们遵循社区的约定。对于业界有多种规则难以确定的，我们确定其中一种，大家共同遵守。\n\n##### 通用规则\n\n- 所有的 API 采用小驼峰的书写规则，如 `onChange`、`direction`、`defaultVisible`。\n- 标签名采用大驼峰书写规则，如 `Menu`、`Slider`、`DatePicker`。\n\n##### 通用命名\n\n| API 名称        | 类型           | 描述                                                         | 常见变量                                              |\n| :------------- | :------------- | :----------------------------------------------------------- | :---------------------------------------------------- |\n| shape          | string         | 形状，从组件的外形来看有区别的时候，使用 shape               |                                                       |\n| direction      | enum           | 方向，取值采用缩写的方式。                                   | hoz（水平）, ver（垂直）                                  |\n| align          | enum           | 对齐方式                                                     | tl, tc, tr, cl, cc, cr, bl, bc, br                    |\n| status         | enum           | 状态                                                         | normal, success, error, warning                       |\n| size           | enum           | 大小                                                         | small, medium, large 更大或更小可用 (xxs, xs, xl, xxl) |\n| type           | enum or string | 分类:1. dom 结构不变、只有皮肤的变化 2.组件类型只有并列的几类 | normal, primary, secondary                            |\n| visible        | boolean        | 是否显示                                                     |                                                       |\n| defaultVisible | boolean        | 是否显示（非受控）                                           |                                                       |\n| disabled       | boolean        | 禁用组件                                                     |                                                       |\n| closable       | bool/string    | 允许关闭的方式                                               |                                                       |\n| htmlType       | string         | 当原生组件与 Fusion 组件的 type 产生冲突时，原生组件使用 `htmlType` |                                                       |\n| link           | string         | 链接                                                         |                                                       |\n| dataSource     | array          | 列表数据源                                                   | [{label, value}, {label, value}]                      |\n| has+'属性'     | boolean        | 拥有某个属性                                                 | 例如 `hasArrow`， `hasHeader`， `hasClose` 等等         |\n\n\n##### 多选枚举\n\n当某个 API 的接口，允许用户指定多个枚举值的时候，我们把这个接口定义为多选枚举。一个很典型的例子是某个弹层组件的 `closable` 属性，我们会允许：键盘 esc 按键、点击 mask、点击 close 按钮、点击组件以外的任何区域进行关闭。\n\n不要有一个 API 值，支持多种类型。例如某个弹层的组件，我们会允许 esc、点击 mask、点击 close 按钮等进行关闭。此时 API 设计可以通过多个 API 承载，例如：\n\n```js\nclosable?: boolean;         // 默认为 true\ncloseMode?: CM[] | string;  // 默认值是 ['close', 'mask', 'esc']\n```\n\ntrue 表示触发规则都会关闭，false 表示触发规则不会关闭。\n\n示例：\n\n- `<Dialog closable closeMode={['close', 'mask', 'esc']} />`，所有合法条件都会关闭\n- `<Dialog closable={false} />`，任何情况下都不关闭，只能通过受控设置 visible\n- `<Dialog closable closeMode={['close', 'esc']} />`，用户按 esc 或者点击关闭按钮会关闭\n\n##### 事件\n\n- 标准事件或者自定义的符合 w3c 标准的事件，命名必须 on 开头， 即 `on` + 事件名，如 onExpand。\n\n##### 表单规范\n\n- 支持[受控模式](https://reactjs.org/docs/forms.html#controlled-components)(value + onChange) （A)\n   - value 控制组件数据展现\n   - onChange 组件发生变化时候的回调函数（第一个参数可以给到 value)\n- `value={undefined}`的时候清空数据，field 的 reset 函数会给所有组件下发 undefined 数据 (AA))\n- 一次完整操作抛一次 onChange 事件 `建议` 比如有 Process 表示进展中的状态，建议增加 API `onProcess`；如果有 Start 表示启动状态，建议增加 API `onStart`  (AA)\n\n##### 属性的传递\n**1. 原子组件（Atomic Component）**\n> 最小粒子，不能再拆分的组件\n\n举例：Input/Button/NumberPicker\n\n期望使用起来像普通的 html 标签一样，能够把用户传入的参数，透传到真正的节点上。\n\n```jsx\n<Input id=\"my-input\" aria-label=\"this is input\" />\n```\n\n渲染后的 dom 结构：\n\n```jsx\n<span class=\"next-input next-medium\">\n  <input id=\"my-input\"  aria-label=\"this is input\" height=\"100%\" autocomplete=\"off\" value=\"\">\n</span>\n```\n\n**2. 复合组件（Composite component）**\n\n复合组件一般由两个及以上的原子组件/复合组件构成，比如：Select 由 Inupt + 弹窗组成，Search 由 Select + Button 组成，TreeSelect 由 Tree + Select 组成。\n\n为了提高组件使用的便利性，对 API 属性的要求如下：\n1. 复合组件核心的原子组件（比如 Search 的核心原子组件是 Input）的属性以及使用频率高的属性建议扁平化，让复合组件可以直接使用其属性；\n2. 复合组件内的非核心原子组件，则通过 `xxxProps` （如 inputProps/btnProps）的方式，将参数传递到相应原子组件上。\n\n\n**属性扁平化例子**：\n\n比如 `Search` 组件由 `Input` 和 `Button` 构成，但是 `Search` 更像是 `Input` ，因此把 `Input` 作为主要组件，将属性扁平化。即在 `Search` 组件上直接使用一些 `Input` 的属性。 `<Search innerBefore=\"before text\">`\n\n比如 `Select` `TreeSelect` 都有弹层部分，`Overlay` `Overlay.Popup` 的 `visible` 属性使用率较高，一般用于 fixed 布局下的弹窗滚动跟随。因此把该属性暴露到最外层，简化使用 `<Select visible={true}>` \n\n**xxxProps 例子**：\n比如 `Search` 组件由 `Input` 和 `Button` 构成，`Button` 的属性通过 `buttonProps` 传递给内部的 `Button`。`<Search buttonProps={{loading: true}}>`\n\n#### 2.1.3 入库方式 (A)\n\n入库是指：发布组件，并且存储到集团物料中心，方便统一管理和流通。\n\nstep 1: 发布组件到 tnpm\n\n```bash\n$ tnpm publish\n```\n\nstep 2: 同步到集团物料中心\n\n```bash\n# 安装工具\n$ tnpm i iceworks -g\n# 执行同步\n$ iceworks sync\n```\n\n\n#### 2.1.4 国际化多语言支持规范（AA）\n\n文件命名采取 [bcp47](https://tools.ietf.org/html/bcp47) 规范\n\n##### 目录规范\n\n在 `src` 目录新增 `locale` 目录用于管理不同语言的文案。\n\n```\n|- BizHello\n|-- src\n|---- locale\n|------ zh-CN.js\n|------ en-US.js\n|------ ja-JP.js\n```\n\n##### 定义不同的语言\n\n```javascript\n// zh-CN.js\nexport default {\n  hello: '你好，世界'\n};\n```\n\n```javascript\n// en-US.js\nexport default {\n  hello: 'hello world'\n};\n```\n\n```javascript\n// ja-JP.js\nexport default {\n  hello: 'こんにちは、世界'\n};\n```\n\n##### 组件支持多语言建议方案\n\n```jsx\n// index.jsx\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport zhCN from './locale/zh-CN.js';            // 引入默认语言\nexport default class BizHello extends Component {\n  static componentName = 'BizHello';\n\n  static propTypes = {\n    locale: PropTypes.object,                     // 增加 locale，用于配置文案\n  };\n\n  static defaultProps = {\n    locale: zhCN,\n  };\n\n  render() {\n    const { locale } = this.props;\n    return (\n      <div>{locale.hello}</div>\n    );\n  }\n}\n```\n\n##### 组件支持全局替换国际化文案\n\n配合 ConfigProvider 支持全局替换国际化文案。\n\n```jsx\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { ConfigProvider } from '@alifd/next';\nimport zhCN from './locale/zh-CN.js';            // 引入默认语言\nclass BizHello extends Component {\n  static propTypes = {\n    locale: PropTypes.object,                     // 增加 locale，用于配置文案\n  };\n\n  static defaultProps = {\n    locale: zhCN,\n  };\n\n  render() {\n    const { locale } = this.props;\n    return (\n      <div>{locale.hello}</div>\n    );\n  }\n}\nexport default ConfigProvider.config(BizHello, {\n  componentName: 'BizHello'                       // 指定组件名称，默认取组件的 displayName\n});\n```\n\n#### 2.1.5 主题切换规范（AA）\n\n业务组件中如果有自定义的需要跟随主题色的 UI，一定要引入变量的形式，增加组件的流通性。\n\n##### src/index.scss\n\n```css\n/* 如果需要引入主题变量引入此段 */\n@import '~@alifd/next/variables.scss';\n\n/* 组件自身样式 */\n.custom-component {\n  color: $color-brand1-1;\n}\n```\n\n\n#### 2.1.6 [Deprecated]支持转设计稿（AAA）\n\n对接 sketch 插件（FusionCool）的目的是为了让开发产出的业务组件能够直接给设计师使用，用法类似现在 Fusion Next 基础组件。\n\n新增文件 `adaptor/index.js` 。\n\n```jsx\nimport BizButton from '@alifd/biz-button';\n\nexport default {\n  name: 'BizButton',\n  editor: () => ({\n    props: [{\n      name: 'level',\n      type: 'enum',\n      options: ['normal', 'primary', 'secondary'],\n    }, {\n      name: 'size',\n      type: 'enum',\n      options: ['large', 'medium', 'small'],\n      default: 'medium',\n    }],\n    data: {\n      default: 'hello',\n    }\n  }),                                           // 内容编辑器\n  adaptor: ({ data, level, size, ...others }) => {\n    return <BizButton type={level} size={size}>{data}</BizButton>;\n  },\n}\n```\n\napi 属性标准参考 [https://fusion.design/help.html#/dev-biz](https://fusion.design/help.html#/dev-biz)\n\n#### 2.1.7 无障碍访问规范 (AAA)\n\n无障碍需要符合 [WCAG 2.1 A 级标准](https://www.w3.org/TR/WCAG21/)，可参考 [W3C 无障碍最佳实践](https://www.w3.org/TR/wai-aria-practices-1.1/)、[Fusion 无障碍指引 2.3.1](https://alibaba-fusion.github.io/next/part1/basics.html) 章节等。\n\n\n##### 增加 a11y.md 无障碍 demo\n\n必须借助 API 才能完成无障碍工作的组件必须为开发者提供无障碍的使用文档，请[参考](https://fusion.design/pc/component/select?themeid=2#accessibility-container)组件 API 中 `ARIA and Keyboard` ，建议在 `demo` 目录新增 `a11y.md` 文件用于演示组件的无障碍使用。\n\n```\ncomponent\n  └─ demo\n      ├─ a11y.md\n      └─ basic.md\n```\n\n详细指引查看无障碍开发指南 [https://alibaba-fusion.github.io/next/part1/basics.html](https://alibaba-fusion.github.io/next/part1/basics.html)。\n\n\n##### 通过键盘快速访问\n\n一般键盘事件有 Up Arrow/Down Arrow/Enter/Esc/Tab\n\n例子：Select 的键盘事件说明\n\n| 按键       | 说明                 |\n| :--------- | :------------------- |\n| Up Arrow   | 获取当前项前一项焦点 |\n| Down Arrow | 获取当前项后一项焦点 |\n| Enter      | 打开列表或选择当前项 |\n| Esc        | 关闭列表             |\n\n\n##### 对读屏软件友好\n\n- 对于组件，我们为开发者内置 `role` 和特定 `aria-_属性`，开发者也可以对非组件 API 属性都可以透传至 DOM 元素，进行修改 `role` 和 `aria-_参数`，但是要注意对应关系，请[参考](https://alibaba-fusion.github.io/next/part1/WAI-ARIA.html)。\n- 对一些特殊的组件传递参数才能支持无障碍，设置 `id`，`autoFocus` 和传参数，如下：\n   - id - `Balloon`，`Rating`\n   - autoFocus - 弹层自动聚焦，例如 `Dialog`，`Overlay`，`Dropdown`\n   - 传参数 - 有些组件需要根据具体的业务，实现不同的可访问性，这里为开发者内置一些参数，想使用无障碍的时候，用户只需要根据现有的需求，选择对应的内置参数，例如设置 aria-label，以下组件需要用户传参数才支持无障碍组件如下：`NumberPicker`、`Transfer`\n\n\n### 2.2 低代码规范\n\n#### 2.2.1 组件规范\n\n通过低代码编辑器搭建而来，有别于源码开发的业务组件，属于业务组件中的一种类型，遵循业务组件的定义；同时低代码业务组件还可以通过低代码编辑器继续多次编辑。\n\n\n| 根属性描述     | 说明                                                                                              | 类型   |\n| -------------- | ------------------------------------------------------------------------------------------------- | ------ |\n| version        | 协议版本号                                                                                        | String |\n| componentsMap  | 描述组件映射关系的集合                                                                            | Array  |\n| componentsTree | 低代码业务组件树描述，是长度固定为 1 的数组，即数组内仅包含根容器的描述（低代码业务组件容器类型） | Array  |\n| utils          | 工具类扩展映射关系                                                                                | Array  |\n| i18n           | 国际化语料                                                                                        | Object |\n\n\n描述举例：\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [{ }],\n  \"componentsTree\": [{                   // 低代码业务组件树，顶层由低代码业务组件容器包裹；\n    \"componentName\": \"Component\",        // 低代码业务组件容器组件名\n    \"fileName\": \"SearchComp\",            // 低代码业务组件文件名，同时会将首字母大写，作为低代码业务组件名\n    \"props\": {},                         // 一般不定义，如果有数据用于模拟外部传入的属性值\n    \"css\": \"body {font-size: 12px;}\",\n    \"state\": {\n      \"name\": \"lucy\",\n    },\n    \"static\": {},                        // 用于定义自定组件的 static 属性\n    \"defaultProps\": {                    // 默认 props：选填仅用于定义低代码业务组件的默认属性固定对象\n      \"name\": \"xxx\"\n    },\n    \"children\": [{\n      \"componentName\": \"Div\",\n      \"props\": {\n        \"className\": \"className1\"\n      },\n      \"children\": [{\n        \"componentName\": \"Button\",\n        \"props\": {\n          \"text\": \"点击弹出我的姓名\",\n          \"onClick\": {\n            \"type\": \"JSFunction\",\n            \"value\": \"function(e){\\\n              alert(this.state.name)\\\n            }\"\n          }\n        }\n      }]\n    }]\n  }],\n  \"i18n\": { }\n}\n```\n\n#### 2.2.2 组件描述协议\n对源码组件在低代码搭建平台中使用时所具备的配置能力和交互行为进行规范化描述，让不同平台对组件接入的实现保持一致，让组件针对不同的搭建平台接入时可以使用一份统一的描述内容，让组件在不同的业务中流通成为可能。\n\n##### 2.2.2.1 协议结构\n\n单个组件描述内容为 json 结构，主要包含以下三部分内容，分别为：\n\n- **基础信息 (A)：** 描述组件的基础信息，通常包含包信息、组件名称、标题、描述等。\n- **组件属性信息 (A)：** 描述组件属性信息，通常包含参数、说明、类型、默认值 4 项内容。\n- **能力配置/体验增强：** 推荐用于优化搭建产品编辑体验，定制编辑能力的配置信息。\n\n##### 2.2.2.2 基础信息（A）\n\n| 字段              | 字段描述              | 字段类型                  | 允许空 |\n| ----------------- | --------------------- | ------------------------- | ------ |\n| componentName     | 组件名称              | String                    | 否     |\n| title             | 组件中文名称          | String                    | 否     |\n| description       | 组件描述              | String                    | 是     |\n| docUrl            | 组件文档链接          | String                    | 否     |\n| screenshot        | 组件快照              | String                    | 否     |\n| icon              | 组件的小图标          | String (URL)              | 是     |\n| tags              | 组件标签              | String                    | 是     |\n| keywords          | 组件关键词，用于搜索联想 | String                    | 是     |\n| devMode           | 组件研发模式          | String  (proCode,lowCode) | 是     |\n| npm               | npm 源引入完整描述对象 | Object                    | 否     |\n| npm.package       | 源码组件库名          | String                    | 否     |\n| npm.exportName    | 源码组件名称          | String                    | 否     |\n| npm.subName       | 子组件名              | String                    | 否     |\n| npm.destructuring | 解构                  | Bool                      | 否     |\n| npm.main          | 组件路径              | String                    | 否     |\n| npm.version       | 源码组件版本号        | String                    | 否     |\n| snippets          | 内容为组件不同状态下的低代码 schema (可以有多个)，用户从组件面板拖入组件到设计器时会向页面 schema 中插入 snippets 中定义的组件低代码 schema | Object[]                    | 否     |\n| group             | 用于描述当前组件位于组件面板的哪个 tab  | String                    | 否     |\n| category          | 用于描述组件位于组件面板同一 tab 的哪个区域        | String                    | 否     |\n| priority          | 用于描述组件在同一 category 中的排序       | String                    | 否     |\n\n\n##### 2.2.2.3 组件属性信息 props (A)\n\n描述组件属性信息，通常包含名称、类型、描述、默认值 4 项内容。\n\n\n| 字段         | 字段描述   | 字段类型        | 允许空 |\n| ------------ | ---------- | --------------- | ------ |\n| name         | 属性名称   | String          | 否     |\n| propType     | 属性类型   | String/Object | 否     |\n| description  | 属性描述   | String          | 是     |\n| defaultValue | 属性默认值 | Any             | 是     |\n\n\npropType 类型参考 [PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes)，存在**基本类型**和**复合类型**，描述如下：\n\n**基本类型**\n\n| propType 值                                          | 类型描述               | 参考 PropTypes 类型       |\n| ---------------------------------------------------- | ---------------------- | ------------------------- |\n| 'array'                                              | 数组类型               | PropTypes.array           |\n| 'bool'                                               | 布尔类型               | PropTypes.bool            |\n| 'func'                                               | 函数类型               | PropTypes.func            |\n| 'number'                                             | 数字类型               | PropTypes.number          |\n| 'object'                                             | 对象类型               | PropTypes.object          |\n| 'string'                                             | 字符串类型             | PropTypes.string          |\n| 'node'                                               | 节点类型               | PropTypes.node            |\n| 'element'                                            | 元素类型               | PropTypes.element         |\n| 'any'                                                | 任意值类型             | PropTypes.any             |\n| {<br />  type: 'xxx',<br />  isRequired: true<br />} | 指定类型，且是必要属性 | PropTypes.xxxx.isRequired |\n\n\n\n> 注意：上述类型均支持 PropTypes.xxx.isRequired 链式描述方式描述该属性是否为**必要属性**。\n\n\n描述举例：\n\n```javascript\n// 组件源码\nexport default class FusionForm extends PureComponent {\n  static displayName = 'FusionForm';\n  static propTypes = {\n    name: PropTypes.string,\n    age: PropTypes.number,\n    friends: PropTypes.array,\n  };\n  render(){\n    return ...;\n  }\n}\n\n// 组件属性描述\n{\n  props: [{\n    name: 'name',\n    propType: {\n      type: 'string',\n      isRequired: true,\n    },\n    description: '这是用于描述姓名',\n    defaultValue: '张三',\n  }, {\n    name: 'age',\n    propType: 'number',\n    description: '这是用于描述年龄',\n    defaultValue: 18,\n  }, {\n    name: 'friends',\n    propType: 'array',\n    description: '这是用于描述好友列表',\n    defaultValue: [ '李四', '王五', '赵六' ],\n  }],\n}\n```\n\n**复合类型**\n\n\n| propType 值                                                                                                                                                                                                                                    | 类型描述                                         | PropTypes 类型           |\n| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ------------------------ |\n| {<br />  type: 'oneOf',<br />  value: ['a', 'b', 'c', '...']<br />}                                                                                                                                                                            | 枚举值类型                                       | PropTypes.oneOf(...)     |\n| {<br />  type: 'oneOfType',<br />  value: ['string', 'number', {<br />    type: 'array',<br />    isRequired: true<br />  }]<br />}                                                                                                            | 指定类型中的一种，支持递归描述                   | PropTypes.oneOfType(...) |\n| {<br />  type: 'arrayOf',<br />  value: 'number'<br />}                                                                                                                                                                                        | 指定统一成员**值类型**的数组类型                 | PropTypes.arrayOf(...)   |\n| {<br />  type: 'objectOf',<br />  value: 'string'<br />}                                                                                                                                                                                       | 指定统一对象属性**值类型**的对象类型             | PropTypes.objectOf(...)  |\n| {<br />  type: 'shape',<br />  value: [{<br />    name: 'color',<br />    propType: 'string'<br />  }, {<br />    name: 'fontSize',<br />    propType: {<br />      type: 'number',<br />      isRequied: true  <br />    }  <br />  }]<br />} | 指定对象的部分**属性名**和**值类型**的对象类型   | PropTypes.shape(...)     |\n| {<br />  type: 'exact',<br />  value: [{<br />    name: 'name',<br />    propType: 'string'  <br />  }, {<br />    name: 'quantity',<br />    propType: 'number'<br />  }]<br />}                                                              | 严格指定对象全部**属性名**和**值类型**的对象类型 | PropTypes.exact(...)     |\n\n\n描述举例：\n\n```javascript\n// 组件源码\nexport default class FusionForm extends PureComponent {\n  static displayName = 'FusionForm';\n  static propTypes = {\n    title: PropTypes.oneOf(['News', 'Photos']),\n    message: PropTypes.oneOfType([\n      PropTypes.string,\n      PropTypes.number,\n      PropTypes.instanceOf(Message),\n    ]),\n    size: PropTypes.arrayOf(PropTypes.number),\n    bodyStyle: PropTypes.shape({\n      color: PropTypes.string,\n      fontSize: PropTypes.number,\n    }),\n    extraContext: function (props, propName, componentName) {\n      if (!/matchme/.test(props[propName])) {\n        return new Error(\n          'Invalid prop `' + propName + '` supplied to' +\n          ' `' + componentName + '`. Validation failed.'\n        );\n      }\n    },\n  };\n  render() {\n    return ...;\n  }\n}\n\n// 组件属性描述\n{\n  props: [{\n    name: 'title',\n    propType: {\n      type: 'oneOf',\n      value: ['News', 'Photos'],\n    },\n    description: '这是用于描述标题',\n    defaultValue: '标题一',\n  }, {\n    name: 'message',\n    propType: {\n      type: 'oneOfType',\n      value: ['string', 'number', {\n        type: 'array',\n        isRequired: true,\n      }],\n    },\n    description: '这是用于描述消息内容',\n    defaultValue: 'xxx',\n  }, {\n    name: 'size',\n    propType: {\n      type: 'arrayOf',\n      value: 'number',\n    },\n    description: '这是用于描述大小列表',\n    defaultValue: [1, 2, 3],\n  }], {\n    name: 'bodyStyle',\n    propType: {\n      type: 'shape',\n      value: [{\n        name: 'color',\n        propType: 'string',\n      }, {\n        name: 'fontSize',\n        propType: {\n          type: 'number',\n          isRequied: true,\n        }\n      }],\n    },\n    description: '这是用于描述主体样式',\n    defaultValue: [1, 2, 3],\n  }],\n}\n```\n\n\n##### 2.2.2.4 编辑体验增强 configure\n\n推荐用于优化搭建产品的编辑体验，定制编辑能力的配置信息，通过能力抽象分类，主要包含如下几个维度的配置项：\n\n\n| 字段          | 字段描述               | 字段类型 | 备注                                                                   |\n| ------------- | ---------------------- | -------- | ---------------------------------------------------------------------- |\n| props (A)     | 属性面板配置           | Array    | 用于属性面板能力描述                                                   |\n| component(A)  | 组件能力配置           | Object   | 与组件相关的能力、约束、行为等描述，有些信息可从组件视图实例上直接获取 |\n| supports (AA) | 通用扩展配置能力支持性 | Object   | 用于通用扩展面板能力描述                                               |\n| advanced (AAA) | 高级特性配置 | Object   | 用户可以在这些配置通过引擎上下文控制组件在设计器中的表现，例如自动初始化组件的子组件、截获组件的操作事件进行个性化处理等        |\n| 【已废弃】experimental (AAA) | 将引擎的一些实验性特性放在这个配置里 | Object   | 用户可以提前体验这些特性                                               |\n\n\n###### 2.2.2.4.1 属性面板配置 props (A)\n\nprops 数组下对象字段描述：\n\n\n| 字段       | 字段描述                                                                               | 字段类型          | 备注                |\n| ---------- | -------------------------------------------------------------------------------------- | ----------------- | ------------------- |\n| type | 指定类型 | Enum | 可选值为 `'field' | 'group'` ,默认为  'field'|\n| display | 指定类型 | Enum | 可选值为 `'accordion' \\| 'inline' \\| 'block' \\| 'plain' \\| 'popup' \\| 'entry'` ，默认为  'inline'|\n| title      | 分类标题                                                                               | 属性标题          | String              |       |\n| items      | 分类下的属性列表                                                                       | Array\\<Object\\> | type = 'group' 生效 |\n| name       | 属性名                                                                                 | String            | type = 'field' 生效 |\n| defaultValue | 默认值 | Any(视字段类型而定) | type = 'field' 生效 |\n| supportVariable | 是否支持配置变量 | Boolean | type = 'field' 生效 |\n| condition | 配置当前 prop 是否展示 | (target: IPublicModelSettingField) => boolean; | - |\n| ignoreDefaultValue | 配置当前 prop 是否忽略默认值处理逻辑，如果返回值是 true 引擎不会处理默认值 | (target: IPublicModelSettingField) => boolean; | - |\n| setter     | 单个控件 (setter) 描述，搭建基础协议组件的描述对象，支持 JSExpression / JSFunction / JSSlot | `String\\|Object\\|Function` | type = 'field' 生效 |\n| extraProps | 其他配置属性（不做流通要求）                                                           | Object            | 其他配置            |\n| extraProps.getValue | setter 渲染时被调用，setter 会根据该函数的返回值设置 setter 当前值 | Function            | (target: IPublicModelSettingField, value: any) => any;            |\n| extraProps.setValue | setter 内容修改时调用，开发者可在该函数内部修改节点 schema 或者进行其他操作 | Function            | (target: IPublicModelSettingField, value: any) => void;            |\n\n\n根据属性值类型 propType，确定对应控件类型 (setter) 。\n\n\n###### 2.2.2.4.2 通用扩展面板支持性配置 supports (AA)\n\n样式配置面板能力描述，描述是否支持行业样式编辑、是否支持类名设置等。\n\n```json\n{\n  \"configure\": {\n    // 支持的事件枚举\n    \"supports\": {\n      // 支持事件列表\n      \"events\": [\"onClick\", \"onChange\"],\n      // 支持循环设置\n      \"loop\": true,\n      // 支持条件设置\n      \"condition\": true,\n      // 支持样式设置\n      \"style\": true,\n    }\n  }\n}\n```\n\n\n###### 2.2.2.4.3 组件能力配置 component\n\n与组件相关的能力、约束、行为等描述，有些信息可从组件视图实例上直接获取，包含如下字段：\n\n\n| 字段                            | 用途                                                                                                | 类型    |\n| ------------------------------- | --------------------------------------------------------------------------------------------------- | ------- |\n| isContainer(A)                  | 是否容器组件                                                                                        | Boolean |\n| isModal(A)                      | 组件是否带浮层，浮层组件拖入设计器时会遮挡画布区域，此时应当辅助一些交互以防止阻挡                  | Boolean |\n| descriptor(A)                   | 组件树描述信息                                                                                      | String  |\n| nestingRule(A)                  | 嵌套控制：防止错误的节点嵌套，比如 a 嵌套 a, FormField 只能在 Form 容器下，Column 只能在 Table 下等 | Object  |\n| nestingRule.childWhitelist      | 子节点类型白名单                                                                                    | `String\\|Function`  |\n| nestingRule.parentWhitelist     | 父节点类型白名单                                                                                    | `String\\|Function`  |\n| nestingRule.descendantBlacklist | 后裔节点类型黑名单                                                                                  | `String\\|Function`  |\n| nestingRule.ancestorWhitelist   | 祖父节点类型白名单                                                                                  | `String\\|Function`  |\n| isNullNode(AAA)                 | 是否存在渲染的根节点                                                                                | Boolean |\n| isLayout(AAA)                   | 是否是 layout 布局组件                                                                                | Boolean |\n| rootSelector(AAA)                   | 组件选中框的 cssSelector                                                                                | String |\n| disableBehaviors(AAA)                   | 用于屏蔽在设计器中选中组件时提供的操作项，默认操作项有 copy、hide、remove                                                                                | String[] |\n| actions(AAA)                   | 用于详细配置上述操作项的内容                                                                                | Object |\n| isMinimalRenderUnit                   | 是否是最小渲染单元，最小渲染单元下的组件渲染和更新都从单元的根节点开始渲染和更新。如果嵌套了多层最小渲染单元，渲染会从最外层的最小渲染单元开始渲染。                                                                                | Boolean |\n\n描述举例：\n\n```js\n{\n  configure: {\n    component: {\n      isContainer: true,\n      isModal: false,\n      descriptor: 'title',\n      nestingRule: {\n        childWhitelist: ['SelectOption'],\n        parentWhitelist: ['Select', 'Table'],\n      },\n      rootSelector: '.next-dialog',\n      disableBehaviors: ['copy', 'remove'],\n      actions: {\n        name: 'copy', // string;\n        content: '＋', // string | ReactNode | ActionContentObject;\n        items: [], // ComponentAction[];\n        condition: 'always', // boolean | ((currentNode: any) => boolean) | 'always';\n        important: true, // boolean;\n      },\n    },\n  },\n}\n```\n\n###### 2.2.2.4.4 高级功能配置 advanced (AAA)\n\n组件在低代码引擎设计器中的事件回调和 hooks 等高级功能配置，包含如下字段：\n\n\n| 字段 | 用途 | 类型 | 备注 |\n| ------------------------------- | --------------------------------------------------------------------------------------------------- | ------- | --- |\n|initialChildren\t| 组件拖入“设计器”时根据此配置自动生成 children 节点 schema |NodeData[]/Function\tNodeData[] | ((target: IPublicModelSettingField) => NodeData[]);|\n|getResizingHandlers|\t用于配置设计器中组件 resize 操作工具的样式和内容 |\tFunction|\t(currentNode: any) => Array<{ type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW'; content?: ReactElement; propTarget?: string; appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always'; }> / ReactElement[];\n|callbacks|\t配置 callbacks 可捕获引擎抛出的一些事件，例如 onNodeAdd、onResize 等 |\tCallback|\t-\n|callbacks.onNodeAdd|\t在容器中拖入组件时触发的事件回调 |\tFunction|\t(e: MouseEvent, currentNode: any) => any\n|callbacks.onNodeRemove|\t在容器中删除组件时触发的事件回调 |\tFunction|\t(e: MouseEvent, currentNode: any) => any\n|callbacks.onResize|\t调整容器尺寸时触发的事件回调，常常与 getResizingHandlers 搭配使用 |\tFunction|\t详见 Types 定义\n|callbacks.onResizeStart|\t调整容器尺寸开始时触发的事件回调，常常与 getResizingHandlers 搭配使用 |\tFunction|\t详见 Types 定义\n|callbacks.onResizeEnd|\t调整容器尺寸结束时触发的事件回调，常常与 getResizingHandlers 搭配使用 |\tFunction|\t详见 Types 定义\n|callbacks.onSubtreeModified|\t容器节点结构树发生变化时触发的回调 |\tFunction|\t(currentNode: any, options: any) => void;\n|callbacks.onMouseDownHook|\t鼠标按下操作回调 |\tFunction|\t(e: MouseEvent, currentNode: any) => any;\n|callbacks.onClickHook|\t鼠标单击操作回调 |\tFunction|\t(e: MouseEvent, currentNode: any) => any;\n|callbacks.onDblClickHook|\t鼠标双击操作回调 |\tFunction|\t(e: MouseEvent, currentNode: any) => any;\n|callbacks.onMoveHook|\t节点被拖动回调 |\tFunction|\t(currentNode: any) => boolean;\n|callbacks.onHoverHook|\t节点被 hover 回调 |\tFunction|\t(currentNode: any) => boolean;\n|callbacks.onChildMoveHook|\t容器节点的子节点被拖动回调 |\tFunction|\t(childNode: any, currentNode: any) => boolean;\n\n\n描述举例：\n\n```js\n{\n  configure: {\n    advanced: {\n      callbacks: {\n        onNodeAdd: (dragment, currentNode) => {\n\n        }\n      },\n      getResizingHandlers: () => {\n        return [ 'E' ];\n      },\n      initials: [\n        {\n          name: 'linkType',\n          initial: () => 'link'\n        },\n      ]\n    },\n  }\n}\n```\n\n##### 2.2.2.5 TypeScript 定义\n\n```TypeScript\n\nexport interface ConfigureProp {\n  /**\n   * 面板配置隶属于单个 field 还是分组\n   */\n  type?: 'field' | 'group';\n  /**\n   * the name of this setting field, which used in quickEditor\n   */\n  name: string | number;\n  /**\n   * the field title\n   * @default sameas .name\n   */\n  title?: TitleContent;\n  /**\n   * 单个属性的 setter 配置\n   *\n   * the field body contains when .type = 'field'\n   */\n  setter?: SetterType | DynamicSetter;\n  /**\n   * the setting items which group body contains when .type = 'group'\n   */\n  items?: ConfigureProp[];\n  /**\n   * extra props for field\n   * 其他配置属性（不做流通要求）\n   */\n  extraProps?: ExtraProps;\n}\n\nexport interface ConfigureSupport {\n  /**\n   * 支持事件列表\n   */\n  events?: ConfigureSupportEvent[];\n  /**\n   * 支持 className 设置\n   */\n  className?: boolean;\n  /**\n   * 支持样式设置\n   */\n  style?: boolean;\n  /**\n   * 支持生命周期设置\n   */\n  lifecycles?: any[];\n  // general?: boolean;\n  /**\n   * 支持循环设置\n   */\n  loop?: boolean;\n  /**\n   * 支持条件式渲染设置\n   */\n  condition?: boolean;\n}\n\nexport interface ConfigureComponent {\n  /**\n   * 是否容器组件\n   */\n  isContainer?: boolean;\n  /**\n   * 组件是否带浮层，浮层组件拖入设计器时会遮挡画布区域，此时应当辅助一些交互以防止阻挡\n   */\n  isModal?: boolean;\n  /**\n   * 是否存在渲染的根节点\n   */\n  isNullNode?: boolean;\n  /**\n   * 组件树描述信息\n   */\n  descriptor?: string;\n  /**\n   * 嵌套控制：防止错误的节点嵌套\n   * 比如 a 嵌套 a, FormField 只能在 Form 容器下，Column 只能在 Table 下等\n   */\n  nestingRule?: NestingRule;\n\n  /**\n   * 是否是最小渲染单元\n   * 最小渲染单元下的组件渲染和更新都从单元的根节点开始渲染和更新。如果嵌套了多层最小渲染单元，渲染会从最外层的最小渲染单元开始渲染。\n   */\n  isMinimalRenderUnit?: boolean;\n\n  /**\n   * 组件选中框的 cssSelector\n   */\n  rootSelector?: string;\n  /**\n   * 禁用的行为，可以为 `'copy'`, `'move'`, `'remove'` 或它们组成的数组\n   */\n  disableBehaviors?: string[] | string;\n  /**\n   * 用于详细配置上述操作项的内容\n   */\n  actions?: ComponentAction[];\n}\n\nexport interface Advanced {\n  /**\n   * @todo 待补充文档\n   */\n  context?: { [contextInfoName: string]: any };\n  /**\n   * @todo 待补充文档\n   */\n  view?: ComponentType<any>;\n  /**\n   * @todo 待补充文档\n   */\n  transducers?: any;\n  /**\n   * @todo 待补充文档\n   */\n  filters?: FilterItem[];\n  /**\n   * @todo 待补充文档\n   */\n  autoruns?: AutorunItem[];\n  /**\n   * 配置 callbacks 可捕获引擎抛出的一些事件，例如 onNodeAdd、onResize 等\n   */\n  callbacks?: Callbacks;\n  /**\n   * 拖入容器时，自动带入 children 列表\n   */\n  initialChildren?: NodeData[] | ((target: IPublicModelSettingField) => NodeData[]);\n  /**\n   * @todo 待补充文档\n   */\n  isAbsoluteLayoutContainer?: boolean;\n  /**\n   * @todo 待补充文档\n   */\n  hideSelectTools?: boolean;\n\n  /**\n   * 样式 及 位置，handle上必须有明确的标识以便事件路由判断，或者主动设置事件独占模式\n   * NWSE 是交给引擎计算放置位置，ReactElement 必须自己控制初始位置\n   */\n  /**\n   * 用于配置设计器中组件 resize 操作工具的样式和内容\n   * - hover 时控制柄高亮\n   * - mousedown 时请求独占\n   * - dragstart 请求通用 resizing 控制 请求 hud 显示\n   * - drag 时 计算并设置效果，更新控制柄位置\n   */\n  getResizingHandlers?: (\n    currentNode: any,\n  ) => (\n    | Array<{\n      type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW';\n      content?: ReactElement;\n      propTarget?: string;\n      appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always';\n    }>\n    | ReactElement[]\n  );\n\n  /**\n   * Live Text Editing：如果 children 内容是纯文本，支持双击直接编辑\n   */\n  liveTextEditing?: LiveTextEditingConfig[];\n}\n\nexport interface Configure {\n  /**\n   * 属性面板配置\n   */\n  props?: ConfigureProp[];\n  /**\n   * 组件能力配置\n   */\n  component?: ConfigureComponent;\n  /**\n   * 通用扩展面板支持性配置\n   */\n  supports?: ConfigureSupport;\n  /**\n   * 高级特性配置\n   */\n  advanced?: Advanced;\n}\n\nexport interface Snippet {\n  /**\n   * 组件分类title\n   */\n  title?: string;\n  /**\n   * snippet 截图\n   */\n  screenshot?: string;\n  /**\n   * snippet 打标\n   *\n   * @deprecated 暂未使用\n   */\n  label?: string;\n  /**\n   * 待插入的 schema\n   */\n  schema?: NodeSchema;\n}\n\nexport interface ComponentDescription { // 组件描述协议，通过 npm 中的 exportName 对应到 package\n  componentName: string;\n  title: string;\n  description?: string;\n  docUrl: string;\n  screenshot: string;\n  icon?: string;\n  tags?: string[];\n  keywords?: string[];\n  devMode?: 'proCode' | 'lowCode';\n  npm: Npm;\n  props: Prop[];\n  configure: Configure;\n  snippets: Snippet[];\n  group: string;\n  category: string;\n  priority: number;\n}\n```\n\n#### 2.2.3 资产包协议\n\n##### 2.2.3.1 协议结构\n\n协议最顶层结构如下，包含 5 方面的描述内容：\n\n- version { String } 当前协议版本号\n- packages{ Array } 低代码编辑器中加载的资源列表\n- components { Array } 所有组件的描述协议列表\n- sort { Object } 用于描述组件面板中的 tab 和 category\n\n##### 2.2.3.2 version (A)\n\n定义当前协议 schema 的版本号；\n\n| 根属性名称 | 类型   | 说明       | 变量支持 | 默认值 |\n| ---------- | ------ | ---------- | -------- | ------ |\n| version    | String | 协议版本号 | -        | 1.0.0  |\n\n##### 2.2.3.3 packages (A)\n\n定义低代码编辑器中加载的资源列表，包含公共库和组件 (库) cdn 资源等；\n\n| 字段             | 字段描述                | 字段类型   | 备注                                                          |\n| --------------- | ---------------------- | --------  | ------------------------------------------------------------ |\n| packages[].title? (A)      | 资源标题             | String       | 资源标题                                               |\n| packages[].package (A)     | npm 包名             | String      | 组件资源唯一标识                                                |\n| packages[].version(A)      | npm 包版本号             | String   | 组件资源版本号                                                  |\n| packages[].library(A)      | 作为全局变量引用时的名称，用来定义全局变量名             | String   | 低代码引擎通过该字段获取组件实例         |\n| packages[].editUrls (A)        | 组件编辑态视图打包后的 CDN url 列表，包含 js 和 css     | Array\\<String\\>   | 低代码引擎编辑器会加载这些 url   |\n| packages[].urls (AA) | 组件渲染态视图打包后的 CDN url 列表，包含 js 和 css     | Array\\<String\\>   | 低代码引擎渲染模块会加载这些 url |\n\n描述举例：\n\n```json\n{\n  \"packages\": [\n    {\n      \"package\": \"moment\",\n      \"version\": \"2.24.0\",\n      \"urls\": [\n        \"https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js\"\n      ],\n      \"library\": \"moment\"\n    },\n    {\n      \"package\": \"lodash\",\n      \"library\": \"_\",\n      \"urls\": [\n        \"https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js\"\n      ]\n    },\n    {\n      \"title\": \"fusion 组件库\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.24.18\",\n      \"urls\": [\n        \"https://g.alicdn.com/code/lib/alifd__next/1.24.18/next.min.css\",\n        \"https://g.alicdn.com/code/lib/alifd__next/1.24.18/next-with-locales.min.js\"\n      ],\n      \"library\": \"Next\"\n    },\n    {\n      \"package\": \"@alilc/lowcode-materials\",\n      \"version\": \"1.0.0\",\n      \"library\": \"AlilcLowcodeMaterials\",\n      \"urls\": [\n        \"https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.0/dist/AlilcLowcodeMaterials.js\",\n        \"https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.0/dist/AlilcLowcodeMaterials.css\"\n      ],\n      \"editUrls\": [\n        \"https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.0/build/lowcode/view.js\",\n        \"https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.0/build/lowcode/view.css\"\n      ]\n    },\n    {\n      \"package\": \"@alifd/fusion-ui\",\n      \"version\": \"1.0.0\",\n      \"library\": \"AlifdFusionUi\",\n      \"urls\": [\n        \"https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.0/build/lowcode/view.js\",\n        \"https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.0/build/lowcode/view.css\"\n      ],\n      \"editUrls\": [\n        \"https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.0/build/lowcode/view.js\",\n        \"https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.0/build/lowcode/view.css\"\n      ]\n    }\n  ]\n}\n```\n\n##### 2.2.3.4 components (A)\n\n定义所有组件的描述协议列表，组件描述协议遵循本规范章节 2.2.2 的定义；\n\n##### 2.2.3.5 sort (A)\n\n定义组件列表分组\n\n| 根属性名称 | 类型   | 说明       | 变量支持 | 默认值 |\n| ---------- | ------ | ---------- | -------- | ------ |\n| sort.groupList  | String[] | 组件分组，用于组件面板 tab 展示 | -        | ['精选组件', '原子组件']  |\n| sort.categoryList  | String[] | 组件面板中同一个 tab 下的不同区间用 category 区分，category 的排序依照 categoryList 顺序排列 | -        | ['通用', '数据展示', '表格类', '表单类']  |\n\n##### 2.2.3.6 TypeScript 定义\n\n```TypeScript\nexport interface ComponentSort {\n  groupList?: String[]; // 用于描述组件面板的 tab 项及其排序，例如：[\"精选组件\", \"原子组件\"]\n  categoryList?: String[]; // 组件面板中同一个 tab 下的不同区间用 category 区分，category 的排序依照 categoryList 顺序排列；\n}\n\nexport interface Assets {\n  version: string; // 资产包协议版本号\n  packages?: Array<Package>; // 大包列表，external与package的概念相似，融合在一起\n  components: Array<ComponentDescription> | Array<RemoteComponentDescription>; // 所有组件的描述协议列表\n  componentList?: ComponentCategory[]; // 【待废弃】组件分类列表，用来描述物料面板\n  sort: ComponentSort; // 新增字段，用于描述组件面板中的 tab 和 category\n}\n\nexport interface RemoteComponentDescription {\n  exportName: string; // 组件描述导出名字，可以通过 window[exportName] 获取到组件描述的 Object 内容；\n  url: string; // 组件描述的资源链接；\n  package: { // 组件(库)的 npm 信息；\n    npm: string;\n  }\n}\n```\n\n## 3 物料规范 - 区块规范\n\n### 3.1 源码规范\n\n英文 block, 可复用的代码片段，每个区块对应一个 npm。\n\n#### 3.1.1 目录 (A)\n\n\n```html\nblock/\n  ├── build\n  │   ├── index.css              // 【编译生成】\n  │   ├── index.html             // 【编译生成】【必选】可直接预览文件\n  │   ├── index.js               // 【编译生成】\n  │   └── views                  // 【3A 编译生成】html2sketch\n  │       ├── block_view1.html   // 【3A 编译生成】给 sketch 用的 html\n  │       └── block_view1.png    // 【3A 编译生成】截图\n  ├── src                        // 【必选】区块源码\n  │   ├── index.jsx              // 【必选】入口\n  │   └── index.module.scss      // 【可选】如有样式请使用 CSS Modules 避免冲突\n  ├── README.md                  // 【可选】无格式要求\n  └── package.json               // 【必选】\n```\n\n\n#### 3.1.2 package.json (A)\n\n\n```json\n{\n  \"name\": \"\",\n  \"version\": \"\",\n  \"description\": \"\",\n  \"files\": [\"src/\", \"build/\", \"screenshot.png\"],\n  \"blockConfig\": {\n    \"name\": \"user-landing\",\n    \"title\": \"用户欢迎信息\",\n    \"category\": \"form\",\n    \"screenshot\": \"https://unpkg.com/@icedesign/user-landing-block/screenshot.png\"\n  }\n}\n```\n\n#### 3.1.3 html2sketch (3A)\n\n##### 3.1.3.1 package.json 内 blockConfig 结构\n\n```json\n{\n  \"blockConfig\": {\n    \"name\": \"user-landing\",\n    \"title\": \"用户欢迎信息\",\n    \"category\": \"form\",\n    \"screenshot\": \"https://unpkg.com/@icedesign/user-landing-block/screenshot.png\",\n    \"views\": [{                                            // 区块视图，配置此项后会进入 fusion cool\n        \"title\": \"视图 1 标题\",                               // 区块视图标题\n        \"props\": {                                         // 区块支持的 props\n          \"type\": \"primary\"\n        },\n        \"screenshot\": \"build/views/block_view1.png\",       // 【编译自动填充】视图截图，会在 build 时自动生成\n        \"html\": \"build/views/block_view1.html\",            // 【编译自动填充】视图渲染后 html 结构，会在 build 时自动生成\n    },{\n        \"title\": \"视图 2 标题\",                               // 区块视图标题\n        \"props\": {                                         // 区块支持的 props\n          \"type\": \"sencondary\"\n        },\n        \"screenshot\": \"build/views/block_view2.png\",       // 【编译自动填充】视图截图，会在 build 时自动生成\n        \"html\": \"build/views/block_view2.html\",            // 【编译自动填充】视图渲染后 html 结构，会在 build 时自动生成\n    }]\n  }\n}\n```\n\n### 3.2 低代码规范\n\n由业务组件、布局组件进行嵌套组合而成。不对外提供可配置的属性。可通过**区块容器组件**的包裹，实现容器内部具备有完整的样式、事件、生命周期管理、状态管理、数据流转机制。能独立存在和运行，可实现跨页面、跨应用的快速复用，保障功能和数据的正常。\n\n| 根属性描述     | 说明                               | 类型   |\n| -------------- | ---------------------------------- | ------ |\n| version        | 协议版本号                         | String |\n| componentsMap  | 描述组件映射关系的集合             | Array  |\n| componentsTree | 区块组件树描述，顶层不限定组件类型 | Array  |\n| utils          | 工具类扩展映射关系                 | Array  |\n| i18n           | 国际化语料                         | Object |\n\n\n描述举例 1：\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [{ }],\n  \"componentsTree\": [{                   // 区块组件树，顶层由区块容器组件包裹；\n    \"componentName\": \"Block\",            // 区块容器组件名\n    \"fileName\": \"block1\",                // 区块容器 1\n    \"props\": {},\n    \"css\": \"body {font-size: 12px;}\",\n    \"state\": {\n      \"name\": \"lucy\"\n    },\n    \"children\": [{\n      \"componentName\": \"Div\",\n      \"props\": {\n        \"className\": \"className1\"\n      },\n      \"children\": [{\n        \"componentName\": \"Button\",\n        \"props\": {\n          \"text\": \"点击弹出我的姓名\",\n          \"onClick\": {\n            \"type\": \"JSFunction\",\n            \"value\": \"function(e){\\\n              alert(this.state.name)\\\n            }\"\n          }\n        }\n      }]\n    }]\n  }],\n  \"i18n\": { }\n}\n```\n\n描述举例 2：\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [{ }],\n  \"componentsTree\": [{                         //区块组件树，由普通组件描述组合而成；无区块容器\n    \"componentName\": \"Input\",\n    \"props\": {\n       \"placeholder\": \"请输入搜索关键词\"\n    },\n  }, {\n    \"componentName\": \"Button\",\n    \"props\": {\n      \"text\": \"搜索\",\n      \"onClick\": {\n        \"type\": \"JSFunction\",\n        \"value\": \"\\\n        // some comments \\\n        function(e){\\\n          //...\\\n        }\"\n      }\n    }\n  }],\n  \"i18n\": { }\n}\n```\n\n## 4 物料规范 - 模板规范\n\n### 4.1 源码规范\n\n#### 4.1.1 目录规范（A）\n\n与标准源码 build-scripts 对齐\n\n```html\n├── META/                          # 低代码元数据信息，用于多分支冲突解决、数据回滚等功能\n├── build\n│   ├── index.css                  # 【编译生成】\n│   ├── index.html                 # 【编译生成】【必选】可直接预览文件\n│   ├── index.js                   # 【编译生成】\n│   └── views                      # 【3A 编译生成】html2sketch\n│       ├── page1.html             # 【3A 编译生成】给 sketch 用的 html\n│       └── page1.png              # 【3A 编译生成】截图\n├── public/                        # 静态文件，构建时会 copy 到 build/ 目录\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/\n│   ├── components/                # 应用内的低代码业务组件\n│   │   └── GuideComponent/\n│   │       ├── index.js           # 组件入口\n│   │       ├── components.js      # 组件依赖的其他组件\n│   │       ├── schema.js          # schema 描述\n│   │       └── index.scss         # css 样式\n│   ├── pages/                     # 页面\n│   │   └── HomePage/              # Home 页面\n│   │       ├── index.js           # 页面入口\n│   │       └── index.scss         # css 样式\n│   ├── layouts/\n│   │   └── BasicLayout/           # layout 组件名称\n│   │       ├── index.js           # layout 入口\n│   │       ├── components.js      # layout 组件依赖的其他组件\n│   │       ├── schema.js          # layout schema 描述\n│   │       └── index.scss         # layout css 样式\n│   ├── config/                    # 配置信息\n│   │   ├── components.js          # 应用上下文所有组件\n│   │   ├── routes.js              # 页面路由列表\n│   │   └── constants.js           # 全局常量定义\n│   │   └── app.js                 # 应用配置文件\n│   ├── utils/                     # 工具库\n│   │   └── index.js               # 应用第三方扩展函数\n│   ├── stores/                    # [可选] 全局状态管理\n│   │   └── user.js\n│   ├── locales/                   # [可选] 国际化资源\n│   │   ├── en-US\n│   │   └── zh-CN\n│   ├── global.scss                # 全局样式\n│   └── index.jsx                  # 应用入口脚本，依赖 config/routes.js 的路由配置动态生成路由；\n├── webpack.config.js              # 项目工程配置，包含插件配置及自定义 `webpack` 配置等\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.js\n├── .gitignore\n├── .stylelintignore\n└── .stylelintrc.js\n```\n\n\n##### 入口文件\n\n(/src/index.jsx)\n\n```javascript\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { hot } from 'react-hot-loader/root';\nimport pkg from '../package.json';\nimport router from './router';\nimport './index.scss';\nconst App = hot(router);\n\nReactDOM.render(<App />, document.getElementById(pkg.config && pkg.config.targetRootID || 'root'));\n```\n\n##### 应用参数配置文件\n\n(/src/config/app.js)\n\n- 支持配置路由方式：historyMode\n   - 支持 2 种路由方式：\n      - 浏览器路由：browser\n      - 哈希路由：hash\n   - 支持透传路由产生的参数到所有组件的上下文 this 对象上\n      - history 对象：this.history\n      - location 对象：this.location\n         - 支持内置 query 参数的解析：this.location.query\n      - match 对象：this.match\n- 支持渲染的目标节点 ID：targetRootID\n- 支持配置应用的 fusion 主题风格：theme\n- 支持配置 layout 的组件名称和属性配置：layout\n- 支持配置渲染模块版本号：sdkVersion\n- 支持配置固定依赖组件列表：compDependencies\n\n\n```javascript\nexport default {\n  \"sdkVersion\": \"1.0.3\",\n  \"historyMode\": \"hash\",           // 浏览器路由：browser  哈希路由：hash\n  \"targetRootID\": \"ice-container\",\n  \"layout\": {\n    \"componentName\": \"BasicLayout\",\n    \"props\": {},\n  },\n  \"theme\": {\n    \"package\": \"@alife/theme-fusion\",\n    \"version\": \"^0.1.0\"\n  },\n  \"compDependencies\": []\n}\n```\n\n##### 应用扩展配置规范：\n\n(/src/utils/index.js)\n\n- 支持 npm 包第三方扩展；\n- 支持应用范围的自定义扩展函数；\n\n\n```javascript\nimport { Message, Dialog } from '@alifd/next';\nimport moment from 'moment';\n\nexport default {\n  Message,                // npm 包依赖\n  Dialog,\n  moment,\n  xxx: function(item) {   // 自定义函数\n    return ...\n  }\n}\n```\n\n##### 应用常量配置\n\n(/src/config/constants.js)\n\n```javascript\nexport default {\n  \"ISIDE\": false\n}\n```\n\n##### 应用样式配置\n\n(/src/global.scss)\n\n```css\na {\n  color: #2077ff;\n  text-decoration: none;\n}\n\n.transparent {\n  opacity: 0;\n}\n```\n\n#### 4.1.2 html2sketch (AAA)\n\n##### 4.1.2.1 package.json 内 scaffoldConfig 结构\n\n```json\n{\n  \"scaffoldConfig\": {\n    \"name\": \"user-landing\",\n    \"title\": \"用户欢迎信息\",\n    \"category\": \"form\",\n    \"screenshot\": \"https://unpkg.com/@icedesign/user-landing-block/screenshot.png\",\n    \"views\": [{                                    // 模板视图，配置此项后会进入 fusion cool\n      \"title\": \"视图 1 标题\",                       // 模板视图标题\n      \"path\": \"#/dashboard/monitor\",               // 读取路由列表生成，hash 路由必须加#\n      \"screenshot\": \"build/views/page0.png\",       // 【编译自动填充】视图截图，会在 build 时自动生成\n      \"html\": \"build/views/page0.html\",            // 【编译自动填充】视图渲染后 html 结构，会在 build 时自动生成\n    },{\n      \"title\": \"视图 2 标题\",                       // 区块视图标题\n      \"path\": \"#/dashboard/list\",                  // 读取路由列表生成，hash 路由必须加#\n      \"screenshot\": \"build/views/page1.png\",       // 【编译自动填充】视图截图，会在 build 时自动生成\n      \"html\": \"build/views/page1.html\",            // 【编译自动填充】视图渲染后 html 结构，会在 build 时自动生成\n    }]\n  }\n}\n```\n"
  },
  {
    "path": "docs/docs/video/index.md",
    "content": "# 官方视频\n- [2023/11/20 云栖大会｜阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Ku4y1w7Zr)\n- [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC)\n\n# 社区视频\n- [低代码从入门到实战：低代码引擎实践](https://www.bilibili.com/video/BV1aP4y1Q7Xa/)\n- [低代码技术在研发团队的应用模式](https://www.bilibili.com/video/BV1L14y1Y72J/)\n- [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/)\n- [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/)\n- [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/)\n- [阿里低代码引擎项目实战 (4)-自定义插件 - 页面管理](https://www.bilibili.com/video/BV17a411i73f/)\n- [阿里低代码引擎项目实战 (4)-用户登录](https://www.bilibili.com/video/BV1Wu411e7EQ/)\n- [【有翻车】阿里低代码引擎项目实战 (5)-表单回显](https://www.bilibili.com/video/BV1UY4y1v7D7/)\n- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 后端](https://www.bilibili.com/video/BV1uZ4y1U7Ly/)\n- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 前端](https://www.bilibili.com/video/BV1Yq4y1a74P/)\n- [阿里低代码引擎项目实战 (7)-自定义插件 - 页面管理 (完结)](https://www.bilibili.com/video/BV13Y4y1e7EV/)\n"
  },
  {
    "path": "docs/docusaurus.config.js",
    "content": "/* eslint-disable @typescript-eslint/no-require-imports */\n// Note: type annotations allow type checking and IDEs autocompletion\n\nconst lightCodeTheme = require('prism-react-renderer/themes/github');\nconst darkCodeTheme = require('prism-react-renderer/themes/dracula');\nconst navbar = require('./config/navbar');\n\n/** @type {import('@docusaurus/types').Config} */\nconst config = {\n  title: 'Low-Code Engine',\n  tagline: 'Low-Code Engine is awesome!',\n  url: 'https://lowcode-engine.cn',\n  baseUrl: '/site/',\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n  favicon:\n    'https://img.alicdn.com/imgextra/i2/O1CN01TNJDDg20pKniPOkN4_!!6000000006898-2-tps-66-78.png',\n\n  organizationName: 'alibaba', // Usually your GitHub org/user name.\n  projectName: 'lowcode-engine', // Usually your repo name.\n\n  i18n: {\n    defaultLocale: 'zh-Hans',\n    locales: ['zh-Hans'],\n  },\n\n  plugins: [\n    [\n      '@docusaurus/plugin-content-docs',\n      {\n        id: 'community',\n        path: 'community',\n        routeBasePath: 'community',\n        sidebarPath: require.resolve('./config/sidebarsCommunity.js'),\n      },\n    ],\n  ],\n\n  presets: [\n    [\n      'classic',\n      ({\n        docs: {\n          sidebarPath: require.resolve('./config/sidebars.js'),\n          // lastVersion: 'current',\n          editUrl:\n            'https://github.com/alibaba/lowcode-engine/tree/develop/docs/',\n        },\n        theme: {\n          customCss: require.resolve('./src/css/custom.css'),\n        },\n      }),\n    ],\n  ],\n\n  themeConfig:\n    ({\n      docs: {\n        sidebar: {\n          hideable: true,\n        },\n      },\n      navbar,\n      footer: {\n        // style: 'dark',\n        copyright: `Copyright © ${new Date().getFullYear()} 阿里巴巴集团, Inc. Built with Docusaurus.`,\n      },\n      // 主题切换\n      prism: {\n        theme: lightCodeTheme,\n        darkTheme: darkCodeTheme,\n      },\n      // 语雀文档导出的图片，会进行 referrer 校验，这里设置关闭，不然加载不了语雀的图片\n      metadata: [{ name: 'referrer', content: 'no-referrer' }],\n      tableOfContents: {\n        minHeadingLevel: 2,\n        maxHeadingLevel: 6,\n      },\n    }),\n\n  themes: [\n    [\n      require.resolve('@easyops-cn/docusaurus-search-local'),\n      {\n        hashed: true,\n        // For Docs using Chinese, The `language` is recommended to set to:\n        // ```\n        language: ['en', 'zh'],\n        // ```\n      },\n    ],\n  ],\n};\n\nmodule.exports = config;\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-engine-docs\",\n  \"version\": \"1.2.31\",\n  \"description\": \"低代码引擎版本化文档\",\n  \"license\": \"MIT\",\n  \"files\": [\n    \"build\"\n  ],\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start --host 0.0.0.0\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\",\n    \"typecheck\": \"tsc\",\n    \"syncOss\": \"node ./scripts/sync-oss.js\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"^2.2.0\",\n    \"@docusaurus/preset-classic\": \"^2.2.0\",\n    \"@easyops-cn/docusaurus-search-local\": \"^0.32.0\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"axios\": \"^1.1.3\",\n    \"clsx\": \"^1.2.1\",\n    \"fs-extra\": \"^10.1.0\",\n    \"prism-react-renderer\": \"^1.3.5\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"^2.2.0\",\n    \"@tsconfig/docusaurus\": \"^1.0.5\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=16.14\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\"\n}\n"
  },
  {
    "path": "docs/scripts/getDocsFromDir.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst glob = require('glob');\nconst matter = require('gray-matter');\n\nmodule.exports = function getDocsFromDir(dir, cateList) {\n  // docs/\n  const baseDir = path.join(__dirname, '../docs/');\n  const docsDir = path.join(baseDir, dir);\n\n  function isNil(value) {\n    return value === undefined || value === null;\n  }\n\n  function getMarkdownOrder(filepath) {\n    const { data } = matter(fs.readFileSync(filepath, 'utf-8'));\n    const { sidebar_position } = data || {};\n    return isNil(sidebar_position) ? 100 : sidebar_position;\n  }\n\n  const docs = glob.sync('*.md?(x)', {\n    cwd: docsDir,\n    // ignore: 'README.md',\n  });\n\n  const result = docs\n    .filter((doc) => !/^index.md(x)?$/.test(doc))\n    .map((doc) => {\n      return path.join(docsDir, doc);\n    })\n    .sort((a, b) => {\n      const orderA = getMarkdownOrder(a);\n      const orderB = getMarkdownOrder(b);\n\n      return orderA - orderB;\n    })\n    .map((filepath) => {\n      // /Users/xxx/site/docs/guide/basic/router.md => guide/basic/router\n      const id = path\n        .relative(baseDir, filepath)\n        .replace(/\\\\/g, '/')\n        .replace(/\\.mdx?/, '');\n      return id;\n    });\n\n  (cateList || []).forEach((item) => {\n    const { dir, subCategory, ...otherConfig } = item;\n    const indexList = glob.sync('index.md?(x)', {\n      cwd: path.join(baseDir, dir),\n    });\n    if (indexList.length > 0) {\n      otherConfig.link = {\n        type: 'doc',\n        id: `${dir}/index`,\n      };\n    }\n    result.push({\n      type: 'category',\n      collapsed: false,\n      ...otherConfig,\n      items: getDocsFromDir(dir, subCategory),\n    });\n  });\n\n  return result;\n};\n"
  },
  {
    "path": "docs/scripts/sync-oss.js",
    "content": "#!/usr/bin/env node\nconst http = require('http');\nconst package = require('../package.json');\nconst { version, name } = package;\nconst options = {\n  method: 'PUT',\n  hostname: 'uipaas-node.alibaba-inc.com',\n  path: '/staticAssets/cdn/packages',\n  headers: {\n    'Content-Type': 'application/json',\n    Cookie: 'locale=en-us',\n  },\n  maxRedirects: 20,\n};\n\nconst onResponse = function (res) {\n  const chunks = [];\n  res.on('data', (chunk) => {\n    chunks.push(chunk);\n  });\n\n  res.on('end', () => {\n    const body = Buffer.concat(chunks);\n    console.table(JSON.stringify(JSON.parse(body.toString()), null, 2));\n  });\n\n  res.on('error', (error) => {\n    console.error(error);\n  });\n};\n\nconst req = http.request(options, onResponse);\n\nconst postData = JSON.stringify({\n  packages: [\n    {\n      packageName: name,\n      version,\n    },\n  ],\n  // 可以发布指定源的 npm 包，默认公网 npm\n  useTnpm: true,\n});\n\nreq.write(postData);\n\nreq.end();\n"
  },
  {
    "path": "docs/src/css/custom.css",
    "content": "\n/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n  --ifm-font-size-base: 14px;\n  --ifm-color-primary: #0089ff;\n  --ifm-color-primary-dark: #007be6;\n  --ifm-color-primary-darker: #0074d9;\n  --ifm-color-primary-darkest: #0060b3;\n  --ifm-color-primary-light: #1a95ff;\n  --ifm-color-primary-lighter: #269bff;\n  --ifm-color-primary-lightest: #4dacff;\n  --ifm-code-font-size: 95%;\n  --ifm-container-width-xl: 2000px;\n  --aa-search-input-height: 32px;\n  --ifm-font-family-base: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont,\n  'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji';\n  --ifm-font-family-monospace: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n  --ifm-global-spacing: 1.5rem;\n  --ifm-line-height-base: 1.85;\n  /* --ifm-font-color-base: #333; */\n}\n\n.header-github-link::before {\n  content: '';\n  width: 24px;\n  height: 24px;\n  display: flex;\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\")\n    no-repeat;\n}\n\n[data-theme='dark'] .header-github-link::before {\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\")\n    no-repeat;\n}\n\n.docusaurus-highlight-code-line {\n  background-color: rgba(0, 0, 0, 0.1);\n  display: block;\n  margin: 0 calc(-1 * var(--ifm-pre-padding));\n  padding: 0 var(--ifm-pre-padding);\n}\n\nhtml[data-theme='dark'] .docusaurus-highlight-code-line {\n  background-color: rgba(0, 0, 0, 0.3);\n}\n\n.navbar__logo,\n.navbar__search {\n  margin-right: 2rem;\n}\n\n.hero {\n  padding: 5rem 0 !important;\n  box-shadow: var(--ifm-navbar-shadow);\n}\n\n.homepage-content {\n  max-width: 1400px;\n  margin: 0 auto;\n}\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n.hero__title{\n  font-size: 2.4rem;\n  background: -webkit-linear-gradient(315deg,#0089ff 25%,#30e724);\n  background-clip: text;\n  -webkit-background-clip: text;\n  -webkit-text-fill-color: transparent;\n  display: inline-block;\n}\n\n.pagination-nav__link {\n  padding: 0.5rem 1.5rem;\n}\n\n.markdown h1:first-child {\n  --ifm-h1-font-size: 2rem;\n}\n\n.markdown > h2{\n  --ifm-h2-font-size: 1.5rem;\n}\n\n.markdown > h3{\n  --ifm-h3-font-size: 1.25rem;\n}\n\n.markdown img {\n  box-shadow: 9px 8px 10px 0px rgb(0 0 0 / 15%);\n}\n"
  },
  {
    "path": "docs/src/pages/index-old.tsx",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport Link from '@docusaurus/Link';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport Layout from '@theme/Layout';\n\nimport styles from './index.module.css';\n\nfunction HomepageHeader() {\n  const { siteConfig } = useDocusaurusContext();\n  return (\n    <header className={clsx('hero hero--primary', styles.heroBanner)}>\n      <div className=\"container\">\n        <h1 className={styles.heroTitle}>{siteConfig.title}</h1>\n        <h2>欢迎光临 低代码引擎文档站</h2>\n        <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n        <div className={styles.buttons}>\n          <Link\n            className=\"button button--secondary button--lg\"\n            to=\"/docs/guide/quickStart/start\"\n          >\n            快速开始\n          </Link>\n        </div>\n      </div>\n    </header>\n  );\n}\n\nexport default function Home(): JSX.Element {\n  const { siteConfig } = useDocusaurusContext();\n  return (\n    <Layout\n      title={`${siteConfig.title}`}\n      description=\"\"\n    >\n      <HomepageHeader />\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "docs/src/pages/index.module.css",
    "content": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n  height: 60rem;\n}\n\n.heroTitle {\n  color: #30e724;\n  font-size: 3rem;\n}\n\n@media screen and (max-width: 996px) {\n  .heroBanner {\n    padding: 2rem;\n  }\n}\n\n.buttons {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}"
  },
  {
    "path": "docs/src/pages/index.tsx",
    "content": "import React from 'react';\nimport BrowserOnly from '@docusaurus/BrowserOnly';\n\nexport default function ToIndex(): JSX.Element {\n  return (\n    <BrowserOnly>\n      {() => {\n        /**\n         * 跳转到首页\n         */\n        window.location.href = '/index';\n        return <></>;\n      }}\n    </BrowserOnly>\n  );\n}\n"
  },
  {
    "path": "docs/src/pages/markdown-page.md",
    "content": "<!-- ---\ntitle: Markdown page example\n--- -->\n\n# 文档能力介绍\n\n这是一个使用 Markdown 编写的任意页面，访问地址为 /markdown-page\n\nProduct Docs Capability Introduction.\n\n## 功能\n\n- ✅ 支持本地离线搜搜\n- ✅ 版本化文档管理\n- ✅ 离线静态部署\n"
  },
  {
    "path": "docs/tsconfig.json",
    "content": "{\n  // This file is not used in compilation. It is here just for a nice editor experience.\n  \"extends\": \"@tsconfig/docusaurus/tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\"\n  }\n}\n"
  },
  {
    "path": "index.ts",
    "content": "import renderer from './packages/react-simulator-renderer/src/renderer';\n\nif (typeof window !== 'undefined') {\n  (window as any).SimulatorRenderer = renderer;\n}\n\nexport default renderer;\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"lerna\": \"4.0.0\",\n  \"version\": \"1.3.2\",\n  \"npmClient\": \"yarn\",\n  \"useWorkspaces\": true,\n  \"packages\": [\n    \"packages/*\"\n  ],\n  \"command\": {\n    \"bootstrap\": {\n      \"npmClientArgs\": [\n        \"--no-package-lock\"\n      ]\n    },\n    \"version\": {\n      \"allowBranch\": [\n        \"master\",\n        \"main\",\n        \"release/*\",\n        \"daily/*\",\n        \"refactor/*\"\n      ]\n    },\n    \"publish\": {\n      \"npmClient\": \"npm\",\n      \"verifyRegistry\": false,\n      \"verifyAccess\": false,\n      \"ignoreChanges\": [\n        \"**/*.md\",\n        \"**/test/**\"\n      ],\n      \"message\": \"chore(release): publish %v\",\n      \"conventionalCommits\": true\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/.gitignore",
    "content": "# project custom\nbuild\nes\ndist\noutput\npackage-lock.json\nyarn.lock\ndeploy-space/packages\ndeploy-space/.env\n/demo/\n/demo-output*/\n/generated/\n\n# IDE\n.vscode\n.idea\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\nlib\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# mac config files\n.DS_Store\n\n# codealike\ncodealike.json\n.node\n\n# def publish\n.package\n\n# types\n/types\n\n# backup files\n*.bak\n\n# tests\ntests/fixtures/**/actual\n\n\n\n"
  },
  {
    "path": "modules/code-generator/.prettierrc.js",
    "content": "module.exports = {\n  printWidth: 100,\n  tabWidth: 2,\n  semi: true,\n  singleQuote: true,\n  trailingComma: 'all',\n};\n"
  },
  {
    "path": "modules/code-generator/.versionrc",
    "content": "{\n  \"releaseCommitMessageFormat\": \"chore(release): code-generator - {{currentTag}}\"\n}"
  },
  {
    "path": "modules/code-generator/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n### [1.0.7-beta.2](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.3...@alilc/lowcode-code-generator@1.0.7-beta.2) (2022-11-24)\n\n### Bug Fixes\n\n* 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 __$evalArray 的问题 ([3b9b177](https://github.com/alibaba/lowcode-engine/commit/3b9b177b052169cd0c1078cf8b488f04cb374dac))\n* 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题 ([2cf788c](https://github.com/alibaba/lowcode-engine/commit/2cf788c1716ae63fef20004348c59a5a65c6b3d2)), closes [#288](https://github.com/alibaba/lowcode-engine/issues/288)\n* 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 __$eval 中用到 window 的问题 ([ce531ae](https://github.com/alibaba/lowcode-engine/commit/ce531aeb457711fac92d828b431cfc3d643b3682))\n* add support for jsx expression ([453e069](https://github.com/alibaba/lowcode-engine/commit/453e0699ece06d98e59227e23248baf1de4082aa))\n* 修复生成的 icejs 项目不支持 constants 的问题, fixes [#1259](https://github.com/alibaba/lowcode-engine/issues/1259) ([a079fbc](https://github.com/alibaba/lowcode-engine/commit/a079fbc256f8275e8a69eb6d8abb6f6b08179578))\n* 修正 react 框架出码中在严格模式对 methods 和 context 的处理 ([b1a6100](https://github.com/alibaba/lowcode-engine/commit/b1a61006bba4292790899c7c49c9c611a9384472))\n### [1.0.7-beta.1](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.7-beta.0...@alilc/lowcode-code-generator@1.0.7-beta.1) (2022-10-26)\n\n\n### Bug Fixes\n\n* fix empty string lost when generate variable ([2cf74cd](https://github.com/alibaba/lowcode-engine/commit/2cf74cd04b4f48a3501d37329d39784f6964366a))\n\n### [1.0.7-beta.0](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.6-beta.0...@alilc/lowcode-code-generator@1.0.7-beta.0) (2022-10-25)\n\n### [1.0.6-beta.0](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.3...@alilc/lowcode-code-generator@1.0.6-beta.0) (2022-10-25)\n\n\n### Features\n\n* 🎸 设计态支持数据源引擎配置 ([04631f8](https://github.com/alibaba/lowcode-engine/commit/04631f813782dbf6d175f51c40ccc75ca4c099d2))\n* 大纲树支持节点过滤 ([f30db20](https://github.com/alibaba/lowcode-engine/commit/f30db20606f5f2fdac0017305b1dda7ab2258c4b))\n* 为 renderer 追加 displayName，以支持后续的反射功能 ([6399cce](https://github.com/alibaba/lowcode-engine/commit/6399cce05ae494dac6facf4366949b0b97576079))\n* 资产包支持一个package从另一个package异步导出 ([#1150](https://github.com/alibaba/lowcode-engine/issues/1150)) ([6b78157](https://github.com/alibaba/lowcode-engine/commit/6b78157b211d6eabf60297b9ce980a3e10cc8272))\n* add availableActions for ComponentMeta ([de1f60b](https://github.com/alibaba/lowcode-engine/commit/de1f60bbee157267e2c2212df1077cc49ce506f4))\n* add code coverage action ([ed3ddcf](https://github.com/alibaba/lowcode-engine/commit/ed3ddcf5c942a8e78e1f247e41d4159da97e75a8))\n* add componentMeta getter for setingPropEntry ([2f8b954](https://github.com/alibaba/lowcode-engine/commit/2f8b9545de0210260001a832b52f608238ac4191))\n* add expanded to shell SettingPropEntry ([534e294](https://github.com/alibaba/lowcode-engine/commit/534e29429d445d97c71d95d4c4e492868527bb6b))\n* add flag createIfNode for ShellNode#getProp ([152a24d](https://github.com/alibaba/lowcode-engine/commit/152a24d65528d0a3b7990c9aa87e6d8d09aa9b2a))\n* add getComponentsMap() for DocumentModel ([f956645](https://github.com/alibaba/lowcode-engine/commit/f9566454ef83eb4c48b68d63a766c3d0ff927c73))\n* add getExtraPropValue setExtraPropValue to shell SettingPropEntry ([70e7c1c](https://github.com/alibaba/lowcode-engine/commit/70e7c1c2e8998e80d58447759efdf651105724a9))\n* add id setter for DocumentModel ([941ae05](https://github.com/alibaba/lowcode-engine/commit/941ae0592586334694c48197aaa6692d49cefbce))\n* add importSchema event for documentModel ([4b8ec09](https://github.com/alibaba/lowcode-engine/commit/4b8ec09e86e3950a9d4066c28e681a59273b4c93))\n* add isGroup & items to shell SettingPropEntry ([7b76ff3](https://github.com/alibaba/lowcode-engine/commit/7b76ff357e4e638454c31a9b1324fb68966ec522))\n* add mergeChldren API for shell node ([a47d4ee](https://github.com/alibaba/lowcode-engine/commit/a47d4eea28cf4479e3b3a2bd1d194a6433666825))\n* add onMountNode event for DocumentModel ([dcc247c](https://github.com/alibaba/lowcode-engine/commit/dcc247c7d54f6af2ed36d46bfd79c7eacf7bd604))\n* add renderer for simulatorHost ([1cfc8d6](https://github.com/alibaba/lowcode-engine/commit/1cfc8d668b8897ef3a53c11520312cc6d18338f9))\n* add script for synchronizing packages to intranet registry ([b4f463e](https://github.com/alibaba/lowcode-engine/commit/b4f463e7d45f7b476de04bd4d98ad9f74d53cf13))\n* add scrollToNode for simulator host ([#1075](https://github.com/alibaba/lowcode-engine/issues/1075)) ([0bcd9ff](https://github.com/alibaba/lowcode-engine/commit/0bcd9ff78227aeddaf2fdc22d10fbd662fed91d3))\n* add setVisible for Node ([ba90327](https://github.com/alibaba/lowcode-engine/commit/ba90327eac0f5f82f6349bb9a7684bf51259e9c9))\n* add showArea & hideArea method for skeleton ([8f6b53e](https://github.com/alibaba/lowcode-engine/commit/8f6b53e67d89ee7af754132f0994a759522b3821))\n* add slotNode for shell prop ([d9a44c5](https://github.com/alibaba/lowcode-engine/commit/d9a44c5de7861e9180567b4afb787e381cefac61))\n* add some features ([18d1a4f](https://github.com/alibaba/lowcode-engine/commit/18d1a4fe1d952bcd4715e693def09fee94da49a5))\n* add some necessary methods and attributes ([4fd7f27](https://github.com/alibaba/lowcode-engine/commit/4fd7f27f8eb33b66324ede279b412940fc1f7032))\n* add some params for onDragstart & onDrag & onDragend ([d1c9838](https://github.com/alibaba/lowcode-engine/commit/d1c9838343ba1bdd4c02c1cfbf1f920dd8c87e7d))\n* add top attrbute for Shell SettingPropEntry ([51aca3d](https://github.com/alibaba/lowcode-engine/commit/51aca3d330b6483c05b71867f1b362a9f5db6cfe))\n* added lowcode engine standard specs ([f25feba](https://github.com/alibaba/lowcode-engine/commit/f25feba63f181efa83f1a8dff530e1c39ab1b34c))\n* added lowcode engine standard specs ([57df803](https://github.com/alibaba/lowcode-engine/commit/57df803179ca9cec4e8ab1dac1be577175732e65))\n* added thisRequiredInJSE API to control whether JSExpression expression access context must use this ([#702](https://github.com/alibaba/lowcode-engine/issues/702)) ([da7f77e](https://github.com/alibaba/lowcode-engine/commit/da7f77ee91b3bf441a4a57614872df32d6a1d041))\n* assetLoader loda scripts with async=false ([f6ad4a1](https://github.com/alibaba/lowcode-engine/commit/f6ad4a157df8c0ff7db327f4770f454998693d9a))\n* change loop sertter config, set defaultValue prop to JsonSetter ([aa6b9c8](https://github.com/alibaba/lowcode-engine/commit/aa6b9c8f7a5353771af9f46216310f044e57c533))\n* cp dist files of simulator-renderer to that of engine ([03c5397](https://github.com/alibaba/lowcode-engine/commit/03c53971df6de8c35620fd77743ac4f57a82d323))\n* export nodeChildrenSymbol && remove some unnecessary editor.set ([e83adce](https://github.com/alibaba/lowcode-engine/commit/e83adcee815eea73b6b1ed4f43f4d684c11818ca))\n* fix render-core leaf hoc component condition config should get from leaf exportSchema fn ([85704c3](https://github.com/alibaba/lowcode-engine/commit/85704c36946191a1b88db789cfac59e9d027a371))\n* low-code components support lifecycle and function execution ([176583f](https://github.com/alibaba/lowcode-engine/commit/176583f48af573d30c0d2c36faa3d901b0541c06))\n* **material-parser:** check module before install it; fix default value issue in ts parser ([fc452f7](https://github.com/alibaba/lowcode-engine/commit/fc452f7166f02acfba6076c1a9425e6f5880b5f6))\n* modify the output method of rendering module parsing errors ([8255b79](https://github.com/alibaba/lowcode-engine/commit/8255b7945836ee5d25fae73913faa6d0af7b3ff3))\n* pass e to customizeIgnoreSelectors ([900b239](https://github.com/alibaba/lowcode-engine/commit/900b2394323e85f0dce5df83dfc773f96da23e24))\n* refine nesting drawer ([4c032d0](https://github.com/alibaba/lowcode-engine/commit/4c032d0d0ead9731c038bd62dccc4a7d96435183))\n* refine nesting drawer ([94a211e](https://github.com/alibaba/lowcode-engine/commit/94a211e2795f74721cfd2ae3ff38a1d3607e9cd0))\n* refine pop drawer ([abf8fae](https://github.com/alibaba/lowcode-engine/commit/abf8fae3ef4d62b5688362e1b98f1b508a207029))\n* requestHandlersMap should be optional ([ee7160e](https://github.com/alibaba/lowcode-engine/commit/ee7160ea3c625d421c07730ef51711b8f14392a0))\n* return unbind function for onChangeDetecting & onChangeSelection ([30267cb](https://github.com/alibaba/lowcode-engine/commit/30267cb173fca2cd80a61450b9f2fe2bceac0f06))\n* support for hiding settings tabs when there is only one item ([#669](https://github.com/alibaba/lowcode-engine/issues/669)) ([cbd95a1](https://github.com/alibaba/lowcode-engine/commit/cbd95a1778415406670f37507ce957af6b3ecd4a))\n* support for NotFoundComponent design state is optional ([#1013](https://github.com/alibaba/lowcode-engine/issues/1013)) ([d3c891e](https://github.com/alibaba/lowcode-engine/commit/d3c891e2a46d138e31c81a7f9b804a8240154df5))\n* support opening document with id ([3f7c0cd](https://github.com/alibaba/lowcode-engine/commit/3f7c0cd5191b7924f2630c58e6439f4d4a936ac9))\n* support SPA mode ([1f9150e](https://github.com/alibaba/lowcode-engine/commit/1f9150e4b260d522bd7cb31497069b700a1e8576))\n* sync utils/constants ([#506](https://github.com/alibaba/lowcode-engine/issues/506)) ([2871b5b](https://github.com/alibaba/lowcode-engine/commit/2871b5ba4c3dbf1ed76bf4d6359fb457190a9b22))\n* the tips when dragging a component from the component panel same with the moving component ([dbe0764](https://github.com/alibaba/lowcode-engine/commit/dbe0764ff4901450f03ca56b62167fbc87d2524a))\n\n\n### Bug Fixes\n\n* 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 __$evalArray 的问题 ([3b9b177](https://github.com/alibaba/lowcode-engine/commit/3b9b177b052169cd0c1078cf8b488f04cb374dac))\n* 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题 ([2cf788c](https://github.com/alibaba/lowcode-engine/commit/2cf788c1716ae63fef20004348c59a5a65c6b3d2)), closes [#288](https://github.com/alibaba/lowcode-engine/issues/288)\n* 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 __$eval 中用到 window 的问题 ([ce531ae](https://github.com/alibaba/lowcode-engine/commit/ce531aeb457711fac92d828b431cfc3d643b3682))\n* 🐛 修复数据源引擎请求处理器映射严格模式下被过滤的问题 ([75626d8](https://github.com/alibaba/lowcode-engine/commit/75626d877db017b8862b1d5e64d75f3af7ff667a))\n* 🐛 修正 i18n 里面的一个参数命名问题 ([20c6fca](https://github.com/alibaba/lowcode-engine/commit/20c6fca03e99b11fa5c257cbbda0d4d23f410090))\n* 新元素无法在大纲树拖拽 ([3d41fd5](https://github.com/alibaba/lowcode-engine/commit/3d41fd5d0783048a7cfb54c6f80d058856153d25))\n* 修复React17选中组件bug ([750d282](https://github.com/alibaba/lowcode-engine/commit/750d282c03a880204fefdef01e180510465b82f8))\n* 修正 react 框架出码中在严格模式对 methods 和 context 的处理 ([b1a6100](https://github.com/alibaba/lowcode-engine/commit/b1a61006bba4292790899c7c49c9c611a9384472))\n* 左侧抽屉固定模式层级不足 ([c657cee](https://github.com/alibaba/lowcode-engine/commit/c657cee0694e3126dee89588a2aa17c4e118f786))\n* add  lowcode-designer, lowcode-utils dependencies ([d250242](https://github.com/alibaba/lowcode-engine/commit/d2502427ca988881747a35bd8da49f024939b833))\n* add support for jsx expression ([1043ef8](https://github.com/alibaba/lowcode-engine/commit/1043ef82b1e9ceefc3b74fd21eb28e9a740bd1db))\n* addon-combine affect metadata unexpectedly ([fc5fbc6](https://github.com/alibaba/lowcode-engine/commit/fc5fbc63a04a32bc887754f32e74c76149d74b05))\n* adjust synchronize-order of packages ([81a7304](https://github.com/alibaba/lowcode-engine/commit/81a73049bd848524e1156761ded08ddf325863ba))\n* change typescript type export to export type ([50e4a03](https://github.com/alibaba/lowcode-engine/commit/50e4a03b7d810131ce413cc057b43d4a726f1ebe))\n* change typescript type export to export type ([573504b](https://github.com/alibaba/lowcode-engine/commit/573504b0e3537ca60d234ce2b2f3feedb323405e))\n* declare parameter appHelper for valid engine options ([058a842](https://github.com/alibaba/lowcode-engine/commit/058a84226af8ca19d8c7d63599d80d0cdf70281c))\n* defaultValue should be evaluated inspite of condition result is falsy, fixes [#1045](https://github.com/alibaba/lowcode-engine/issues/1045) ([fcfce3c](https://github.com/alibaba/lowcode-engine/commit/fcfce3cbeb5a53600c40aea07ffef19c9c9591c4))\n* delete the defaultValue configuration outside the loop ([acf7449](https://github.com/alibaba/lowcode-engine/commit/acf7449ca231d45e8ed7e1d9416817ea11b1266f))\n* delete unused typescript types ([63f5d2c](https://github.com/alibaba/lowcode-engine/commit/63f5d2ca3e0bda92898fd0df28c9500707812082))\n* delete unused typescript types ([2432aed](https://github.com/alibaba/lowcode-engine/commit/2432aed83d55407d2f8b5f94910ada7ea78bb59e))\n* designer/loadIncrementalAssets await Sequential ([#841](https://github.com/alibaba/lowcode-engine/issues/841)) ([8232424](https://github.com/alibaba/lowcode-engine/commit/823242469743d235923b3b946ec7d2db70887ead))\n* error thrown when triggering undo after save schema on SchemaPane ([9be46e7](https://github.com/alibaba/lowcode-engine/commit/9be46e7b34e3a40cbc489dbae4bfd0915c2090e3))\n* fallback focusNode to root if empty ([a9a118f](https://github.com/alibaba/lowcode-engine/commit/a9a118fe6e79080245c6eea42ed26772b7c784ca))\n* **filter:**  unique key prop warning ([3fe6e41](https://github.com/alibaba/lowcode-engine/commit/3fe6e41536cd3a9b9c7eaca5b353de4bd1f91b11))\n* **filter:**  unique key prop warning ([06e6920](https://github.com/alibaba/lowcode-engine/commit/06e6920602bdf21b6e1ffe5cfa3dfe4856e7c57e))\n* fix css resources with parameters not loading correctly ([f859752](https://github.com/alibaba/lowcode-engine/commit/f85975211814147d40ae5330a76cb21cb6c66916))\n* fix css resources with parameters not loading correctly ([9a5a04a](https://github.com/alibaba/lowcode-engine/commit/9a5a04ac9560fb6a51bf4e0ed8ea446381d39c35))\n* fix dataSource needs to be compatible due to empty schema ([98bc477](https://github.com/alibaba/lowcode-engine/commit/98bc477d80dbf7993f89befdb42762d78a55fb1b))\n* fix displayName spell mistake ([2b2bcbd](https://github.com/alibaba/lowcode-engine/commit/2b2bcbdaebde6a3ce974072f586386ef7ef3497c))\n* fix internal project.getSchema default stage is error ([0d40db2](https://github.com/alibaba/lowcode-engine/commit/0d40db2581f4fe5a9e22f763f21aec641e366c34))\n* fix lint issues for renderer-core/renderer/base ([d85437d](https://github.com/alibaba/lowcode-engine/commit/d85437d4af1043371e27dfde98cecf914b93a126))\n* fix lint issues for renderer-core/renderer/base ([4b59190](https://github.com/alibaba/lowcode-engine/commit/4b59190c7f9d518bc7efac44b7eeee73f1b5d177))\n* fix low-code component rendering problems: 1. thisRequiredInJSE does not take effect 2. jsx components cannot obtain source components ([5dd4625](https://github.com/alibaba/lowcode-engine/commit/5dd462544fbbbccfa97165f2bcfeed8629fab2a3))\n* fix material-spec demo ([438cccd](https://github.com/alibaba/lowcode-engine/commit/438cccd58e4341638070c1d8b2d4e78e4e20e3fb))\n* fix misused doc urls ([16a8857](https://github.com/alibaba/lowcode-engine/commit/16a88578634b9da2f04698df5ca5a5e69151bb97))\n* fix monitor utils incorrect assignment method ([bf280c6](https://github.com/alibaba/lowcode-engine/commit/bf280c6fa1e46d084fc8f20323164816fad4076f))\n* fix outline-pane invisible occasionally when dragging tree node ([031c7f2](https://github.com/alibaba/lowcode-engine/commit/031c7f25f10a6cfebfc7929c9226f4e4167a359f))\n* fix outline-tree initialization failed ([a2d5c6f](https://github.com/alibaba/lowcode-engine/commit/a2d5c6fd90ca0226bbbfea01a4b28c8b8d307a78))\n* fix render module state expression initialization exception ([5bd68ee](https://github.com/alibaba/lowcode-engine/commit/5bd68ee6b448fa58b022870b3f8175d8b77febde))\n* fix render module state expression initialization exception ([9c545cc](https://github.com/alibaba/lowcode-engine/commit/9c545cca6004f65e2f206ea001cefa3fa3cfa807))\n* fix setter hooks error ([8a3a0b8](https://github.com/alibaba/lowcode-engine/commit/8a3a0b824162e25a930711c6fef511b4b369e897))\n* fix test case failures of designer ([4b0521a](https://github.com/alibaba/lowcode-engine/commit/4b0521a47494f78e120f75021e0a076fb00ce53e))\n* Fix the conversion failure of some props expressions under Slot props of low-code components ([7db5461](https://github.com/alibaba/lowcode-engine/commit/7db5461706c739fac673b2466bc2fda7661242e4))\n* fix the leaf hoc component fails to monitor Node changes, and modify the logic for get node ([6ee6b07](https://github.com/alibaba/lowcode-engine/commit/6ee6b07a10ba4aac583def52d8ff1fa78d111d0b))\n* fix the leaf hoc component fails to monitor Node changes, and modify the logic for get node ([f400172](https://github.com/alibaba/lowcode-engine/commit/f4001728259047b09db75d76a8c3ef1e1bcb4e0a))\n* fix the problem that material.getComponentMetasMap returns the wrong result ([e02933c](https://github.com/alibaba/lowcode-engine/commit/e02933c18bc15519b2eba8ad946282502a509611))\n* Fix the rendering error caused by incorrect key value when configuring the loop ([1026763](https://github.com/alibaba/lowcode-engine/commit/1026763dc5a77d4395a1e86e5a0084ab4fb4230c))\n* fix the unit test failure problem caused by thisRequiredInJSE modification ([c2c59b7](https://github.com/alibaba/lowcode-engine/commit/c2c59b7ff72ba06156bbcdb952262739d6188209))\n* fix unnecessary props calculation ([f1fed75](https://github.com/alibaba/lowcode-engine/commit/f1fed75f39be8289ede1ec558b04428a69e25b5f))\n* fixed an issue where materials would be rendered multiple times ([9d187cc](https://github.com/alibaba/lowcode-engine/commit/9d187ccb7de55857e861d3fc881c610506872d03))\n* fixed an issue where materials would be rendered multiple times ([64cc328](https://github.com/alibaba/lowcode-engine/commit/64cc3283c15342151a8f93c46a276681f3575153))\n* fixed focusNodeSelector configuration not taking effect ([9beae9c](https://github.com/alibaba/lowcode-engine/commit/9beae9c3269901bf03a29033121c7d480571bce5))\n* fixed the issue that thisRequiredInJSE did not take effect in some scenarios ([7e5a919](https://github.com/alibaba/lowcode-engine/commit/7e5a919f9352397f11741fd911495996469c0256))\n* in ES require changed to import ([b4d7d6d](https://github.com/alibaba/lowcode-engine/commit/b4d7d6d8c290a335a2c1f60731d4417b23444941))\n* in ES require changed to import ([7c8cd36](https://github.com/alibaba/lowcode-engine/commit/7c8cd36a10a7caa61de31a15abd93ab8a97fbe08))\n* leaf should be type of ShellNode other than InnerNode ([5bb8cf5](https://github.com/alibaba/lowcode-engine/commit/5bb8cf5d12d38d70b69fa28deb2f8aa0afa9b9b9))\n* lowcode component exec lifecycle has error ([f99a47e](https://github.com/alibaba/lowcode-engine/commit/f99a47e502080134454795f5e361cfa4fba3f03b))\n* lowcode component leaf dont have export prop, exec leaf.export make error ([9d51dcd](https://github.com/alibaba/lowcode-engine/commit/9d51dcdae38850be0206861f2cae74ca68805c25))\n* missing engine options config info ([a79875c](https://github.com/alibaba/lowcode-engine/commit/a79875cf8698d3912b50526d97f6ac72e9a21fc9))\n* missing engine options config info ([9ccded0](https://github.com/alibaba/lowcode-engine/commit/9ccded006ef44cd538abaa140250e519243bf090))\n* npm run clean error in windows ([a176e9d](https://github.com/alibaba/lowcode-engine/commit/a176e9d245981fb5718c8d144f477202b3796be6))\n* project event listeners will not be invoked sometimes ([a0c772f](https://github.com/alibaba/lowcode-engine/commit/a0c772fb903cf5eb9e0b811b64bbe3846d4ba8ac))\n* project.exportSchema api lack stage param & setAssets should be a async fn ([0ea76a7](https://github.com/alibaba/lowcode-engine/commit/0ea76a746fac8ea8e7b999d42434c468c85d6372))\n* project.exportSchema should export componentsMap of all documents ([969a130](https://github.com/alibaba/lowcode-engine/commit/969a130b373fb028f8051e96cb9d79f1de0a2a1c))\n* removed incorrectly calling childWhitelist hook logic during drag and drop ([#1141](https://github.com/alibaba/lowcode-engine/issues/1141)) ([6576346](https://github.com/alibaba/lowcode-engine/commit/6576346b9185bedb090be9c84129e077cf5389b3))\n* renderer not rendering correct components when loading components with loadAsyncLibrary api ([9b3b4f9](https://github.com/alibaba/lowcode-engine/commit/9b3b4f9b0e35ef3ea2f0117f0cdb2254e15d5389))\n* should pass index param when creating a Prop instance under a list type Prop instance, fix [#780](https://github.com/alibaba/lowcode-engine/issues/780) ([a8de3f2](https://github.com/alibaba/lowcode-engine/commit/a8de3f299c7b26fa939d2b2ea1428143e2b5fb01))\n* simulator eclipses setting area [#773](https://github.com/alibaba/lowcode-engine/issues/773) ([b4b30a3](https://github.com/alibaba/lowcode-engine/commit/b4b30a359932f5c0e8fde1b28f54a883c87901d8))\n* spec typo ([#1064](https://github.com/alibaba/lowcode-engine/issues/1064)) ([ecb9dca](https://github.com/alibaba/lowcode-engine/commit/ecb9dca2b9386ef6fadfd009d161a9203b9b9558))\n* try catch calculation of dynamic setter ([f61e2a2](https://github.com/alibaba/lowcode-engine/commit/f61e2a2b8a3d8d6754474cd392bc259917c7eb10))\n* type=legao dont make request ([98ececa](https://github.com/alibaba/lowcode-engine/commit/98ececa9c11f93e5f849b201b5b5e7ff453733d7))\n* **types:** rrror declaration of the children prop ([951d1cb](https://github.com/alibaba/lowcode-engine/commit/951d1cb103fa46c0e7926d6138657c7d10cc4f88))\n* use the original object if it is not a shell object ([5ea53f7](https://github.com/alibaba/lowcode-engine/commit/5ea53f706b6571946bcfa56b8655b55717381771))\n* use the outer documentation url of unique key, fixes [#868](https://github.com/alibaba/lowcode-engine/issues/868) ([d770007](https://github.com/alibaba/lowcode-engine/commit/d770007ff8c39e6cf527e07a7d6468dbb88c776d))\n* use the outer documentation url of unique key, fixes [#868](https://github.com/alibaba/lowcode-engine/issues/868) ([912ee22](https://github.com/alibaba/lowcode-engine/commit/912ee22180a424f63298c319c62fb481513af904))\n* use uppercase resize trigger names based on material spec ([7fda0ef](https://github.com/alibaba/lowcode-engine/commit/7fda0efe131e0e2e3141849cf3f87307e7ce1b36))\n* when designMode is not design, the hidden attribute does not take effect ([3dd0b6d](https://github.com/alibaba/lowcode-engine/commit/3dd0b6d0a86267e3029c176ff49aff793ce3e186))\n\n### [1.0.4](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.4-beta.0...@alilc/lowcode-code-generator@1.0.4) (2022-04-12)\n\n\n### Bug Fixes\n\n* 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 __$evalArray 的问题 ([eb4cc69](https://github.com/alibaba/lowcode-engine/commit/eb4cc693f5dbcae54546c569eb8fa331d074e062))\n\n### [1.0.4-beta.1](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.4-beta.0...@alilc/lowcode-code-generator@1.0.4-beta.1) (2022-04-11)\n\n\n### Bug Fixes\n\n* 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 __$evalArray 的问题 ([987f4ce](https://github.com/alibaba/lowcode-engine/commit/987f4cea54ef8a75d0b63a0268b5a20b2938b8a7))\n\n### [1.0.4-beta.0](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.3...@alilc/lowcode-code-generator@1.0.4-beta.0) (2022-04-10)\n\n\n### Features\n\n* **material-parser:** check module before install it; fix default value issue in ts parser ([fc452f7](https://github.com/alibaba/lowcode-engine/commit/fc452f7166f02acfba6076c1a9425e6f5880b5f6))\n\n\n### Bug Fixes\n\n* 🐛 修正 i18n 里面的一个参数命名问题 ([1e9e388](https://github.com/alibaba/lowcode-engine/commit/1e9e388ce9104d76c4f6d9bc513c57e5059d7982))\n* 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题 ([1eb9add](https://github.com/alibaba/lowcode-engine/commit/1eb9addd8df2323f9aabac87af32ac2efcd6bf22)), closes [#288](https://github.com/alibaba/lowcode-engine/issues/288)\n* 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 __$eval 中用到 window 的问题 ([67dabb0](https://github.com/alibaba/lowcode-engine/commit/67dabb04beb32b6e94eb1276222e53b416e47c9d))\n* Fix the conversion failure of some props expressions under Slot props of low-code components ([7db5461](https://github.com/alibaba/lowcode-engine/commit/7db5461706c739fac673b2466bc2fda7661242e4))\n* fix unnecessary props calculation ([f1fed75](https://github.com/alibaba/lowcode-engine/commit/f1fed75f39be8289ede1ec558b04428a69e25b5f))\n* 修正 react 框架出码中在严格模式对 methods 和 context 的处理 ([79db4ac](https://github.com/alibaba/lowcode-engine/commit/79db4ac97f34f24b7f7460fb3fc67521967f8cc5))\n\n### [1.0.3](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2...@alilc/lowcode-code-generator@1.0.3) (2022-03-29)\n\n\n### Features\n\n* add getConvertedExtraKey / getOriginalExtraKey to utils ([8e7bb9d](https://github.com/alibaba/lowcode-engine/commit/8e7bb9d4b86454dd77c6928eb769cd764cad8630))\n\n\n### Bug Fixes\n\n* 🐛 出码: 解决 componentName 和 exportName 不一致时生成的 import 语句的问题 ([eefc091](https://github.com/alibaba/lowcode-engine/commit/eefc091ee7e86d6214d20d486212cb5aff237946))\n* component cannot be redisplayed by configuration after rendering is closed ([c54f369](https://github.com/alibaba/lowcode-engine/commit/c54f369e1860d818479dda9d6429f851c0b08fa6))\n* fix loop configuration auto fill empty array issue ([d087092](https://github.com/alibaba/lowcode-engine/commit/d087092fd712eff0556adacda692d3ff6f2f9f22))\n* make important true by default ([c63b6e1](https://github.com/alibaba/lowcode-engine/commit/c63b6e1bfadc3fc87ed41840952e02ffbff24fab))\n* make insertAfter & insertBefore work ([70fd372](https://github.com/alibaba/lowcode-engine/commit/70fd3720d098d6e227acb9281ee22feee66b9c0b))\n* npm源 ([437adcc](https://github.com/alibaba/lowcode-engine/commit/437adccf5f2dbb400de6e2bef10cfc4b65286f2b))\n* prop should return undefined when all items are undefined ([5bb9ec7](https://github.com/alibaba/lowcode-engine/commit/5bb9ec7a1dfaabfdb5369226b54d5f63a7999e59))\n* should not create new prop while querying fileName ([19c207d](https://github.com/alibaba/lowcode-engine/commit/19c207d29de045f473ba73baaf34e7294d40261a))\n* variable binding lost after modify the mock value ([ef95b56](https://github.com/alibaba/lowcode-engine/commit/ef95b5683273d8302bde1582de8afe3d87a808d8))\n* Workbench should receive the original skeleton other than shell skeleton ([d5c3ca1](https://github.com/alibaba/lowcode-engine/commit/d5c3ca1068ce2c2140980bd059d0da333574dc34))\n\n### [1.0.2](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2-beta.1...@alilc/lowcode-code-generator@1.0.2) (2022-03-08)\n\n### [1.0.2-beta.1](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.2-beta.0...@alilc/lowcode-code-generator@1.0.2-beta.1) (2022-03-08)\n\n\n### Bug Fixes\n\n* 🐛 补充 icejs 模板中缺失的依赖包 ([a94553e](https://github.com/alibaba/lowcode-engine/commit/a94553e503d439b67478df6a34950d9e3d15a063))\n\n### [1.0.2-beta.0](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.0...@alilc/lowcode-code-generator@1.0.2-beta.0) (2022-03-08)\n\n\n### Features\n\n* 在 skeleton 增加几个方法和事件 ([a7d436a](https://github.com/alibaba/lowcode-engine/commit/a7d436a0525a0ce0c7229710077111f283b452f4))\n* modify npm private control & version ([ee55d02](https://github.com/alibaba/lowcode-engine/commit/ee55d024a7f964ccf35a0efabec817364cea8041))\n* modify yuque link in README ([d522034](https://github.com/alibaba/lowcode-engine/commit/d522034879d20a7b5ed12f8fe02a30662a2ea7c6))\n* remove CHANGELOG.md ([b996414](https://github.com/alibaba/lowcode-engine/commit/b996414c436b5d2439c8368eb4e001cdbcd02892))\n* remove module field in material-parser package.json ([6141c27](https://github.com/alibaba/lowcode-engine/commit/6141c273c9c32eea22b5374679fe625e6ea15394))\n* rename build:umd ([23c7959](https://github.com/alibaba/lowcode-engine/commit/23c795931e1d5cf43e9c21cd902441c69c1ecc63))\n* replace tnpm with npm ([36caf0f](https://github.com/alibaba/lowcode-engine/commit/36caf0f18980c16f7ebb82ac845ad6b33e033567))\n* support UMD packageing for react-renderer ([982d0d6](https://github.com/alibaba/lowcode-engine/commit/982d0d676b3dfbfc10a2190c0040126d6925ed37))\n\n\n### Bug Fixes\n\n* 🐛 去掉 npm 上没有的依赖 ([#68](https://github.com/alibaba/lowcode-engine/issues/68)) ([e7ce779](https://github.com/alibaba/lowcode-engine/commit/e7ce77987eb05871dd1675d2a88367c5569bfbff))\n* 兼容 setters 为空的情况 ([56b459a](https://github.com/alibaba/lowcode-engine/commit/56b459a017a8350a911ef20f0166d1e62b6390e4))\n* 解决 package.json 中误添加了没有用到的数据源类型的 handler 的包的问题 ([#56](https://github.com/alibaba/lowcode-engine/issues/56)) ([76341c8](https://github.com/alibaba/lowcode-engine/commit/76341c8456b227192bb65537dc3d16033db0b3a1))\n* 解决出码的一些问题 ([#87](https://github.com/alibaba/lowcode-engine/issues/87)) ([4a01c97](https://github.com/alibaba/lowcode-engine/commit/4a01c97ea6bf23eb677888ba1aba54e5c9f4f630))\n* 修复 setup 的逻辑 ([1cfb15a](https://github.com/alibaba/lowcode-engine/commit/1cfb15aebea9796af23b2135f2aa4409d81283d7))\n* 修正一些对内的地址 ([07cc1f2](https://github.com/alibaba/lowcode-engine/commit/07cc1f2954530c64a1a3d260e8d532c9e19892e8))\n* 增加必要的方法 ([1b38a81](https://github.com/alibaba/lowcode-engine/commit/1b38a812653656aa02100a3b1b2a581188d1b3ef))\n* fix tsconfig of material-parser ([46725cb](https://github.com/alibaba/lowcode-engine/commit/46725cb9f3166912c8f5b42f1e0b1177158c1ee3))\n* lint&fix auto generated types.ts ([7dde970](https://github.com/alibaba/lowcode-engine/commit/7dde9701c7960b29523abddf32421cdbac47016d))\n* The outline tree does not display the loop flag when the loop is an empty array ([191e284](https://github.com/alibaba/lowcode-engine/commit/191e284f2fa190c2b3aecb4df31849b2bdc99d38))\n\n### [1.0.1](https://github.com/alibaba/lowcode-engine/compare/@alilc/lowcode-code-generator@1.0.0...@alilc/lowcode-code-generator@1.0.1) (2022-03-08)\n\n\n### Features\n\n* 在 skeleton 增加几个方法和事件 ([a7d436a](https://github.com/alibaba/lowcode-engine/commit/a7d436a0525a0ce0c7229710077111f283b452f4))\n* modify npm private control & version ([ee55d02](https://github.com/alibaba/lowcode-engine/commit/ee55d024a7f964ccf35a0efabec817364cea8041))\n* modify yuque link in README ([d522034](https://github.com/alibaba/lowcode-engine/commit/d522034879d20a7b5ed12f8fe02a30662a2ea7c6))\n* remove CHANGELOG.md ([b996414](https://github.com/alibaba/lowcode-engine/commit/b996414c436b5d2439c8368eb4e001cdbcd02892))\n* remove module field in material-parser package.json ([6141c27](https://github.com/alibaba/lowcode-engine/commit/6141c273c9c32eea22b5374679fe625e6ea15394))\n* rename build:umd ([23c7959](https://github.com/alibaba/lowcode-engine/commit/23c795931e1d5cf43e9c21cd902441c69c1ecc63))\n* replace tnpm with npm ([36caf0f](https://github.com/alibaba/lowcode-engine/commit/36caf0f18980c16f7ebb82ac845ad6b33e033567))\n* support UMD packageing for react-renderer ([982d0d6](https://github.com/alibaba/lowcode-engine/commit/982d0d676b3dfbfc10a2190c0040126d6925ed37))\n\n\n### Bug Fixes\n\n* 🐛 修正一些示例地址 ([8d21283](https://github.com/alibaba/lowcode-engine/commit/8d212832e77a1ec763db668683917705774acd0d))\n* 兼容 setters 为空的情况 ([56b459a](https://github.com/alibaba/lowcode-engine/commit/56b459a017a8350a911ef20f0166d1e62b6390e4))\n* 修复 setup 的逻辑 ([1cfb15a](https://github.com/alibaba/lowcode-engine/commit/1cfb15aebea9796af23b2135f2aa4409d81283d7))\n* 修正一些对内的地址 ([07cc1f2](https://github.com/alibaba/lowcode-engine/commit/07cc1f2954530c64a1a3d260e8d532c9e19892e8))\n* 增加必要的方法 ([1b38a81](https://github.com/alibaba/lowcode-engine/commit/1b38a812653656aa02100a3b1b2a581188d1b3ef))\n* fix tsconfig of material-parser ([46725cb](https://github.com/alibaba/lowcode-engine/commit/46725cb9f3166912c8f5b42f1e0b1177158c1ee3))\n* lint&fix auto generated types.ts ([7dde970](https://github.com/alibaba/lowcode-engine/commit/7dde9701c7960b29523abddf32421cdbac47016d))\n* The outline tree does not display the loop flag when the loop is an empty array ([191e284](https://github.com/alibaba/lowcode-engine/commit/191e284f2fa190c2b3aecb4df31849b2bdc99d38))\n\n## 1.0.0 (2022-02-17)\n\n\n### Features\n\n* first commit - genesis ([4f4ac51](https://github.com/alibaba/lowcode-engine/commit/4f4ac5115d18357a7399632860808f6cffc33fad))\n"
  },
  {
    "path": "modules/code-generator/CONTRIBUTING.md",
    "content": "# 如何共建\n\n1. 拉取最新代码，切换到 develop 分支，基于 develop 分支切出一个 feature 或 hotfix 分支\n2. 到 `lowcode-engine` 项目根目录下，执行 `lerna bootstrap && lerna run build --scope \"@alilc/lowcode-types\"` 来安装依赖并构建\n3. 到 `lowcode-engine/modules/code-generator`下，安装依赖(`npm i`)，然后先跑一遍 `npm test` 看看是否所有用例都能通过 (如果网络条件不太好，建议使用 [cnpm - 淘宝提供的中国 NPM 镜像](https://npmmirror.com/))\n4. 在 tests 目录下编写您的需求/问题的测试用例\n5. 修改 src 下的一些代码，然后运行 `npm test` 或 `npm start` 启动 jest 进行调测\n6. 确保所有的测试用例都能通过时，提 MR 给 @牧毅 -- MR 将在 1 个工作日内给您回复意见。\n\n当然，欢迎提前私聊沟通 @牧毅，或加入 低代码渲染/出码服务金牌用户群 讨论沟通。\n\n# FAQ\n\n## 如何查看单测覆盖率？\n\n执行 `npm test:cov` 命令，这样会自动生成单测覆盖率的报告到 `coverage` 目录下。\n\n## 如何只执行一个测试用例？\n\n```sh\nnpm test -t 'demo2-utils-name-alias'\n```\n\n## 更新特定测试用例的 expected:\n\n```sh\nnpm test:update-snapshots -t 'demo2-utils-name-alias'\n```\n\n## 如何只执行某个测试用例文件？\n\n执行 `npx jest 测试用例的文件路径` 即可，如:\n\n```sh\nnpx jest tests/plugins/common/requireUtils.test.ts\n```\n\n## 如何调试某个测试用例？\n\n建议需要打断点的地方通过 VSCode 打上断点，然后打开 VSCode 的 JavaScript Debug Terminal，在其中执行 `npx jest tests/path/to/your/test/file.ts` 或 `npx jest -t your-test-case-title` 来执行你的测试用例 -- 这样执行到打了断点的语句时会自动断住，以便调试。\n"
  },
  {
    "path": "modules/code-generator/README.md",
    "content": "# 出码\n\n所谓出码，即将低代码编排出的 schema 进行解析并转换成最终可执行的代码的过程。本模块提供有 Icejs 和 Rax 两套框架的出码方案，并提供了强大而灵活的扩展机制。\n\n## 使用方法\n\n### 1) 通过命令行快速体验\n\n欢迎使用命令行工具快速体验：`npx @alilc/lowcode-code-generator -i example-schema.json -o generated -s icejs`\n\n--其中 example-schema.json 可以从[这里下载](https://unpkg.com/@alilc/lowcode-code-generator@beta/example-schema.json)\n\n### 2) 通过设计器插件快速体验\n\n1. 安装依赖: `npm install --save @alilc/lowcode-plugin-code-generator`\n2. 注册插件:\n\n```ts\nimport { plugins } from '@alilc/lowcode-engine';\nimport CodeGenPlugin from '@alilc/lowcode-plugin-code-generator';\n\n// 在你的初始化函数中：\nawait plugins.register(CodeGenPlugin);\n\n// 如果您不希望自动加上出码按钮，则可以这样注册\nawait plugins.register(CodeGenPlugin, { disableCodeGenActionBtn: true });\n```\n\n然后运行你的低代码编辑器项目即可 -- 在设计器的右上角会出现一个“出码”按钮，点击即可在浏览器中出码并预览。\n\n### 3）服务端出码接入\n\n此代码生成器一开始就是为服务端出码设计的，你可以直接这样来在 node.js 环境中使用：\n\n1. 安装依赖: `npm install --save @alilc/lowcode-code-generator`\n2. 引入代码生成器:\n\n```js\nimport CodeGenerator from '@alilc/lowcode-code-generator';\n```\n\n3. 创建项目构建器:\n\n```js\nconst projectBuilder = CodeGenerator.solutions.icejs();\n```\n\n4. 生成代码\n\n```js\nconst project = await projectBuilder.generateProject(\n  schema, // 编排搭建出来的 schema\n);\n```\n\n5. 将生成的代码写入到磁盘中(也可以生成一个 zip 包)\n\n```js\n// 写入磁盘\nawait CodeGenerator.publishers.disk().publish({\n  project, // 上一步生成的 project\n  outputPath: '/path/to/your/output/dir', // 输出目录\n  projectSlug: 'your-project-slug', // 项目标识\n});\n\n// 写入到 zip 包\nawait CodeGenerator.publishers.zip().publish({\n  project, // 上一步生成的 project\n  outputPath: '/path/to/your/output/dir', // 输出目录\n  projectSlug: 'your-project-slug', // 项目标识 -- 对应生成 your-project-slug.zip 文件\n});\n```\n\n注：一般来说在服务端出码可以跟 github/gitlab, CI 和 CD 流程等一起串起来使用，通常用于优化性能。\n\n### 4）浏览器中出码接入\n\n随着现在电脑性能和浏览器技术的发展，出码其实已经不必非得在服务端做了，借助于 Web Worker 特性，可以在浏览器中进行出码：\n\n1. 安装依赖: `npm install --save @alilc/lowcode-code-generator`\n2. 引入代码生成器:\n\n```js\nimport * as CodeGenerator from '@alilc/lowcode-code-generator/standalone-loader';\n```\n\n3. 【可选】提前初始化代码生成器:\n\n```js\n// 提前初始化下，这样后面用的时候更快(这个 init 内部会提前准备好创建 worker 的一些资源)\nawait CodeGenerator.init();\n```\n\n4. 出码\n\n```js\nconst project = await CodeGenerator.generateCode({\n  solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax )\n  schema, // 编排搭建出来的 schema\n});\n\nconsole.log(project); // 出码结果(默认是递归结构描述的，可以传 flattenResult: true 以生成扁平结构的结果)\n```\n\n注：一般来说在浏览器中出码适合做即时预览功能。\n\n5. 下载 zip 包\n\n```js\n// 写入到 zip 包\nawait CodeGenerator.publishers.zip().publish({\n  project, // 上一步生成的 project\n  projectSlug: 'your-project-slug', // 项目标识 -- 对应下载 your-project-slug.zip 文件\n});\n```\n\n### 5）自定义出码\n\n前端框架灵活多变，默认内置的出码方案很难满足所有人的需求，好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件，然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。\n\n## 参与共建\n\n欢迎参与共建，如何共建请参阅：[./CONTRIBUTING.md](https://github.com/alibaba/lowcode-engine/blob/main/modules/code-generator/CONTRIBUTING.md)\n"
  },
  {
    "path": "modules/code-generator/babel.config.js",
    "content": "module.exports = require('../../babel.config');"
  },
  {
    "path": "modules/code-generator/bin/lowcode-code-generator.js",
    "content": "#!/usr/bin/env node\n/* eslint-disable no-var */\n/* eslint-disable prefer-arrow-callback */\n/* eslint-disable @typescript-eslint/no-require-imports */\n\nvar program = require('commander');\n\nprogram\n  .command('generate', { isDefault: true })\n  .description('Generate code from ali lowcode schema')\n  .requiredOption('-s, --solution <solution>', 'specify the solution to use (icejs/rax/recore)')\n  .option('-i, --input <input>', 'specify the input schema file')\n  .option('-o, --output <output>', 'specify the output directory', 'generated')\n  .option('-c, --cwd <cwd>', 'specify the working directory', '.')\n  .option('-q, --quiet', 'be quiet, do not output anything unless get error', false)\n  .option('-v, --verbose', 'be verbose, output more information', false)\n  .option('--solution-options <options>', 'specify the solution options', '{}')\n  .arguments('[input-schema] ali lowcode schema JSON file')\n  .action(function doGenerate(inputSchema, command) {\n    var options = command.opts();\n    if (options.cwd) {\n      process.chdir(options.cwd);\n    }\n\n    require('../dist/cli')\n      .run(inputSchema ? [inputSchema] : [], options)\n      .then((retCode) => {\n        process.exit(retCode);\n      });\n  });\n\nprogram\n  .command('init-solution')\n  .option('-c, --cwd <cwd>', 'specify the working directory', '.')\n  .option('-q, --quiet', 'be quiet, do not output anything unless get error', false)\n  .option('-v, --verbose', 'be verbose, output more information', false)\n  .arguments('<your-solution-name>')\n  .action(function initSolution(solutionName, command) {\n    var options = command.opts();\n    if (options.cwd) {\n      process.chdir(options.cwd);\n    }\n\n    require('../dist/cli')\n      .initSolution([solutionName], options)\n      .then((retCode) => {\n        process.exit(retCode);\n      });\n  });\n\nprogram.parse(process.argv);\n\n"
  },
  {
    "path": "modules/code-generator/example-schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"componentName\": \"Button\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Button\"\n    },\n    {\n      \"componentName\": \"Button.Group\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Button\",\n      \"subName\": \"Group\"\n    },\n    {\n      \"componentName\": \"Input\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Input\"\n    },\n    {\n      \"componentName\": \"Form\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Form\"\n    },\n    {\n      \"componentName\": \"Form.Item\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Form\",\n      \"subName\": \"Item\"\n    },\n    {\n      \"componentName\": \"NumberPicker\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"NumberPicker\"\n    },\n    {\n      \"componentName\": \"Select\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Select\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node$1\",\n      \"meta\": {\n        \"title\": \"测试\",\n        \"router\": \"/\"\n      },\n      \"props\": {\n        \"ref\": \"outerView\",\n        \"autoLoading\": true\n      },\n      \"fileName\": \"test\",\n      \"state\": {\n        \"text\": \"outer\"\n      },\n      \"lifeCycles\": {\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function componentDidMount() { console.log('componentDidMount'); }\"\n        }\n      },\n      \"dataSource\": {\n        \"list\": [\n          {\n            \"id\": \"urlParams\",\n            \"type\": \"urlParams\"\n          },\n\n          {\n            \"id\": \"user\",\n            \"type\": \"fetch\",\n            \"options\": {\n              \"method\": \"GET\",\n              \"uri\": \"https://shs.xxx.com/mock/1458/demo/user\",\n              \"isSync\": true\n            },\n            \"dataHandler\": {\n              \"type\": \"JSFunction\",\n              \"value\": \"function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data;\\n}\"\n            }\n          },\n\n          {\n            \"id\": \"orders\",\n            \"type\": \"fetch\",\n            \"options\": {\n              \"method\": \"GET\",\n              \"uri\": \"https://shs.xxx.com/mock/1458/demo/orders\",\n              \"isSync\": true\n            },\n            \"dataHandler\": {\n              \"type\": \"JSFunction\",\n              \"value\": \"function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data.result;\\n}\"\n            }\n          }\n        ],\n        \"dataHandler\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function (dataMap) {\\n  console.info(\\\"All datasources loaded:\\\", dataMap);\\n}\"\n        }\n      },\n      \"children\": [\n        {\n          \"componentName\": \"Form\",\n          \"id\": \"node$2\",\n          \"props\": {\n            \"labelCol\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"this.state.colNum\"\n            },\n            \"style\": {},\n            \"ref\": \"testForm\"\n          },\n          \"children\": [\n            {\n              \"componentName\": \"Form.Item\",\n              \"id\": \"node$3\",\n              \"props\": {\n                \"label\": \"姓名：\",\n                \"name\": \"name\",\n                \"initValue\": \"李雷\"\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"Input\",\n                  \"id\": \"node$4\",\n                  \"props\": {\n                    \"placeholder\": \"请输入\",\n                    \"size\": \"medium\",\n                    \"style\": {\n                      \"width\": 320\n                    }\n                  }\n                }\n              ]\n            },\n            {\n              \"componentName\": \"Form.Item\",\n              \"id\": \"node$5\",\n              \"props\": {\n                \"label\": \"年龄：\",\n                \"name\": \"age\",\n                \"initValue\": \"22\"\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"NumberPicker\",\n                  \"id\": \"node$6\",\n                  \"props\": {\n                    \"size\": \"medium\",\n                    \"type\": \"normal\"\n                  }\n                }\n              ]\n            },\n            {\n              \"componentName\": \"Form.Item\",\n              \"id\": \"node$7\",\n              \"props\": {\n                \"label\": \"职业：\",\n                \"name\": \"profession\"\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"Select\",\n                  \"id\": \"node$8\",\n                  \"props\": {\n                    \"dataSource\": [\n                      {\n                        \"label\": \"教师\",\n                        \"value\": \"t\"\n                      },\n                      {\n                        \"label\": \"医生\",\n                        \"value\": \"d\"\n                      },\n                      {\n                        \"label\": \"歌手\",\n                        \"value\": \"s\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            {\n              \"componentName\": \"Div\",\n              \"id\": \"node$9\",\n              \"props\": {\n                \"style\": {\n                  \"textAlign\": \"center\"\n                }\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"Button.Group\",\n                  \"id\": \"node$a\",\n                  \"props\": {},\n                  \"children\": [\n                    {\n                      \"componentName\": \"Button\",\n                      \"id\": \"node$b\",\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.index >= 1\"\n                      },\n                      \"loop\": [\"a\", \"b\", \"c\"],\n                      \"props\": {\n                        \"type\": \"primary\",\n                        \"style\": {\n                          \"margin\": \"0 5px 0 5px\"\n                        }\n                      },\n                      \"children\": [\n                        {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.item\"\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"constants\": {\n    \"ENV\": \"prod\",\n    \"DOMAIN\": \"xxx.xxx.com\"\n  },\n  \"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n  \"config\": {\n    \"sdkVersion\": \"1.0.3\",\n    \"historyMode\": \"hash\",\n    \"targetRootID\": \"J_Container\",\n    \"layout\": {\n      \"componentName\": \"BasicLayout\",\n      \"props\": {\n        \"logo\": \"...\",\n        \"name\": \"测试网站\"\n      }\n    },\n    \"theme\": {\n      \"package\": \"@alife/theme-fusion\",\n      \"version\": \"^0.1.0\",\n      \"primary\": \"#ff9966\"\n    }\n  },\n  \"meta\": {\n    \"name\": \"demo应用\",\n    \"git_group\": \"appGroup\",\n    \"project_name\": \"app_demo\",\n    \"description\": \"这是一个测试应用\",\n    \"spma\": \"spa23d\",\n    \"creator\": \"Test\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/example-schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Button',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Button',\n    },\n    {\n      componentName: 'Button.Group',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Button',\n      subName: 'Group',\n    },\n    {\n      componentName: 'Input',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Input',\n    },\n    {\n      componentName: 'Form',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Form',\n    },\n    {\n      componentName: 'Form.Item',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Form',\n      subName: 'Item',\n    },\n    {\n      componentName: 'NumberPicker',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'NumberPicker',\n    },\n    {\n      componentName: 'Select',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Select',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node$1',\n      meta: {\n        title: '测试',\n        router: '/',\n      },\n      props: {\n        ref: 'outerView',\n        autoLoading: true,\n      },\n      fileName: 'test',\n      state: {\n        text: 'outer',\n      },\n      lifeCycles: {\n        componentDidMount: {\n          type: 'JSFunction',\n          value: \"function componentDidMount() { console.log('componentDidMount'); }\",\n        },\n      },\n      dataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n          },\n\n          {\n            id: 'user',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data;\\n}',\n            },\n          },\n\n          {\n            id: 'orders',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/orders',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data.result;\\n}',\n            },\n          },\n        ],\n        dataHandler: {\n          type: 'JSFunction',\n          value: 'function (dataMap) {\\n  console.info(\"All datasources loaded:\", dataMap);\\n}',\n        },\n      },\n      children: [\n        {\n          componentName: 'Form',\n          id: 'node$2',\n          props: {\n            labelCol: {\n              type: 'JSExpression',\n              value: 'this.state.colNum',\n            },\n            style: {},\n            ref: 'testForm',\n          },\n          children: [\n            {\n              componentName: 'Form.Item',\n              id: 'node$3',\n              props: {\n                label: '姓名：',\n                name: 'name',\n                initValue: '李雷',\n              },\n              children: [\n                {\n                  componentName: 'Input',\n                  id: 'node$4',\n                  props: {\n                    placeholder: '请输入',\n                    size: 'medium',\n                    style: {\n                      width: 320,\n                    },\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node$5',\n              props: {\n                label: '年龄：',\n                name: 'age',\n                initValue: '22',\n              },\n              children: [\n                {\n                  componentName: 'NumberPicker',\n                  id: 'node$6',\n                  props: {\n                    size: 'medium',\n                    type: 'normal',\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node$7',\n              props: {\n                label: '职业：',\n                name: 'profession',\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node$8',\n                  props: {\n                    dataSource: [\n                      {\n                        label: '教师',\n                        value: 't',\n                      },\n                      {\n                        label: '医生',\n                        value: 'd',\n                      },\n                      {\n                        label: '歌手',\n                        value: 's',\n                      },\n                    ],\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Div',\n              id: 'node$9',\n              props: {\n                style: {\n                  textAlign: 'center',\n                },\n              },\n              children: [\n                {\n                  componentName: 'Button.Group',\n                  id: 'node$a',\n                  props: {},\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node$b',\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.index >= 1',\n                      },\n                      loop: ['a', 'b', 'c'],\n                      props: {\n                        type: 'primary',\n                        style: {\n                          margin: '0 5px 0 5px',\n                        },\n                      },\n                      children: [\n                        {\n                          type: 'JSExpression',\n                          value: 'this.item',\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  constants: {\n    ENV: 'prod',\n    DOMAIN: 'xxx.xxx.com',\n  },\n  css: 'body {font-size: 12px;} .table { width: 100px;}',\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'J_Container',\n    layout: {\n      componentName: 'BasicLayout',\n      props: {\n        logo: '...',\n        name: '测试网站',\n      },\n    },\n    theme: {\n      package: '@alife/theme-fusion',\n      version: '^0.1.0',\n      primary: '#ff9966',\n    },\n  },\n  meta: {\n    name: 'demo应用',\n    git_group: 'appGroup',\n    project_name: 'app_demo',\n    description: '这是一个测试应用',\n    spma: 'spa23d',\n    creator: 'Test',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/jest.config.js",
    "content": "module.exports = {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n  transformIgnorePatterns: ['/node_modules/(?!core-js)/'],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: false,\n  collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/node_modules/**', '!**/vendor/**'],\n  testMatch: ['<rootDir>/tests/**/*.test.ts'],\n  setupFiles: ['./jest.setup.js'],\n};\n"
  },
  {
    "path": "modules/code-generator/jest.setup.js",
    "content": "// 对于 standalone 模式的专门 polyfills\nif (process.env.TEST_TARGET === 'standalone') {\n  // 模拟浏览器环境\n  global.window = global;\n  global.self = global;\n\n  // 将所有测试用例里面的 './src' 都替换为 './dist/standalone'\n  jest.mock('./src', () => require('./dist/standalone'));\n}\n\n// 如果在调试模式下，则不限制超时时间\njest.setTimeout(typeof v8debug === 'object' ? Infinity : 30 * 1000);\n"
  },
  {
    "path": "modules/code-generator/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-code-generator\",\n  \"version\": \"1.1.7\",\n  \"description\": \"出码引擎 for LowCode Engine\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"typings\": \"types/index.d.ts\",\n  \"files\": [\n    \"bin\",\n    \"lib\",\n    \"es\",\n    \"demo\",\n    \"dist\",\n    \"types\",\n    \"standalone\",\n    \"standalone-worker\",\n    \"standalone-loader\",\n    \"loader\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"CONTRIBUTING.md\",\n    \"example-schema.json\",\n    \"example-schema.json5\"\n  ],\n  \"bin\": {\n    \"lowcode-code-generator\": \"bin/lowcode-code-generator.js\"\n  },\n  \"scripts\": {\n    \"start\": \"jest --watchAll\",\n    \"build\": \"npm run clean && node scripts/build\",\n    \"build:standalone\": \"node scripts/build-standalone\",\n    \"clean\": \"rimraf es lib dist types generated demo coverage output test-cases/*/*/actual\",\n    \"lint\": \"eslint --ext .jsx,.js,.ts,.tsx src/\",\n    \"lintfix\": \"eslint --ext .jsx,.js,.ts,.tsx --fix src/\",\n    \"check:types\": \"tsc --noEmit\",\n    \"template\": \"node ./scripts/build-template-static-files.js\",\n    \"test\": \"npm run test:normal && npm run test:standalone\",\n    \"test:normal\": \"jest\",\n    \"test:standalone\": \"node scripts/test-standalone\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:update-snapshots\": \"cross-env UPDATE_EXPECTED=true jest -u\",\n    \"analyze:standalone\": \"ANALYZE=true node scripts/build-standalone\",\n    \"release:beta\": \"standard-version -t @alilc/lowcode-code-generator\\\\@ -r patch --prerelease beta && git push --follow-tags && npm publish --tag beta\",\n    \"release:patch\": \"standard-version -t @alilc/lowcode-code-generator\\\\@ -r patch && git push --follow-tags && npm publish\",\n    \"release:minor\": \"standard-version -t @alilc/lowcode-code-generator\\\\@ -r minor && git push --follow-tags && npm publish\",\n    \"prepublishOnly\": \"npm run build\",\n    \"demo\": \"node bin/lowcode-code-generator.js -i example-schema.json -o demo -s icejs\"\n  },\n  \"standard-version\": {\n    \"skip\": {\n      \"changelog\": true\n    }\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\",\n      \"commit-msg\": \"commitlint -E HUSKY_GIT_PARAMS\"\n    }\n  },\n  \"lint-staged\": {\n    \"**/*.{js,jsx,ts,tsx}\": \"eslint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-types\": \"^1.0.0\",\n    \"@babel/generator\": \"^7.12.11\",\n    \"@babel/parser\": \"^7.12.11\",\n    \"@babel/runtime\": \"^7.12.5\",\n    \"@babel/traverse\": \"^7.12.12\",\n    \"@babel/types\": \"^7.12.12\",\n    \"@types/debug\": \"^4.1.7\",\n    \"@types/fs-extra\": \"^9.0.12\",\n    \"@types/glob\": \"^7.2.0\",\n    \"@types/lodash\": \"^4.14.162\",\n    \"@types/node-fetch\": \"2.x\",\n    \"@types/qs\": \"^6.9.6\",\n    \"@types/semver\": \"^7.3.4\",\n    \"buffer\": \"^6.0.3\",\n    \"chalk\": \"^4.1.0\",\n    \"change-case\": \"^3.1.0\",\n    \"commander\": \"^6.1.0\",\n    \"debug\": \"^4.3.2\",\n    \"file-saver\": \"^2.0.5\",\n    \"fp-ts\": \"^2.11.9\",\n    \"fs-extra\": \"9.x\",\n    \"glob\": \"^7.2.0\",\n    \"html-entities\": \"^2.3.2\",\n    \"json5\": \"^2.2.0\",\n    \"jsonc\": \"^2.0.0\",\n    \"jszip\": \"^3.5.0\",\n    \"lodash\": \"^4.17.21\",\n    \"lodash-es\": \"^4.17.21\",\n    \"mock-fs\": \"^5.1.2\",\n    \"moment\": \"^2.29.1\",\n    \"nanomatch\": \"^1.2.13\",\n    \"node-fetch\": \"2.x\",\n    \"path-browserify\": \"^1.0.1\",\n    \"prettier\": \"^2.5.1\",\n    \"qs\": \"^6.10.1\",\n    \"semver\": \"^7.3.4\",\n    \"short-uuid\": \"^3.1.1\",\n    \"babel-jest\": \"^26.5.2\",\n    \"tslib\": \"^2.3.1\"\n  },\n  \"browser\": {\n    \"path\": \"path-browserify\",\n    \"lodash\": \"lodash-es\",\n    \"prettier\": \"prettier/standalone\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.4.2\",\n    \"@types/babel__traverse\": \"^7.11.0\",\n    \"@types/file-saver\": \"^2.0.7\",\n    \"@types/jest\": \"^27.0.2\",\n    \"@types/lodash\": \"^4.14.162\",\n    \"@types/node\": \"^14.14.20\",\n    \"@types/prettier\": \"^2.4.2\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.12.0\",\n    \"@typescript-eslint/parser\": \"^4.12.0\",\n    \"concurrently\": \"^6.5.1\",\n    \"cross-env\": \"^7.0.3\",\n    \"esbuild\": \"^0.14.5\",\n    \"esbuild-plugin-alias\": \"^0.2.1\",\n    \"esbuild-plugin-ignore\": \"^1.1.0\",\n    \"esbuild-visualizer\": \"^0.3.1\",\n    \"eslint\": \"^7.17.0\",\n    \"eslint-config-ali\": \"^11.4.1\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-react\": \"^7.22.0\",\n    \"eslint-plugin-react-hooks\": \"^4.2.0\",\n    \"jest\": \"^26.5.2\",\n    \"jest-util\": \"^27.4.2\",\n    \"rimraf\": \"^3.0.2\",\n    \"standard-version\": \"^9.1.1\",\n    \"ts-jest\": \"^26.5.2\",\n    \"ts-loader\": \"^6.2.2\",\n    \"ts-node\": \"^8.10.2\",\n    \"tsconfig-paths\": \"^3.9.0\",\n    \"typescript\": \"4.x\",\n    \"yargs-parser\": \"^20.2.9\"\n  },\n  \"engines\": {\n    \"node\": \">=10.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/modules/code-generator\"\n  },\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "modules/code-generator/scripts/build-cli.js",
    "content": "/* eslint-disable no-console */\n/* eslint-disable @typescript-eslint/no-require-imports */\nconst esbuild = require('esbuild');\nconst ignorePlugin = require('esbuild-plugin-ignore');\n\n// 执行脚本\n(async () => {\n  try {\n    console.log('building...');\n    const result = await esbuild.build({\n      entryPoints: ['src/cli/index.ts'],\n      outfile: 'dist/cli.js',\n      bundle: true,\n      platform: 'node',\n      target: ['node10'],\n      format: 'cjs',\n      sourcemap: true,\n      sourcesContent: true,\n      plugins: [\n        ignorePlugin([\n          // @alilc/lowcode-types 中误依赖了 react，这里忽略下\n          {\n            resourceRegExp: /^react$/,\n            contextRegExp: /./,\n          },\n          {\n            resourceRegExp: /setter-config/,\n            contextRegExp: /lowcode-types/,\n          },\n        ]),\n      ],\n      define: {},\n      treeShaking: true,\n      minify: false,\n      minifyWhitespace: false,\n      minifyIdentifiers: false,\n      minifySyntax: false,\n      legalComments: 'external',\n      external: Object.keys(require('../package.json').dependencies),\n    });\n    if (result.errors.length > 0) {\n      throw result.errors;\n    }\n\n    if (result.warnings.length > 0) {\n      result.warnings.forEach((warnings) => {\n        console.warn(warnings);\n      });\n    }\n\n    console.log('done');\n  } catch (e) {\n    console.error(e);\n    process.exit(1);\n  }\n})();\n"
  },
  {
    "path": "modules/code-generator/scripts/build-standalone-loader.js",
    "content": "/* eslint-disable no-console */\n/* eslint-disable @typescript-eslint/no-require-imports */\nconst esbuild = require('esbuild');\n\nconst packageVersion = require('../package.json').version;\nconsole.log('build standalone-loader: packageVersion=%s', packageVersion);\n\nconst enableAnalyze = process.env.ANALYZE === 'true';\nconst buildConfig = {\n  entryPoints: ['src/standalone-loader.ts'],\n  outfile: 'dist/standalone-loader.js',\n  metafile: enableAnalyze,\n  bundle: true,\n  target: ['chrome69'],\n  format: 'cjs',\n  sourcemap: true,\n  sourcesContent: true,\n  external: Object.keys(require('../package.json').dependencies),\n  define: {\n    process: JSON.stringify({\n      env: {\n        NODE_ENV: 'production',\n        STANDALONE: 'true',\n      },\n    }),\n    __PACKAGE_VERSION__: JSON.stringify(packageVersion),\n  },\n  minify: false,\n  minifyWhitespace: false,\n  minifyIdentifiers: false,\n  minifySyntax: false,\n  legalComments: 'external',\n  treeShaking: true,\n};\n\n// 执行脚本\n(async () => {\n  try {\n    console.log('building cjs...');\n    const result = await esbuild.build({\n      ...buildConfig,\n    });\n    if (result.errors.length > 0) {\n      throw result.errors;\n    }\n\n    if (result.warnings.length > 0) {\n      result.warnings.forEach((warnings) => {\n        console.warn(warnings);\n      });\n    }\n\n    const result2 = await esbuild.build({\n      ...buildConfig,\n      outfile: buildConfig.outfile.replace(/\\.js$/, '.esm.js'),\n      format: 'esm',\n    });\n    if (result2.errors.length > 0) {\n      throw result2.errors;\n    }\n\n    if (result2.warnings.length > 0) {\n      result2.warnings.forEach((warnings) => {\n        console.warn(warnings);\n      });\n    }\n\n    console.log('done');\n  } catch (e) {\n    console.error(e);\n    process.exit(1);\n  }\n})();\n"
  },
  {
    "path": "modules/code-generator/scripts/build-standalone-worker.js",
    "content": "/* eslint-disable no-console */\n/* eslint-disable @typescript-eslint/no-require-imports */\nconst esbuild = require('esbuild');\nconst { spawnSync } = require('child_process');\nconst ignorePlugin = require('esbuild-plugin-ignore');\nconst fs = require('fs');\nconst path = require('path');\n\nconst enableAnalyze = process.env.ANALYZE === 'true';\nconst buildConfig = {\n  entryPoints: ['src/standalone-worker.ts'],\n  outfile: 'dist/standalone-worker.js',\n  metafile: enableAnalyze,\n  bundle: true,\n  target: ['chrome69'],\n  format: 'iife',\n  sourcemap: true,\n  sourcesContent: true,\n  plugins: [\n    ignorePlugin([\n      {\n        resourceRegExp: /^fs$/,\n        contextRegExp: /./,\n      },\n      // @alilc/lowcode-types 中误依赖了 react，这里忽略下\n      {\n        resourceRegExp: /^react$/,\n        contextRegExp: /./,\n      },\n      {\n        resourceRegExp: /setter-config/,\n        contextRegExp: /lowcode-types|..[\\\\/]types/,\n      },\n    ]),\n  ],\n  define: {\n    process: JSON.stringify({\n      env: {\n        NODE_ENV: 'production',\n        STANDALONE: 'true',\n      },\n    }),\n  },\n  treeShaking: true,\n};\n\n// 执行脚本\n(async () => {\n  try {\n    console.log('building...');\n    const result = await esbuild.build({\n      ...buildConfig,\n      minify: false,\n      minifyWhitespace: false,\n      minifyIdentifiers: false,\n      minifySyntax: false,\n      legalComments: 'external',\n    });\n    if (result.errors.length > 0) {\n      throw result.errors;\n    }\n\n    if (result.warnings.length > 0) {\n      result.warnings.forEach((warnings) => {\n        console.warn(warnings);\n      });\n    }\n\n    if (enableAnalyze) {\n      const metaFile = buildConfig.outfile.replace(/\\.js/, '.meta.json');\n      const statsFile = buildConfig.outfile.replace(/\\.js/, '.stats.html');\n      fs.writeFileSync(metaFile, JSON.stringify(result.metafile || {}), { encoding: 'utf-8' });\n      spawnSync('npx', ['esbuild-visualizer', '--metadata', metaFile, '--filename', statsFile], {\n        shell: true,\n        stdio: 'inherit',\n      });\n      spawnSync('open', [statsFile], {\n        shell: true,\n        stdio: 'inherit',\n      });\n      return;\n    }\n\n    const outFileContent = fs.readFileSync(buildConfig.outfile, 'utf-8');\n\n    console.log('minifying...');\n    const minifiedOutFile = buildConfig.outfile.replace(/\\.js$/, '.min.js');\n    const minifiedResult = esbuild.transformSync(outFileContent, {\n      minify: true,\n      sourcemap: true,\n      sourcesContent: true,\n      sourcefile: path.basename(buildConfig.outfile),\n    });\n\n    fs.writeFileSync(minifiedOutFile, minifiedResult.code, { encoding: 'utf-8' });\n    fs.writeFileSync(`${minifiedOutFile}.map`, minifiedResult.map, { encoding: 'utf-8' });\n\n    minifiedResult.warnings.forEach((warnings) => {\n      console.log(warnings);\n    });\n\n    console.log('done');\n  } catch (e) {\n    console.error(e);\n    process.exit(1);\n  }\n})();\n"
  },
  {
    "path": "modules/code-generator/scripts/build-standalone.js",
    "content": "/* eslint-disable no-console */\n/* eslint-disable @typescript-eslint/no-require-imports */\nconst esbuild = require('esbuild');\nconst { spawnSync } = require('child_process');\nconst ignorePlugin = require('esbuild-plugin-ignore');\nconst fs = require('fs');\nconst path = require('path');\n\nconst UMD_GLOBAL_NAME = 'AliLowCodeCodeGenerator';\n\nconst enableAnalyze = process.env.ANALYZE === 'true';\nconst buildConfig = {\n  entryPoints: ['src/standalone.ts'],\n  outfile: 'dist/standalone.js',\n  metafile: enableAnalyze,\n  bundle: true,\n  target: ['chrome69'],\n  format: 'cjs',\n  sourcemap: true,\n  sourcesContent: true,\n  plugins: [\n    ignorePlugin([\n      {\n        resourceRegExp: /^fs$/,\n        contextRegExp: /./,\n      },\n      // @alilc/lowcode-types 中误依赖了 react，这里忽略下\n      {\n        resourceRegExp: /^react$/,\n        contextRegExp: /./,\n      },\n      {\n        resourceRegExp: /setter-config/,\n        contextRegExp: /lowcode-types|..[\\\\/]types/,\n      },\n    ]),\n  ],\n  define: {\n    process: JSON.stringify({\n      env: {\n        NODE_ENV: 'production',\n        STANDALONE: 'true',\n      },\n    }),\n  },\n  treeShaking: true,\n};\n\n// 执行脚本\n(async () => {\n  try {\n    console.log('building...');\n    const result = await esbuild.build({\n      ...buildConfig,\n      minify: false,\n      minifyWhitespace: false,\n      minifyIdentifiers: false,\n      minifySyntax: false,\n      legalComments: 'external',\n    });\n    if (result.errors.length > 0) {\n      throw result.errors;\n    }\n\n    if (result.warnings.length > 0) {\n      result.warnings.forEach((warnings) => {\n        console.warn(warnings);\n      });\n    }\n\n    if (enableAnalyze) {\n      const metaFile = buildConfig.outfile.replace(/\\.js/, '.meta.json');\n      const statsFile = buildConfig.outfile.replace(/\\.js/, '.stats.html');\n      fs.writeFileSync(metaFile, JSON.stringify(result.metafile || {}), { encoding: 'utf-8' });\n      spawnSync('npx', ['esbuild-visualizer', '--metadata', metaFile, '--filename', statsFile], {\n        shell: true,\n        stdio: 'inherit',\n      });\n      spawnSync('open', [statsFile], {\n        shell: true,\n        stdio: 'inherit',\n      });\n      return;\n    }\n\n    const outFileContent = transformCjsToUmdFile(buildConfig.outfile);\n\n    console.log('minifying...');\n    const minifiedOutFile = buildConfig.outfile.replace(/\\.js$/, '.min.js');\n    const minifiedResult = esbuild.transformSync(outFileContent, {\n      minify: true,\n      sourcemap: true,\n      sourcesContent: true,\n      sourcefile: path.basename(buildConfig.outfile),\n    });\n\n    fs.writeFileSync(minifiedOutFile, minifiedResult.code, { encoding: 'utf-8' });\n    fs.writeFileSync(`${minifiedOutFile}.map`, minifiedResult.map, { encoding: 'utf-8' });\n\n    minifiedResult.warnings.forEach((warnings) => {\n      console.log(warnings);\n    });\n\n    console.log('done');\n  } catch (e) {\n    console.error(e);\n    process.exit(1);\n  }\n})();\n\n// esbuild 没有直接提供 UMD 格式，所以这里我们自行包装转换下\nfunction transformCjsToUmdFile(file) {\n  const globalName = UMD_GLOBAL_NAME;\n  const fileContent = fs.readFileSync(file, { encoding: 'utf-8' });\n  const transformedFileContent = `(function (global, factory) {\n  if (typeof exports === 'object' && typeof module !== 'undefined'){\n    factory(module, exports);\n  } else if (typeof define === 'function' && define.amd) {\n    define(['module', 'exports'], factory);\n  } else {\n    global = global || self;\n    var m = { exports: {} };\n    factory(m, m.exports);\n    global.${globalName} = m.exports;\n  }\n}(this, function (module, exports) {\n  'use strict';\n  ${fileContent};\n  return module.exports;\n}));\n`;\n\n  fs.writeFileSync(file, transformedFileContent, { encoding: 'utf-8' });\n  return transformedFileContent;\n}\n"
  },
  {
    "path": "modules/code-generator/scripts/build-template-static-files.js",
    "content": "/* eslint-disable no-console */\n/* eslint-disable @typescript-eslint/quotes */\n/* eslint-disable @typescript-eslint/ban-ts-comment */\n/* eslint-disable @typescript-eslint/no-require-imports */\n// @ts-check\n// 这个文件是用来构建模板中的静态文件的\nconst fs = require('fs');\nconst glob = require('glob');\nconst path = require('path');\nconst JSON5 = require('json5');\nconst { spawnSync } = require('child_process');\n\nconst PROJECT_ROOT = path.join(__dirname, '..');\n\nconst TEMPLATES = [\n  {\n    sourceDir: path.join(PROJECT_ROOT, 'static-files/rax'),\n    outputDir: path.join(PROJECT_ROOT, 'src/plugins/project/framework/rax/template'),\n  },\n];\n\ntry {\n  TEMPLATES.forEach(buildTemplateStaticFiles);\n  console.log('All done.');\n} catch (e) {\n  console.error(e);\n  process.exit(1);\n}\n\nfunction buildTemplateStaticFiles({ sourceDir, outputDir }) {\n  console.log('processing %s template...', path.dirname(sourceDir));\n\n  // 扫描所有的目录\n  const sourceFiles = glob.sync('**/*', {\n    nodir: true,\n    dot: true,\n    cwd: sourceDir,\n  });\n\n  console.log('got %d files: %o', sourceFiles.length, sourceFiles);\n\n  const staticFiles = {\n    imports: [],\n    runs: [],\n  };\n\n  // 生成对应的文件\n  sourceFiles.forEach((sourceFileName, index) => {\n    console.log('processing %s', sourceFileName);\n    const sourceFileContent = fs.readFileSync(path.join(sourceDir, sourceFileName), 'utf-8');\n    const sourceFileRealName = sourceFileName.replace(/\\.template$/, '');\n    const outputFileName = `${sourceFileRealName}.ts`;\n    const outputFileFullPath = path.join(outputDir, 'files', outputFileName);\n\n    const sourceFileExtName = path.extname(sourceFileRealName);\n    const sourceFileBaseName = path.basename(sourceFileRealName, sourceFileExtName);\n\n    // 确保目录存在\n    fs.mkdirSync(path.dirname(outputFileFullPath), { recursive: true });\n\n    // 写入文件\n    fs.writeFileSync(\n      outputFileFullPath,\n      [\n        `/* eslint-disable max-len */`,\n        `/* Note: this file is generated by \"npm run template\", please dont modify this file directly */`,\n        `/* -- instead, you should modify \"${path.relative(\n          PROJECT_ROOT,\n          path.join(sourceDir, sourceFileName),\n        )}\" and run \"npm run template\" */`,\n        `import { ResultFile } from '@alilc/lowcode-types';`,\n        '',\n        `export default function getFile(): [string[], ResultFile] {`,\n        `  return ${JSON5.stringify([\n          // 文件目录：\n          path.dirname(sourceFileRealName).split(path.sep).filter(Boolean),\n          // 文件名和内容:\n          {\n            name: sourceFileBaseName,\n            ext: sourceFileExtName.replace(/^\\./, ''),\n            content: sourceFileContent,\n          },\n        ])};`,\n        `}`,\n        '',\n      ].join('\\n'),\n      {\n        encoding: 'utf-8',\n      },\n    );\n\n    staticFiles.imports.push(`import file${index} from './files/${sourceFileRealName}';`);\n\n    staticFiles.runs.push(`  runFileGenerator(root, file${index})`);\n  });\n\n  console.log('generating static-files.ts...');\n  fs.writeFileSync(\n    path.join(outputDir, 'static-files.ts'),\n    [\n      `/* Note: this file is generated by \"npm run template\", please dont modify this file directly */`,\n      `import { ResultDir } from '@alilc/lowcode-types';\n\n      import { createResultDir } from '../../../../../utils/resultHelper';\n      import { runFileGenerator } from '../../../../../utils/templateHelper';`,\n      ...staticFiles.imports,\n      '',\n      `export function generateStaticFiles(root = createResultDir('.')): ResultDir {`,\n      ...staticFiles.runs,\n      `  return root;`,\n      `}`,\n      '',\n    ].join('\\n'),\n    { encoding: 'utf-8' },\n  );\n\n  // prettier 一把\n  console.log('run prettier...');\n  spawnSync('npx', ['prettier', '--write', `${outputDir}`], {\n    stdio: 'inherit',\n    shell: true,\n  });\n\n  console.log('done %s', path.basename(sourceDir));\n}\n"
  },
  {
    "path": "modules/code-generator/scripts/build-types",
    "content": "#!/bin/sh\n\necho building types...\ntsc --outDir types --declaration --emitDeclarationOnly &&  \\\n  echo built types... && \\\n  rm -rf types/packages && \\\n  mv types/modules/code-generator/src/* types/ && \\\n  rm -rf types/modules\n\n\n"
  },
  {
    "path": "modules/code-generator/scripts/build.js",
    "content": "/* eslint-disable no-console */\n/* eslint-disable @typescript-eslint/no-require-imports */\nconst _ = require('lodash');\nconst esbuild = require('esbuild');\nconst concurrently = require('concurrently');\nconst argv = require('yargs-parser')(process.argv.slice(2));\nconst packageJson = require('../package.json');\n\nif (!argv.format) {\n  buildAll();\n} else {\n  buildFormat(argv.format, argv.out || 'dist');\n}\n\nfunction buildAll() {\n  concurrently(\n    [\n      { name: 'build:types', command: 'sh scripts/build-types' },\n      { name: 'build:cjs', command: 'node scripts/build --format=cjs --out=lib' },\n      { name: 'build:esm', command: 'node scripts/build --format=esm --out=es' },\n      { name: 'build:standalone', command: 'node scripts/build-standalone' },\n      { name: 'build:standalone-worker', command: 'node scripts/build-standalone-worker' },\n      { name: 'build:standalone-loader', command: 'node scripts/build-standalone-loader' },\n      { name: 'build:cli', command: 'node scripts/build-cli' },\n    ],\n    {\n      prefix: 'name',\n      killOthers: ['failure'],\n      restartTries: 0,\n    },\n  ).then(\n    () => {\n      console.log('all done.');\n    },\n    () => {\n      process.exit(1);\n    },\n  );\n}\n\nfunction buildFormat(format, outDir) {\n  try {\n    console.log('building %s...', format);\n    const startTime = Date.now();\n    const result = esbuild.buildSync({\n      entryPoints: ['src/index.ts'],\n      outfile: `${outDir}/index.js`,\n      bundle: true,\n      platform: 'node',\n      target: ['node10'],\n      format,\n      sourcemap: true,\n      sourcesContent: true,\n      define: {},\n      treeShaking: true,\n      external: _.keys(packageJson.dependencies),\n      minify: false,\n      legalComments: 'external',\n    });\n    if (result.errors.length > 0) {\n      throw result.errors;\n    }\n\n    if (result.warnings.length > 0) {\n      result.warnings.forEach((warnings) => {\n        console.warn(warnings);\n      });\n    }\n\n    console.log('built %s in %ds', format, ((Date.now() - startTime) / 1000).toFixed(2));\n  } catch (e) {\n    console.error(e);\n    process.exit(1);\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/scripts/move-files-to-build-dest.js",
    "content": "/* eslint-disable @typescript-eslint/no-require-imports */\nconst fs = require('fs');\nconst { spawnSync } = require('child_process');\n\nconst BUILD_DEST = process.env.BUILD_DEST || '.package';\n\nfs.mkdirSync(BUILD_DEST, { recursive: true });\n\nconst distFiles = [...require('../package.json').files, 'package.json'];\n\ndistFiles.forEach((file) => {\n  console.log('mv %s', file);\n  if (file === BUILD_DEST) {\n    fs.mkdirSync(`${BUILD_DEST}/${file}`, { recursive: true });\n    spawnSync('mv', [`${file}/*`, `${BUILD_DEST}/${file}/`], { shell: true, stdio: 'inherit' });\n  }\n});\n\ndistFiles.forEach((file) => {\n  console.log('mv %s', file);\n  if (file !== BUILD_DEST) {\n    spawnSync('mv', [file, `${BUILD_DEST}/${file}`], { shell: true, stdio: 'inherit' });\n  }\n});\n"
  },
  {
    "path": "modules/code-generator/scripts/run-demo-project",
    "content": "#!/usr/bin/env node\n\n// @ts-check\nconst program = require('commander');\nconst { spawnSync } = require('child_process');\nconst glob = require('glob');\nconst fs = require('fs');\nconst path = require('path');\nconst _ = require('lodash');\n\nprogram\n  .option('--npm <npm>', 'specify the npm command location or alias')\n  .arguments('<project>')\n  .action((project, options) => {\n    try {\n      if (!fs.existsSync(project)) {\n        throw new Error(`Project ${project} does not exist`);\n      }\n\n      const getProjectActualPath = [\n        () => path.resolve(process.cwd(), project),\n        () =>\n          path.resolve(\n            process.cwd(),\n            path.join(\n              project,\n              path.dirname(glob.sync('*/package.json', { cwd: project })[0] || ''),\n            ),\n          ),\n      ]\n        .map((x) => _.memoize(x))\n        .find((x) => fs.existsSync(path.join(x(), 'package.json')));\n\n      if (!getProjectActualPath) {\n        throw new Error(`Project ${project} is not a valid project(no package.json)`);\n      }\n\n      const projectActualPath = getProjectActualPath();\n      if (path.resolve(process.cwd(), project) !== projectActualPath) {\n        console.log('Changing directory to', path.relative(process.cwd(), projectActualPath));\n      }\n\n      process.chdir(projectActualPath);\n\n      const npm = options.npm || 'npm';\n      const cmd = `${npm} install && ${npm} start`;\n      console.log('# %s', cmd);\n      spawnSync(cmd, { stdio: 'inherit', shell: true });\n    } catch (err) {\n      console.log(err);\n      process.exit(1);\n    }\n  });\n\nprogram.parse(process.argv);\n"
  },
  {
    "path": "modules/code-generator/scripts/test-standalone.js",
    "content": "// 测试 standalone 模式的基本功能\n// 注1：指定文件测试就直接在后面加文件: node scripts/test-standalone.js tests/public/rax-app.test.ts\n// 注2：指定测试用例就直接在后面加`-t xxx`: node scripts/test-standalone.js tests/public/rax-app.test.ts -t demo01\nconst { spawnSync } = require('child_process');\n\n// 一定要先构建\nspawnSync('npm', ['run', 'build:standalone'], { shell: true, stdio: 'inherit' });\n\n// 然后只执行特定的一些测试用例\nspawnSync('npx', ['jest', ...process.argv.slice(2)], {\n  env: {\n    ...process.env,\n    TEST_TARGET: 'standalone',\n  },\n  shell: true,\n  stdio: 'inherit',\n});\n"
  },
  {
    "path": "modules/code-generator/src/analyzer/componentAnalyzer.ts",
    "content": "import type { IPublicTypeNodeSchema, IPublicTypeCompositeObject } from '@alilc/lowcode-types';\nimport type { TComponentAnalyzer } from '../types';\n\nimport { handleSubNodes } from '../utils/schema';\n\nexport const componentAnalyzer: TComponentAnalyzer = (container) => {\n  let hasRefAttr = false;\n  const nodeValidator = (n: IPublicTypeNodeSchema) => {\n    if (n.props) {\n      const props = n.props as IPublicTypeCompositeObject;\n      if (props.ref) {\n        hasRefAttr = true;\n      }\n    }\n  };\n\n  nodeValidator(container);\n\n  if (!hasRefAttr && container.children) {\n    // eslint-disable-next-line @typescript-eslint/no-invalid-void-type\n    handleSubNodes<void>(\n      container.children,\n      {\n        node: nodeValidator,\n      },\n      {\n        rerun: true,\n      },\n    );\n  }\n\n  return {\n    isUsingRef: hasRefAttr,\n  };\n};\n"
  },
  {
    "path": "modules/code-generator/src/cli/index.ts",
    "content": "export * from './run';\nexport * from './init-solution';\n"
  },
  {
    "path": "modules/code-generator/src/cli/init-solution.ts",
    "content": "/* eslint-disable no-console */\nimport * as fs from 'fs-extra';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport * as changeCase from 'change-case';\nimport { getErrorMessage } from '../utils/errors';\nimport { getLowcodeSolutionTemplateFiles } from './solutions/example-solution';\n\n\nexport async function initSolution(args: string[], options: {\n  quiet?: boolean;\n  verbose?: boolean;\n}) {\n  try {\n    const cwd = process.cwd();\n    let solutionName = args[0] || 'hello';\n    let solutionPath = path.resolve(cwd, solutionName);\n    if (solutionName === '.') {\n      solutionName = path.basename(cwd);\n      solutionPath = cwd;\n    }\n\n    const modifyFileContent = (content: string) =>\n      content\n        .replace(/hello-world/g, changeCase.paramCase(solutionName))\n        .replace(/HelloWorld/g, changeCase.pascalCase(solutionName))\n        .replace(/Hello World/g, changeCase.titleCase(solutionName));\n\n    await ensureDirExists(solutionPath);\n\n    const templateFiles = getLowcodeSolutionTemplateFiles();\n    for (const templateFile of templateFiles) {\n      if (options.verbose) {\n        console.log('%s', chalk.gray(`creating file ${templateFile.file}`));\n      }\n\n      const templateFilePath = path.join(solutionPath, templateFile.file);\n      await ensureDirExists(path.dirname(templateFilePath));\n      await fs.writeFile(templateFilePath, modifyFileContent(templateFile.content), { encoding: 'utf-8' });\n    }\n\n    if (!options.quiet) {\n      console.log('%s', chalk.green(`solution ${solutionName} created successfully`));\n    }\n\n    return 0;\n  } catch (e) {\n    console.log(chalk.red(getErrorMessage(e) || `Unexpected error: ${e}`));\n    if (typeof e === 'object' && (e as { stack: string } | null)?.stack && options.verbose) {\n      console.log(chalk.gray((e as { stack: string }).stack));\n    }\n    return 1;\n  }\n}\n\nasync function ensureDirExists(dirPath: string) {\n  try {\n    await fs.mkdir(dirPath, { recursive: true });\n  } catch (e) {\n    if ((e as { code: string }).code === 'EEXIST') {\n      return;// ignore existing error\n    }\n    throw e;\n  }\n}"
  },
  {
    "path": "modules/code-generator/src/cli/run.ts",
    "content": "/* eslint-disable no-console */\nimport chalk from 'chalk';\nimport * as fs from 'fs-extra';\nimport JSON5 from 'json5';\nimport { jsonc } from 'jsonc';\nimport { spawnSync } from 'child_process';\nimport * as path from 'path';\n\nimport { getErrorMessage } from '../utils/errors';\nimport CodeGenerator from '..';\nimport type { IProjectBuilder } from '..';\nimport type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\n\n/**\n * 执行出码 CLI 命令\n * @param args 入参数组\n * @param options 选项\n * @returns {Promise<number>} 错误码\n */\nexport async function run(\n  args: string[],\n  options: {\n    solution: string;\n    input?: string;\n    output?: string;\n    quiet?: boolean;\n    verbose?: boolean;\n    solutionOptions?: string;\n  },\n): Promise<number> {\n  try {\n    const schemaFile = options.input || args[0];\n    if (!schemaFile) {\n      throw new Error(\n        'a schema file must be specified by `--input <schema.json>` or by the first positional argument',\n      );\n    }\n\n    if ((options.input && args.length > 0) || args.length > 1) {\n      throw new Error(\n        'only one schema file can be specified, either by `--input <schema.json>` or by the first positional argument',\n      );\n    }\n\n    let solutionOptions = {};\n\n    if (options.solutionOptions) {\n      try {\n        solutionOptions = JSON.parse(options.solutionOptions);\n      } catch (err: any) {\n        throw new Error(\n          `solution options parse error, error message is \"${err.message}\"`,\n        );\n      }\n    }\n\n\n    // 读取 Schema\n    const schema = await loadSchemaFile(schemaFile);\n\n    // 创建一个项目构建器\n    const createProjectBuilder = await getProjectBuilderFactory(options.solution, {\n      quiet: options.quiet,\n    });\n    const builder = createProjectBuilder(solutionOptions);\n\n    // 生成代码\n    const generatedSourceCodes = await builder.generateProject(schema);\n\n    // 输出到磁盘\n    const publisher = CodeGenerator.publishers.disk();\n\n    await publisher.publish({\n      project: generatedSourceCodes,\n      outputPath: options.output || 'generated',\n      projectSlug: 'example',\n      createProjectFolder: false,\n    });\n    return 0;\n  } catch (e) {\n    console.log(chalk.red(getErrorMessage(e) || `Unexpected error: ${e}`));\n    if (typeof e === 'object' && (e as { stack: string } | null)?.stack && options.verbose) {\n      console.log(chalk.gray((e as { stack: string }).stack));\n    }\n    return 1;\n  }\n}\n\nasync function getProjectBuilderFactory(\n  solution: string,\n  { quiet }: { quiet?: boolean },\n): Promise<(options: {[prop: string]: any}) => IProjectBuilder> {\n  if (solution in CodeGenerator.solutions) {\n    return CodeGenerator.solutions[solution as 'icejs' | 'rax'];\n  }\n\n  const solutionPackageName = isLocalSolution(solution)\n    ? solution\n    : `${solution.startsWith('@') ? solution : `@alilc/lowcode-solution-${solution}`}`;\n\n  if (!isLocalSolution(solution)) {\n    if (!quiet) {\n      console.log(`\"${solution}\" is not internal, installing it as ${solutionPackageName}...`);\n    }\n\n    spawnSync('npm', ['i', solutionPackageName], {\n      stdio: quiet ? 'ignore' : 'inherit',\n    });\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-require-imports\n  const solutionExports = require(!isLocalSolution(solution)\n    ? solutionPackageName\n    : `${path.isAbsolute(solution) ? solution : path.join(process.cwd(), solution)}`);\n\n  const projectBuilderFactory =\n    solutionExports.createProjectBuilder ||\n    solutionExports.createAppBuilder ||\n    solutionExports.default;\n\n  if (typeof projectBuilderFactory !== 'function') {\n    throw new Error(\n      `\"${solutionPackageName}\" should export project builder factory via named export 'createProjectBuilder' or via default export`,\n    );\n  }\n\n  return projectBuilderFactory;\n}\n\nfunction isLocalSolution(solution: string) {\n  return solution.startsWith('.') || solution.startsWith('/') || solution.startsWith('~');\n}\n\nasync function loadSchemaFile(schemaFile: string): Promise<IPublicTypeProjectSchema> {\n  if (!schemaFile) {\n    throw new Error('invalid schema file name');\n  }\n\n  const schemaFileContent = await fs.readFile(schemaFile, 'utf8');\n\n  if (/\\.json5/.test(schemaFile)) {\n    return JSON5.parse(schemaFileContent);\n  }\n\n  // 默认用 JSONC 的格式解析（兼容 JSON）\n  return jsonc.parse(schemaFileContent);\n}\n"
  },
  {
    "path": "modules/code-generator/src/cli/solutions/example-solution.ts",
    "content": "export function getLowcodeSolutionTemplateFiles() {\n  return [\n    {\n      file: '.editorconfig',\n      content: `root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nquote_type = single\n\n[*.md]\ntrim_trailing_whitespace = false\n`,\n    },\n    {\n      file: '.eslintignore',\n      content: `# 忽略目录\nnode_modules/\nbuild/\ndist/\ntest-cases/\ntest/\ntests/\noutput/\nes/\nlib/\ncoverage/\n\n# 忽略文件\n**/*.min.js\n**/*-min.js\n**/*.bundle.js\n`,\n    },\n    {\n      file: '.eslintrc.js',\n      content: `module.exports = {\n  extends: 'eslint-config-ali/typescript/react',\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'comma-dangle': 0,\n  },\n};\n`,\n    },\n    {\n      file: '.gitignore',\n      content: `# project custom\nbuild\nes\nlib\ndist\noutput\npackage-lock.json\ndeploy-space/packages\ndeploy-space/.env\ngenerated\n\n# IDE\n.vscode\n.idea\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\nlib\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# mac config files\n.DS_Store\n\n# codealike\ncodealike.json\n.node\n`,\n    },\n    {\n      file: '.prettierignore',\n      content: '/test-cases/',\n    },\n    {\n      file: '.prettierrc',\n      content: `{\n  \"tabWidth\": 2,\n  \"singleQuote\": true,\n  \"trailingComma\": \"es5\"\n}\n`,\n    },\n    {\n      file: 'CHANGELOG.md',\n      content: '',\n    },\n    {\n      file: 'CONTRIBUTING.md',\n      content: `# 欢迎共建\n\n# 注意\n\n- 注意解决 eslint 问题\n- 注意代码格式化 -- 建议安装 prettier 插件\n- 发布前注意要跑通 demo 和所有的单测\n\n## 本地调试运行 Demo\n\n\\`\\`\\`sh\n> npm run demo\n\\`\\`\\`\n\n## 本地跑单测\n\n\\`\\`\\`sh\n> npm test\n\\`\\`\\`\n`,\n    },\n    {\n      file: 'README.md',\n      content: `# 低代码出码自定义方案之 Hello World\n\n## 直接执行\n\n\\`\\`\\`sh\n> npx ali-lowcode-solution-hello-world demo-schema.json\n\\`\\`\\`\n\n## 本地调试运行 Demo\n\n\\`\\`\\`sh\n> npm run demo\n\\`\\`\\`\n`,\n    },\n    {\n      file: 'demo-schema.json',\n      content: `{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"componentName\": \"Button\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Button\"\n    },\n    {\n      \"componentName\": \"Button.Group\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Button\",\n      \"subName\": \"Group\"\n    },\n    {\n      \"componentName\": \"Input\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Input\"\n    },\n    {\n      \"componentName\": \"Form\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Form\"\n    },\n    {\n      \"componentName\": \"Form.Item\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Form\",\n      \"subName\": \"Item\"\n    },\n    {\n      \"componentName\": \"NumberPicker\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"NumberPicker\"\n    },\n    {\n      \"componentName\": \"Select\",\n      \"package\": \"@alifd/next\",\n      \"version\": \"1.19.18\",\n      \"destructuring\": true,\n      \"exportName\": \"Select\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node$1\",\n      \"meta\": {\n        \"title\": \"测试\",\n        \"router\": \"/\"\n      },\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"autoLoading\": true\n      },\n      \"fileName\": \"test\",\n      \"state\": {\n        \"text\": \"outter\"\n      },\n      \"lifeCycles\": {\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function componentDidMount() {\\\\n  console.log('componentDidMount');\\\\n}\"\n        }\n      },\n      \"methodsModule\": {\n        \"type\": \"JSModule\",\n        \"source\": \"export function helloWorld() {\\\\n  console.log('Hello world!');\\\\n}\\\\n\"\n      },\n      \"dataSource\": {\n        \"list\": [\n          {\n            \"id\": \"urlParams\",\n            \"type\": \"urlParams\"\n          },\n\n          {\n            \"id\": \"user\",\n            \"type\": \"fetch\",\n            \"options\": {\n              \"method\": \"GET\",\n              \"uri\": \"https://shs.xxx.com/mock/1458/demo/user\",\n              \"isSync\": true\n            },\n            \"dataHandler\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"function (response) {\\\\nif (!response.data.success){\\\\n    throw new Error(response.data.message);\\\\n  }\\\\n  return response.data.data;\\\\n}\"\n            }\n          },\n\n          {\n            \"id\": \"orders\",\n            \"type\": \"fetch\",\n            \"options\": {\n              \"method\": \"GET\",\n              \"uri\": \"https://shs.xxx.com/mock/1458/demo/orders\",\n              \"isSync\": true\n            },\n            \"dataHandler\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"function (response) {\\\\nif (!response.data.success){\\\\n    throw new Error(response.data.message);\\\\n  }\\\\n  return response.data.data.result;\\\\n}\"\n            }\n          }\n        ],\n        \"dataHandler\": {\n          \"type\": \"JSExpression\",\n          \"value\": \"function (dataMap) {\\\\n  console.info(\\\\\"All datasources loaded:\\\\\", dataMap);\\\\n}\"\n        }\n      },\n      \"children\": [\n        {\n          \"componentName\": \"Form\",\n          \"id\": \"node$2\",\n          \"props\": {\n            \"labelCol\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"this.state.colNum\"\n            },\n            \"style\": {},\n            \"ref\": \"testForm\"\n          },\n          \"children\": [\n            {\n              \"componentName\": \"Form.Item\",\n              \"id\": \"node$3\",\n              \"props\": {\n                \"label\": \"姓名：\",\n                \"name\": \"name\",\n                \"initValue\": \"李雷\"\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"Input\",\n                  \"id\": \"node$4\",\n                  \"props\": {\n                    \"placeholder\": \"请输入\",\n                    \"size\": \"medium\",\n                    \"style\": {\n                      \"width\": 320\n                    }\n                  }\n                }\n              ]\n            },\n            {\n              \"componentName\": \"Form.Item\",\n              \"id\": \"node$5\",\n              \"props\": {\n                \"label\": \"年龄：\",\n                \"name\": \"age\",\n                \"initValue\": \"22\"\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"NumberPicker\",\n                  \"id\": \"node$6\",\n                  \"props\": {\n                    \"size\": \"medium\",\n                    \"type\": \"normal\"\n                  }\n                }\n              ]\n            },\n            {\n              \"componentName\": \"Form.Item\",\n              \"id\": \"node$7\",\n              \"props\": {\n                \"label\": \"职业：\",\n                \"name\": \"profession\"\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"Select\",\n                  \"id\": \"node$8\",\n                  \"props\": {\n                    \"dataSource\": [\n                      {\n                        \"label\": \"教师\",\n                        \"value\": \"t\"\n                      },\n                      {\n                        \"label\": \"医生\",\n                        \"value\": \"d\"\n                      },\n                      {\n                        \"label\": \"歌手\",\n                        \"value\": \"s\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            {\n              \"componentName\": \"Div\",\n              \"id\": \"node$9\",\n              \"props\": {\n                \"style\": {\n                  \"textAlign\": \"center\"\n                }\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"Button.Group\",\n                  \"id\": \"node$a\",\n                  \"props\": {},\n                  \"children\": [\n                    {\n                      \"componentName\": \"Button\",\n                      \"id\": \"node$b\",\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.index >= 1\"\n                      },\n                      \"loop\": [\"a\", \"b\", \"c\"],\n                      \"props\": {\n                        \"type\": \"primary\",\n                        \"style\": {\n                          \"margin\": \"0 5px 0 5px\"\n                        }\n                      },\n                      \"children\": [\n                        {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.item\"\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"constants\": {\n    \"ENV\": \"prod\",\n    \"DOMAIN\": \"xxx.xxx.com\"\n  },\n  \"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n  \"config\": {\n    \"sdkVersion\": \"1.0.3\",\n    \"historyMode\": \"hash\",\n    \"targetRootID\": \"J_Container\",\n    \"layout\": {\n      \"componentName\": \"BasicLayout\",\n      \"props\": {\n        \"logo\": \"...\",\n        \"name\": \"测试网站\"\n      }\n    },\n    \"theme\": {\n      \"package\": \"@alife/theme-fusion\",\n      \"version\": \"^0.1.0\",\n      \"primary\": \"#ff9966\"\n    }\n  },\n  \"meta\": {\n    \"name\": \"demo应用\",\n    \"git_group\": \"appGroup\",\n    \"project_name\": \"app_demo\",\n    \"description\": \"这是一个测试应用\",\n    \"spma\": \"spa23d\",\n    \"creator\": \"月飞\"\n  }\n}\n`,\n    },\n    {\n      file: 'jest.config.js',\n      content: `module.exports = {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n  testPathIgnorePatterns: ['/node_modules/', '/test-cases/', '/static-files/', '/lib/'],\n};\n`,\n    },\n    {\n      file: 'package.json',\n      content: `{\n  \"name\": \"ali-lowcode-solution-hello-world\",\n  \"version\": \"1.0.0\",\n  \"description\": \"AlLowCode Code Generate Solution - Hello World\",\n  \"files\": [\n    \"src\",\n    \"lib\",\n    \"tests\",\n    \"jest.config.js\",\n    \".editorconfig\",\n    \".eslintignore\",\n    \".eslintrc.js\",\n    \".gitignore\",\n    \".prettierignore\",\n    \".prettierrc\",\n    \"CHANGELOG.md\",\n    \"CONTRIBUTING.md\",\n    \"demo-schema.json\",\n    \"package.json\",\n    \"README.md\",\n    \"tsconfig.json\"\n  ],\n  \"main\": \"lib/index.js\",\n  \"scripts\": {\n    \"start\": \"jest --watch\",\n    \"build\": \"npm run clean && concurrently 'npm run build:ts' 'npm run lint'\",\n    \"build:ts\": \"tsc\",\n    \"check:type\": \"tsc -p . --noEmit\",\n    \"clean\": \"rm -rf build dist lib generated\",\n    \"dev\": \"build-scripts start\",\n    \"lint\": \"eslint --ext .tsx,.ts,.js,.jsx src\",\n    \"lintfix\": \"eslint --fix --color --ext .tsx,.ts,.js,.jsx src\",\n    \"lint-staged\": \"lint-staged\",\n    \"prepublishOnly\": \"npm run build\",\n    \"postpublish\": \"git push origin master --tags\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:update-snapshots\": \"cross-env UPDATE_EXPECTED=true npx jest\",\n    \"demo\": \"npm run build && npx @alilc/lowcode-code-generator --solution . --output generated demo-schema.json\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git@github.com:your-name/ali-lowcode-solution-hello-world.git\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npm.xxx.com\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-code-generator\": \"^1.0.0\",\n    \"@alilc/lowcode-types\": \"^1.0.0\",\n    \"tslib\": \"^2.3.0\"\n  },\n  \"devDependencies\": {\n    \"@types/async\": \"^3.2.3\",\n    \"@types/jest\": \"^26.0.17\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.28.4\",\n    \"@typescript-eslint/parser\": \"^4.28.4\",\n    \"async\": \"^3.2.0\",\n    \"babel-runtime\": \"^6.26.0\",\n    \"concurrently\": \"^5.2.0\",\n    \"cross-env\": \"^7.0.0\",\n    \"debug\": \"^4.1.1\",\n    \"eslint\": \"^7.31.0\",\n    \"eslint-config-ali\": \"^12.1.0\",\n    \"eslint-plugin-import\": \"^2.23.4\",\n    \"eslint-plugin-react\": \"^7.24.0\",\n    \"eslint-plugin-react-hooks\": \"^4.2.0\",\n    \"glob\": \"^7.2.0\",\n    \"husky\": \"4.2.5\",\n    \"jest\": \"^26.6.3\",\n    \"json5\": \"^2.2.0\",\n    \"lint-staged\": \"10.1.x\",\n    \"lodash\": \"^4.17.21\",\n    \"md5\": \"^2.2.1\",\n    \"prettier\": \"^2.3.2\",\n    \"ts-jest\": \"^26.4.4\",\n    \"ts-node\": \"^9.0.0\",\n    \"typescript\": \"4.x\"\n  }\n}\n`,\n    },\n    {\n      file: 'tsconfig.json',\n      content: `{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"importHelpers\": true,\n    \"incremental\": false,\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"stripInternal\": true,\n    \"outDir\": \"./lib\",\n    \"declarationDir\": \"./lib\",\n    \"rootDirs\": [\"./src\"],\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"lib\": [\"esnext\"],\n    \"types\": [\"jest\", \"node\"],\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false\n  },\n  \"include\": [\"src/**/*\", \"typings/**/*\"]\n}\n`,\n    },\n    {\n      file: 'src/index.ts',\n      content: `import CodeGen from '@alilc/lowcode-code-generator';\n\nimport examplePlugin from './plugins/example';\n\nexport default function createHelloWorldProjectBuilder() {\n  return CodeGen.createProjectBuilder({\n    template: CodeGen.solutionParts.icejs.template,\n    plugins: {\n      components: [\n        CodeGen.plugins.icejs.reactCommonDeps(),\n        CodeGen.plugins.common.esModule({ fileType: 'jsx' }),\n        CodeGen.plugins.common.styleImport(),\n        CodeGen.plugins.icejs.containerClass(),\n        CodeGen.plugins.icejs.containerInjectContext(),\n        CodeGen.plugins.icejs.containerInjectUtils(),\n        CodeGen.plugins.icejs.containerInjectDataSourceEngine(),\n        CodeGen.plugins.icejs.containerInjectI18n(),\n        CodeGen.plugins.icejs.containerInjectConstants(),\n        CodeGen.plugins.icejs.containerInitState(),\n        CodeGen.plugins.icejs.containerLifeCycle(),\n        CodeGen.plugins.icejs.containerMethod(),\n        examplePlugin(),\n        CodeGen.plugins.icejs.jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Page: 'div',\n            Block: 'div',\n          },\n        }),\n        CodeGen.plugins.style.css(),\n      ],\n      pages: [\n        CodeGen.plugins.icejs.reactCommonDeps(),\n        CodeGen.plugins.common.esModule({ fileType: 'jsx' }),\n        CodeGen.plugins.common.styleImport(),\n        CodeGen.plugins.icejs.containerClass(),\n        CodeGen.plugins.icejs.containerInjectContext(),\n        CodeGen.plugins.icejs.containerInjectUtils(),\n        CodeGen.plugins.icejs.containerInjectDataSourceEngine(),\n        CodeGen.plugins.icejs.containerInjectI18n(),\n        CodeGen.plugins.icejs.containerInjectConstants(),\n        CodeGen.plugins.icejs.containerInitState(),\n        CodeGen.plugins.icejs.containerLifeCycle(),\n        CodeGen.plugins.icejs.containerMethod(),\n        examplePlugin(),\n        CodeGen.plugins.icejs.jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Page: 'div',\n            Block: 'div',\n          },\n        }),\n        CodeGen.plugins.style.css(),\n      ],\n      router: [\n        CodeGen.plugins.common.esModule(),\n        CodeGen.solutionParts.icejs.plugins.router(),\n      ],\n      entry: [CodeGen.solutionParts.icejs.plugins.entry()],\n      constants: [CodeGen.plugins.project.constants()],\n      utils: [\n        CodeGen.plugins.common.esModule(),\n        CodeGen.plugins.project.utils('react'),\n      ],\n      i18n: [CodeGen.plugins.project.i18n()],\n      globalStyle: [CodeGen.solutionParts.icejs.plugins.globalStyle()],\n      htmlEntry: [CodeGen.solutionParts.icejs.plugins.entryHtml()],\n      packageJSON: [CodeGen.solutionParts.icejs.plugins.packageJSON()],\n    },\n    postProcessors: [CodeGen.postprocessor.prettier()],\n  });\n}\n`,\n    },\n    {\n      file: 'src/plugins/example.ts',\n      content: `import {\n  ICodeStruct,\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  FileType,\n  ChunkType,\n  IContainerInfo,\n  COMMON_CHUNK_NAME,\n  CLASS_DEFINE_CHUNK_NAME,\n  DEFAULT_LINK_AFTER,\n} from '@alilc/lowcode-code-generator';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (\n  config?\n) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo & {\n      methodsModule?: {\n        type?: 'JSModule';\n        source?: string;\n      };\n    };\n\n    if (ir.methodsModule?.type !== 'JSModule' || !ir.methodsModule?.source) {\n      return next;\n    }\n\n    // 创建 methods.jsx\n    next.chunks.push({\n      type: ChunkType.STRING,\n      subModule: 'methods',\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.CustomContent,\n      content: ir.methodsModule.source,\n      linkAfter: [],\n    });\n\n    // 引入对应的模块\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: \"import __$$methodsModule from './methods';\",\n      linkAfter: [...DEFAULT_LINK_AFTER[COMMON_CHUNK_NAME.InternalDepsImport]],\n    });\n\n    // 将导出的东东都放到 class 上实例方法部分\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n      content: 'Object.assign(this, __$$methodsModule);',\n      linkAfter: [\n        ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent],\n      ],\n    });\n\n    return next;\n  };\n\n  return plugin;\n};\n\nexport default pluginFactory;\n`,\n    },\n    {\n      file: 'tests/basic.test.ts',\n      content: `test('basic functions should be ok', () => {\n  // 这里放一些单元测试\n  expect(0).toBe(0);\n});\n`,\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/config/env.ts",
    "content": "import * as path from 'path';\n\nexport const CODE_GENERATOR_ROOT = path.join(__dirname, '../..');\n"
  },
  {
    "path": "modules/code-generator/src/const/file.ts",
    "content": "import { FileType } from '../types/core';\n\nexport const FILE_TYPE_FAMILY = [[FileType.TSX, FileType.TS, FileType.JSX, FileType.JS]];\n"
  },
  {
    "path": "modules/code-generator/src/const/generator.ts",
    "content": "export const COMMON_CHUNK_NAME = {\n  ExternalDepsImport: 'CommonExternalDependencyImport',\n  InternalDepsImport: 'CommonInternalDependencyImport',\n  ImportAliasDefine: 'CommonImportAliasDefine',\n  FileVarDefine: 'CommonFileScopeVarDefine',\n  FileUtilDefine: 'CommonFileScopeMethodDefine',\n  FileMainContent: 'CommonFileMainContent',\n  FileExport: 'CommonFileExport',\n  StyleDepsImport: 'CommonStyleDepsImport',\n  StyleCssContent: 'CommonStyleCssContent',\n  HtmlContent: 'CommonHtmlContent',\n  CustomContent: 'CommonCustomContent',\n};\n\nexport const CLASS_DEFINE_CHUNK_NAME = {\n  Start: 'CommonClassDefineStart',\n  ConstructorStart: 'CommonClassDefineConstructorStart',\n  ConstructorContent: 'CommonClassDefineConstructorContent',\n  ConstructorEnd: 'CommonClassDefineConstructorEnd',\n  StaticVar: 'CommonClassDefineStaticVar',\n  StaticMethod: 'CommonClassDefineStaticMethod',\n  InsVar: 'CommonClassDefineInsVar',\n  InsVarMethod: 'CommonClassDefineInsVarMethod',\n  InsMethod: 'CommonClassDefineInsMethod',\n  InsPrivateMethod: 'CommonClassDefineInsPrivateMethod',\n  End: 'CommonClassDefineEnd',\n};\n\nexport const DEFAULT_LINK_AFTER = {\n  [COMMON_CHUNK_NAME.ExternalDepsImport]: [],\n  [COMMON_CHUNK_NAME.InternalDepsImport]: [COMMON_CHUNK_NAME.ExternalDepsImport],\n  [COMMON_CHUNK_NAME.ImportAliasDefine]: [\n    COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport,\n  ],\n  [COMMON_CHUNK_NAME.FileVarDefine]: [\n    COMMON_CHUNK_NAME.ExternalDepsImport,\n    COMMON_CHUNK_NAME.InternalDepsImport,\n    COMMON_CHUNK_NAME.ImportAliasDefine,\n  ],\n  [COMMON_CHUNK_NAME.FileUtilDefine]: [\n    COMMON_CHUNK_NAME.ExternalDepsImport,\n    COMMON_CHUNK_NAME.InternalDepsImport,\n    COMMON_CHUNK_NAME.ImportAliasDefine,\n    COMMON_CHUNK_NAME.FileVarDefine,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.Start]: [\n    COMMON_CHUNK_NAME.ExternalDepsImport,\n    COMMON_CHUNK_NAME.InternalDepsImport,\n    COMMON_CHUNK_NAME.ImportAliasDefine,\n    COMMON_CHUNK_NAME.FileVarDefine,\n    COMMON_CHUNK_NAME.FileUtilDefine,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.ConstructorStart]: [\n    CLASS_DEFINE_CHUNK_NAME.Start,\n    CLASS_DEFINE_CHUNK_NAME.StaticVar,\n    CLASS_DEFINE_CHUNK_NAME.StaticMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsVar,\n    CLASS_DEFINE_CHUNK_NAME.InsVarMethod,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.ConstructorContent]: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],\n  [CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]: [\n    CLASS_DEFINE_CHUNK_NAME.ConstructorStart,\n    CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.StaticVar]: [CLASS_DEFINE_CHUNK_NAME.Start],\n  [CLASS_DEFINE_CHUNK_NAME.StaticMethod]: [\n    CLASS_DEFINE_CHUNK_NAME.Start, CLASS_DEFINE_CHUNK_NAME.StaticVar,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.InsVar]: [\n    CLASS_DEFINE_CHUNK_NAME.Start,\n    CLASS_DEFINE_CHUNK_NAME.StaticVar,\n    CLASS_DEFINE_CHUNK_NAME.StaticMethod,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.InsVarMethod]: [\n    CLASS_DEFINE_CHUNK_NAME.Start,\n    CLASS_DEFINE_CHUNK_NAME.StaticVar,\n    CLASS_DEFINE_CHUNK_NAME.StaticMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsVar,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.InsMethod]: [\n    CLASS_DEFINE_CHUNK_NAME.Start,\n    CLASS_DEFINE_CHUNK_NAME.StaticVar,\n    CLASS_DEFINE_CHUNK_NAME.StaticMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsVar,\n    CLASS_DEFINE_CHUNK_NAME.InsVarMethod,\n    CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod]: [\n    CLASS_DEFINE_CHUNK_NAME.Start,\n    CLASS_DEFINE_CHUNK_NAME.StaticVar,\n    CLASS_DEFINE_CHUNK_NAME.StaticMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsVar,\n    CLASS_DEFINE_CHUNK_NAME.InsVarMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsMethod,\n    CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,\n  ],\n  [CLASS_DEFINE_CHUNK_NAME.End]: [\n    CLASS_DEFINE_CHUNK_NAME.Start,\n    CLASS_DEFINE_CHUNK_NAME.StaticVar,\n    CLASS_DEFINE_CHUNK_NAME.StaticMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsVar,\n    CLASS_DEFINE_CHUNK_NAME.InsVarMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsMethod,\n    CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,\n    CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,\n  ],\n  [COMMON_CHUNK_NAME.FileMainContent]: [\n    COMMON_CHUNK_NAME.ExternalDepsImport,\n    COMMON_CHUNK_NAME.InternalDepsImport,\n    COMMON_CHUNK_NAME.ImportAliasDefine,\n    COMMON_CHUNK_NAME.FileVarDefine,\n    COMMON_CHUNK_NAME.FileUtilDefine,\n    CLASS_DEFINE_CHUNK_NAME.End,\n  ],\n  [COMMON_CHUNK_NAME.FileExport]: [\n    COMMON_CHUNK_NAME.ExternalDepsImport,\n    COMMON_CHUNK_NAME.InternalDepsImport,\n    COMMON_CHUNK_NAME.ImportAliasDefine,\n    COMMON_CHUNK_NAME.FileVarDefine,\n    COMMON_CHUNK_NAME.FileUtilDefine,\n    CLASS_DEFINE_CHUNK_NAME.End,\n    COMMON_CHUNK_NAME.FileMainContent,\n  ],\n  [COMMON_CHUNK_NAME.StyleDepsImport]: [],\n  [COMMON_CHUNK_NAME.StyleCssContent]: [COMMON_CHUNK_NAME.StyleDepsImport],\n  [COMMON_CHUNK_NAME.HtmlContent]: [],\n};\n\nexport const COMMON_SUB_MODULE_NAME = 'index';\n"
  },
  {
    "path": "modules/code-generator/src/const/index.ts",
    "content": "export const NATIVE_ELE_PKG = 'native';\n\nexport const CONTAINER_TYPE = {\n  COMPONENT: 'Component',\n  BLOCK: 'Block',\n  PAGE: 'Page',\n};\n\nexport const SUPPORT_SCHEMA_VERSION_LIST = ['0.0.1', '1.0.0'];\n\n// built-in slot names which have been handled in ProjectBuilder\nexport const BUILTIN_SLOT_NAMES = [\n  'pages',\n  'components',\n  'router',\n  'entry',\n  'appConfig',\n  'buildConfig',\n  'constants',\n  'utils',\n  'i18n',\n  'globalStyle',\n  'htmlEntry',\n  'packageJSON',\n  'demo',\n];\n\nexport const isBuiltinSlotName = function (name: string) {\n  return BUILTIN_SLOT_NAMES.includes(name);\n};\n\nexport * from './file';\nexport * from './generator';\n"
  },
  {
    "path": "modules/code-generator/src/core/jsx/handlers/transformJsExpression.ts",
    "content": "import { IScope } from '../../../types';\nimport { parseExpression } from '../../../utils/expressionParser';\nimport { isLiteralAtomicExpr } from '../util/isLiteralAtomicExpr';\nimport { isSimpleStraightLiteral } from '../util/isSimpleStraightLiteral';\nimport { transformThis2Context } from './transformThis2Context';\n\nexport function transformJsExpr(\n  expr: string,\n  scope: IScope,\n  { dontWrapEval = false, dontTransformThis2ContextAtRootScope = false } = {},\n) {\n  if (!expr) {\n    return 'undefined';\n  }\n\n  if (isLiteralAtomicExpr(expr)) {\n    return expr;\n  }\n\n  const exprAst = parseExpression(expr);\n\n  // 对于下面这些比较安全的字面值，可以直接返回对应的表达式，而非包一层\n  if (isSimpleStraightLiteral(exprAst)) {\n    return expr;\n  }\n\n  if (dontWrapEval) {\n    return transformThis2Context(exprAst, scope, {\n      ignoreRootScope: dontTransformThis2ContextAtRootScope,\n    });\n  }\n\n  switch (exprAst.type) {\n    // 对于直接写个函数的，则不用再包下，因为这样不会抛出异常的\n    case 'ArrowFunctionExpression':\n    case 'FunctionExpression':\n      return transformThis2Context(exprAst, scope, {\n        ignoreRootScope: dontTransformThis2ContextAtRootScope,\n      });\n\n    default:\n      break;\n  }\n\n  // 其他的都需要包一层\n  return `__$$eval(() => (${transformThis2Context(exprAst, scope, {\n    ignoreRootScope: dontTransformThis2ContextAtRootScope,\n  })}))`;\n}\n"
  },
  {
    "path": "modules/code-generator/src/core/jsx/handlers/transformThis2Context.ts",
    "content": "import { Expression } from '@babel/types';\nimport generate from '@babel/generator';\nimport { IScope } from '../../../types';\nimport { parseExpressionConvertThis2Context } from '../../../utils/expressionParser';\n\n/**\n * 将所有的 this.xxx 替换为 __$$context.xxx\n * @param expr\n */\nexport function transformThis2Context(\n  expr: string | Expression,\n  scope: IScope,\n  { ignoreRootScope = false } = {},\n): string {\n  if (ignoreRootScope && scope.parent == null) {\n    return typeof expr === 'string' ? expr : generate(expr).code;\n  }\n\n  // 下面这种字符串替换的方式虽然简单直接，但是对于复杂场景会误匹配，故后期改成了解析 AST 然后修改 AST 最后再重新生成代码的方式\n  // return expr\n  //   .replace(/\\bthis\\.item\\./g, () => 'item.')\n  //   .replace(/\\bthis\\.index\\./g, () => 'index.')\n  //   .replace(/\\bthis\\./g, () => '__$$context.');\n  return parseExpressionConvertThis2Context(\n    expr,\n    '__$$context',\n    scope.bindings?.getAllBindings() || [],\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/src/core/jsx/util/isLiteralAtomicExpr.ts",
    "content": "/**\n * 判断是否是原子类型的表达式\n */\nexport function isLiteralAtomicExpr(expr: string): boolean {\n  return (\n    expr === 'null' ||\n    expr === 'undefined' ||\n    expr === 'true' ||\n    expr === 'false' ||\n    /^-?\\d+(\\.\\d+)?$/.test(expr)\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/src/core/jsx/util/isSimpleStraightLiteral.ts",
    "content": "import { Expression } from '@babel/types';\n\n/** 判断是非是一些简单直接的字面值 */\nexport function isSimpleStraightLiteral(expr: Expression): boolean {\n  switch (expr.type) {\n    case 'BigIntLiteral':\n    case 'BooleanLiteral':\n    case 'DecimalLiteral':\n    case 'NullLiteral':\n    case 'NumericLiteral':\n    case 'RegExpLiteral':\n    case 'StringLiteral':\n      return true;\n    default:\n      return false;\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/src/generator/ChunkBuilder.ts",
    "content": "import { BuilderComponentPlugin, IChunkBuilder, ICodeChunk, ICodeStruct, FileType } from '../types';\n\nimport { COMMON_SUB_MODULE_NAME } from '../const/generator';\nimport { FILE_TYPE_FAMILY } from '../const/file';\n\ninterface ChunkGroupInfo {\n  chunk: ICodeChunk;\n  familyIdx?: number;\n}\n\nfunction whichFamily(type: FileType): [number, FileType[]] | undefined {\n  const idx = FILE_TYPE_FAMILY.findIndex((family) => family.indexOf(type) >= 0);\n  if (idx < 0) {\n    return undefined;\n  }\n  return [idx, FILE_TYPE_FAMILY[idx]];\n}\n\nexport const groupChunks = (chunks: ICodeChunk[]): ICodeChunk[][] => {\n  const tmp: Record<string, Record<number, number>> = {};\n  const col = chunks.reduce((chunksSet: Record<string, ChunkGroupInfo[]>, chunk) => {\n    const fileKey = chunk.subModule || COMMON_SUB_MODULE_NAME;\n    if (!chunksSet[fileKey]) {\n      // eslint-disable-next-line no-param-reassign\n      chunksSet[fileKey] = [];\n    }\n    const res = whichFamily(chunk.fileType as FileType);\n    const info: ChunkGroupInfo = {\n      chunk,\n    };\n    if (res) {\n      const [familyIdx, family] = res;\n      const rank = family.indexOf(chunk.fileType as FileType);\n      if (tmp[fileKey]) {\n        if (tmp[fileKey][familyIdx] !== undefined) {\n          if (tmp[fileKey][familyIdx] > rank) {\n            tmp[fileKey][familyIdx] = rank;\n          }\n        } else {\n          tmp[fileKey][familyIdx] = rank;\n        }\n      } else {\n        tmp[fileKey] = {};\n        tmp[fileKey][familyIdx] = rank;\n      }\n      info.familyIdx = familyIdx;\n    }\n\n    chunksSet[fileKey].push(info);\n    return chunksSet;\n  }, {});\n\n  const result: ICodeChunk[][] = [];\n  Object.keys(col).forEach((key) => {\n    const byType: Record<string, ICodeChunk[]> = {};\n    col[key].forEach((info) => {\n      let t: string = info.chunk.fileType;\n      if (info.familyIdx !== undefined) {\n        t = FILE_TYPE_FAMILY[info.familyIdx][tmp[key][info.familyIdx]];\n        // eslint-disable-next-line no-param-reassign\n        info.chunk.fileType = t;\n      }\n      if (!byType[t]) {\n        byType[t] = [];\n      }\n      byType[t].push(info.chunk);\n    });\n    result.push(...Object.keys(byType).map((t) => byType[t]));\n  });\n\n  return result;\n};\n\n/**\n * 代码片段构建器\n *\n * @export\n * @class ChunkBuilder\n * @template T\n */\nexport class ChunkBuilder implements IChunkBuilder {\n  private plugins: BuilderComponentPlugin[];\n\n  constructor(plugins: BuilderComponentPlugin[] = []) {\n    this.plugins = plugins;\n  }\n\n  async run(\n    ir: unknown,\n    initialStructure: ICodeStruct = {\n      ir,\n      chunks: [],\n      depNames: [],\n      contextData: {},\n    },\n  ) {\n    const structure = initialStructure;\n\n    const finalStructure: ICodeStruct = await this.plugins.reduce(\n      async (previousPluginOperation: Promise<ICodeStruct>, plugin) => {\n        const modifiedStructure = await previousPluginOperation;\n        return plugin(modifiedStructure);\n      },\n      Promise.resolve(structure),\n    );\n\n    const chunks = groupChunks(finalStructure.chunks);\n\n    return {\n      chunks,\n    };\n  }\n\n  getPlugins() {\n    return this.plugins;\n  }\n\n  addPlugin(plugin: BuilderComponentPlugin) {\n    this.plugins.push(plugin);\n  }\n}\n\nexport default ChunkBuilder;\n"
  },
  {
    "path": "modules/code-generator/src/generator/CodeBuilder.ts",
    "content": "import {\n  ChunkContent,\n  ChunkType,\n  CodeGeneratorError,\n  CodeGeneratorFunction,\n  ICodeBuilder,\n  ICodeChunk,\n} from '../types';\n\nexport class CodeBuilder implements ICodeBuilder {\n  private chunkDefinitions: ICodeChunk[] = [];\n\n  private generators: { [key: string]: CodeGeneratorFunction<ChunkContent> } = {\n    [ChunkType.STRING]: (str: string) => str, // no-op for string chunks\n    [ChunkType.JSON]: (json: Record<string, unknown>) => JSON.stringify(json), // stringify json to string\n  };\n\n  constructor(chunkDefinitions: ICodeChunk[] = []) {\n    this.chunkDefinitions = chunkDefinitions;\n  }\n\n  /**\n   * Links all chunks together based on their requirements. Returns an array\n   * of ordered chunk names which need to be compiled and glued together.\n   */\n  link(chunkDefinitions: ICodeChunk[] = []): string {\n    const chunks = chunkDefinitions || this.chunkDefinitions;\n    if (chunks.length <= 0) {\n      return '';\n    }\n\n    const unprocessedChunks = chunks.map((chunk) => {\n      return {\n        name: chunk.name,\n        type: chunk.type,\n        content: chunk.content,\n        linkAfter: this.cleanupInvalidChunks(chunk.linkAfter, chunks),\n      };\n    });\n\n    const resultingString: string[] = [];\n\n    while (unprocessedChunks.length > 0) {\n      let indexToRemove = 0;\n      for (let index = 0; index < unprocessedChunks.length; index++) {\n        if (unprocessedChunks[index].linkAfter.length <= 0) {\n          indexToRemove = index;\n          break;\n        }\n      }\n\n      if (unprocessedChunks[indexToRemove].linkAfter.length > 0) {\n        throw new CodeGeneratorError(\n          'Operation aborted. Reason: cyclic dependency between chunks.',\n        );\n      }\n\n      const { type, content, name } = unprocessedChunks[indexToRemove];\n      const compiledContent = this.generateByType(type, content);\n      if (compiledContent) {\n        resultingString.push(`${compiledContent}\\n`);\n      }\n\n      unprocessedChunks.splice(indexToRemove, 1);\n      if (!unprocessedChunks.some((ch) => ch.name === name)) {\n        unprocessedChunks.forEach(\n          // remove the processed chunk from all the linkAfter arrays from the remaining chunks\n          (ch) => {\n            // eslint-disable-next-line no-param-reassign\n            ch.linkAfter = ch.linkAfter.filter((after) => after !== name);\n          },\n        );\n      }\n    }\n\n    return resultingString.join('\\n');\n  }\n\n  generateByType(type: string, content: unknown): string {\n    if (!content) {\n      return '';\n    }\n    if (Array.isArray(content)) {\n      return content.map((contentItem) => this.generateByType(type, contentItem)).join('\\n');\n    }\n\n    if (!this.generators[type]) {\n      throw new Error(\n        `Attempted to generate unknown type ${type}. Please register a generator for this type in builder/index.ts`,\n      );\n    }\n\n    return this.generators[type](content);\n  }\n\n  // remove invalid chunks (which did not end up being created) from the linkAfter fields\n  // one use-case is when you want to remove the import plugin\n  private cleanupInvalidChunks(linkAfter: string[], chunks: ICodeChunk[]) {\n    return linkAfter.filter((chunkName) => chunks.some((chunk) => chunk.name === chunkName));\n  }\n}\n\nexport default CodeBuilder;\n"
  },
  {
    "path": "modules/code-generator/src/generator/ModuleBuilder.ts",
    "content": "import { IPublicTypeProjectSchema, ResultFile, ResultDir } from '@alilc/lowcode-types';\n\nimport {\n  BuilderComponentPlugin,\n  CodeGeneratorError,\n  ICodeChunk,\n  ICompiledModule,\n  IContextData,\n  IModuleBuilder,\n  IParseResult,\n  ISchemaParser,\n  PostProcessor,\n} from '../types';\n\nimport { COMMON_SUB_MODULE_NAME } from '../const/generator';\n\nimport { SchemaParser } from '../parser/SchemaParser';\nimport { ChunkBuilder } from './ChunkBuilder';\nimport { CodeBuilder } from './CodeBuilder';\nimport { createResultFile, createResultDir, addFile } from '../utils/resultHelper';\n\nexport function createModuleBuilder(\n  options: {\n    plugins: BuilderComponentPlugin[];\n    postProcessors: PostProcessor[];\n    mainFileName?: string;\n    contextData?: IContextData;\n  } = {\n    plugins: [],\n    postProcessors: [],\n  },\n): IModuleBuilder {\n  const chunkGenerator = new ChunkBuilder(options.plugins);\n  const linker = new CodeBuilder();\n\n  const generateModule = async (input: unknown): Promise<ICompiledModule> => {\n    const moduleMainName = options.mainFileName || COMMON_SUB_MODULE_NAME;\n    if (chunkGenerator.getPlugins().length <= 0) {\n      throw new CodeGeneratorError(\n        'No plugins found. Component generation cannot work without any plugins!',\n      );\n    }\n\n    let files: ResultFile[] = [];\n\n    const { chunks } = await chunkGenerator.run(input, {\n      ir: input,\n      chunks: [],\n      depNames: [],\n      contextData: options.contextData || {},\n    });\n\n    chunks.forEach((fileChunkList) => {\n      const content = linker.link(fileChunkList);\n      const file = createResultFile(\n        fileChunkList[0].subModule || moduleMainName,\n        fileChunkList[0].fileType,\n        content,\n      );\n      files.push(file);\n    });\n\n    if (options.postProcessors.length > 0) {\n      files = files.map((file) => {\n        let { content, ext: type, name } = file;\n        options.postProcessors.forEach((processer) => {\n          content = processer(content, type, name);\n        });\n\n        return createResultFile(file.name, type, content);\n      });\n    }\n\n    return {\n      files,\n    };\n  };\n\n  const generateModuleCode = async (schema: IPublicTypeProjectSchema | string): Promise<ResultDir> => {\n    // Init\n    const schemaParser: ISchemaParser = new SchemaParser();\n    const parseResult: IParseResult = schemaParser.parse(schema);\n\n    const containerInfo = parseResult.containers[0];\n    const { files } = await generateModule(containerInfo);\n\n    const dir = createResultDir(containerInfo.moduleName);\n    files.forEach((file) => addFile(dir, file));\n\n    return dir;\n  };\n\n  const linkCodeChunks = (chunks: Record<string, ICodeChunk[]>, fileName: string) => {\n    const files: ResultFile[] = [];\n\n    Object.keys(chunks).forEach((fileKey) => {\n      const fileChunkList = chunks[fileKey];\n      const content = linker.link(fileChunkList);\n      const file = createResultFile(\n        fileChunkList[0].subModule || fileName,\n        fileChunkList[0].fileType,\n        content,\n      );\n      files.push(file);\n    });\n\n    return files;\n  };\n\n  return {\n    generateModule,\n    generateModuleCode,\n    linkCodeChunks,\n    addPlugin: chunkGenerator.addPlugin.bind(chunkGenerator),\n  };\n}\n"
  },
  {
    "path": "modules/code-generator/src/generator/ProjectBuilder.ts",
    "content": "import { ResultDir, ResultFile, IPublicTypeProjectSchema } from '@alilc/lowcode-types';\n\nimport {\n  IModuleBuilder,\n  IParseResult,\n  IProjectBuilder,\n  IProjectPlugins,\n  IProjectTemplate,\n  ISchemaParser,\n  PostProcessor,\n} from '../types';\n\nimport { SchemaParser } from '../parser/SchemaParser';\nimport { createResultDir, addDirectory, addFile } from '../utils/resultHelper';\n\nimport { createModuleBuilder } from './ModuleBuilder';\nimport { ProjectPreProcessor, ProjectPostProcessor, IContextData } from '../types/core';\nimport { CodeGeneratorError } from '../types/error';\nimport { isBuiltinSlotName } from '../const';\n\ninterface IModuleInfo {\n  moduleName?: string;\n  path: string[];\n  files: ResultFile[];\n}\n\nexport interface ProjectBuilderInitOptions {\n\n  /** 项目模板 */\n  template: IProjectTemplate;\n\n  /** 项目插件 */\n  plugins: IProjectPlugins;\n\n  /** 模块后置处理器 */\n  postProcessors: PostProcessor[];\n\n  /** Schema 解析器 */\n  schemaParser?: ISchemaParser;\n\n  /** 项目级别的前置处理器 */\n  projectPreProcessors?: ProjectPreProcessor[];\n\n  /** 项目级别的后置处理器 */\n  projectPostProcessors?: ProjectPostProcessor[];\n\n  /** 是否处于严格模式 */\n  inStrictMode?: boolean;\n\n  /** 一些额外的上下文数据 */\n  extraContextData?: Record<string, unknown>;\n\n  /**\n   * Hook which is used to customize original options, we can reorder/add/remove plugins/processors\n   * of the existing solution.\n   */\n  customizeBuilderOptions?(originalOptions: ProjectBuilderInitOptions): ProjectBuilderInitOptions;\n}\n\nexport class ProjectBuilder implements IProjectBuilder {\n  /** 项目模板 */\n  private template: IProjectTemplate;\n\n  /** 项目插件 */\n  private plugins: IProjectPlugins;\n\n  /** 模块后置处理器 */\n  private postProcessors: PostProcessor[];\n\n  /** Schema 解析器 */\n  private schemaParser: ISchemaParser;\n\n  /** 项目级别的前置处理器 */\n  private projectPreProcessors: ProjectPreProcessor[];\n\n  /** 项目级别的后置处理器 */\n  private projectPostProcessors: ProjectPostProcessor[];\n\n  /** 是否处于严格模式 */\n  readonly inStrictMode: boolean;\n\n  /** 一些额外的上下文数据 */\n  readonly extraContextData: IContextData;\n\n  constructor(builderOptions: ProjectBuilderInitOptions) {\n    let customBuilderOptions = builderOptions;\n    if (typeof builderOptions.customizeBuilderOptions === 'function') {\n      customBuilderOptions = builderOptions.customizeBuilderOptions(builderOptions);\n    }\n    const {\n      template,\n      plugins,\n      postProcessors,\n      schemaParser = new SchemaParser(),\n      projectPreProcessors = [],\n      projectPostProcessors = [],\n      inStrictMode = false,\n      extraContextData = {},\n    } = customBuilderOptions;\n    this.template = template;\n    this.plugins = plugins;\n    this.postProcessors = postProcessors;\n    this.schemaParser = schemaParser;\n    this.projectPreProcessors = projectPreProcessors;\n    this.projectPostProcessors = projectPostProcessors;\n    this.inStrictMode = inStrictMode;\n    this.extraContextData = extraContextData;\n  }\n\n  async generateProject(originalSchema: IPublicTypeProjectSchema | string): Promise<ResultDir> {\n    // Init\n    const { schemaParser } = this;\n\n    let schema: IPublicTypeProjectSchema =\n      typeof originalSchema === 'string' ? JSON.parse(originalSchema) : originalSchema;\n\n    // Parse / Format\n    // Preprocess\n    for (const preProcessor of this.projectPreProcessors) {\n      // eslint-disable-next-line no-await-in-loop\n      schema = await preProcessor(schema);\n    }\n\n    // Validate\n    if (!schemaParser.validate(schema)) {\n      throw new CodeGeneratorError('Schema is invalid');\n    }\n\n    // Collect Deps\n    // Parse JSExpression\n    const parseResult: IParseResult = schemaParser.parse(schema);\n\n    const projectRoot = await this.template.generateTemplate(parseResult);\n\n    let buildResult: IModuleInfo[] = [];\n\n    const builders = this.createModuleBuilders({\n      extraContextData: {\n        projectRemark: parseResult?.project?.projectRemark,\n        template: this.template,\n      },\n    });\n    // Generator Code module\n    // components\n    // pages\n    const containerBuildResult: IModuleInfo[] = await Promise.all<IModuleInfo>(\n      parseResult.containers.map(async (containerInfo) => {\n        let builder: IModuleBuilder;\n        let path: string[];\n        if (containerInfo.containerType === 'Page') {\n          builder = builders.pages;\n          path = this.template.slots.pages.path;\n        } else {\n          builder = builders.components;\n          path = this.template.slots.components.path;\n        }\n\n        const { files } = await builder.generateModule(containerInfo);\n\n        return {\n          moduleName: containerInfo.moduleName,\n          path,\n          files,\n        };\n      }),\n    );\n    buildResult = buildResult.concat(containerBuildResult);\n\n    // router\n    if (parseResult.globalRouter && builders.router) {\n      const { files } = await builders.router.generateModule(parseResult.globalRouter);\n\n      buildResult.push({\n        path: this.template.slots.router.path,\n        files,\n      });\n    }\n\n    // entry\n    if (parseResult.project && builders.entry) {\n      const { files } = await builders.entry.generateModule(parseResult.project);\n\n      buildResult.push({\n        path: this.template.slots.entry.path,\n        files,\n      });\n    }\n\n    // appConfig\n    if (builders.appConfig) {\n      const { files } = await builders.appConfig.generateModule(parseResult);\n\n      buildResult.push({\n        path: this.template.slots.appConfig.path,\n        files,\n      });\n    }\n\n    // buildConfig\n    if (builders.buildConfig) {\n      const { files } = await builders.buildConfig.generateModule(parseResult);\n\n      buildResult.push({\n        path: this.template.slots.buildConfig.path,\n        files,\n      });\n    }\n\n    // constants?\n    if (parseResult.project && builders.constants && this.template.slots.constants) {\n      const { files } = await builders.constants.generateModule(parseResult.project);\n\n      buildResult.push({\n        path: this.template.slots.constants.path,\n        files,\n      });\n    }\n\n    // utils?\n    if (parseResult.globalUtils && builders.utils && this.template.slots.utils) {\n      const { files } = await builders.utils.generateModule(parseResult.globalUtils);\n\n      buildResult.push({\n        path: this.template.slots.utils.path,\n        files,\n      });\n    }\n\n    // i18n?\n    if (builders.i18n && this.template.slots.i18n) {\n      const { files } = await builders.i18n.generateModule(parseResult.project);\n\n      buildResult.push({\n        path: this.template.slots.i18n.path,\n        files,\n      });\n    }\n\n    // globalStyle\n    if (parseResult.project && builders.globalStyle) {\n      const { files } = await builders.globalStyle.generateModule(parseResult.project);\n\n      buildResult.push({\n        path: this.template.slots.globalStyle.path,\n        files,\n      });\n    }\n\n    // htmlEntry\n    if (parseResult.project && builders.htmlEntry) {\n      const { files } = await builders.htmlEntry.generateModule(parseResult.project);\n\n      buildResult.push({\n        path: this.template.slots.htmlEntry.path,\n        files,\n      });\n    }\n\n    // packageJSON\n    if (parseResult.project && builders.packageJSON) {\n      const { files } = await builders.packageJSON.generateModule(parseResult.project);\n\n      buildResult.push({\n        path: this.template.slots.packageJSON.path,\n        files,\n      });\n    }\n\n    // demo\n    if (parseResult.project && builders.demo) {\n      const { files } = await builders.demo.generateModule(parseResult.project);\n      buildResult.push({\n        path: this.template.slots.demo.path,\n        files,\n      });\n    }\n\n    // handle extra slots\n    await this.generateExtraSlots(builders, parseResult, buildResult);\n\n    // Post Process\n    const isSingleComponent = parseResult?.project?.projectRemark?.isSingleComponent;\n    // Combine Modules\n    buildResult.forEach((moduleInfo) => {\n      let targetDir = getDirFromRoot(projectRoot, moduleInfo.path);\n      // if project only contain single component, skip creation of directory.\n      if (moduleInfo.moduleName && !isSingleComponent) {\n        const dir = createResultDir(moduleInfo.moduleName);\n        addDirectory(targetDir, dir);\n        targetDir = dir;\n      }\n      moduleInfo.files.forEach((file) => addFile(targetDir, file));\n    });\n\n    // post-processors\n    let finalResult = projectRoot;\n    for (const projectPostProcessor of this.projectPostProcessors) {\n      // eslint-disable-next-line no-await-in-loop\n      finalResult = await projectPostProcessor(finalResult, schema, originalSchema, {\n        template: this.template,\n        parseResult,\n      });\n    }\n\n    return finalResult;\n  }\n\n  private createModuleBuilders(extraContextData: Record<string, unknown> = {}):\n    Record<string, IModuleBuilder> {\n    const builders: Record<string, IModuleBuilder> = {};\n\n    Object.keys(this.plugins).forEach((pluginName) => {\n      if (this.plugins[pluginName].length > 0) {\n        const options: { mainFileName?: string } = {};\n        if (this.template.slots[pluginName] && this.template.slots[pluginName].fileName) {\n          options.mainFileName = this.template.slots[pluginName].fileName;\n        }\n        builders[pluginName] = createModuleBuilder({\n          plugins: this.plugins[pluginName],\n          postProcessors: this.postProcessors,\n          contextData: {\n            // template: this.template,\n            inStrictMode: this.inStrictMode,\n            tolerateEvalErrors: true,\n            evalErrorsHandler: '',\n            ...this.extraContextData,\n            ...extraContextData,\n          },\n          ...options,\n        });\n      }\n    });\n\n    return builders;\n  }\n\n  private async generateExtraSlots(\n    builders: Record<string, IModuleBuilder>,\n    parseResult: IParseResult,\n    buildResult: IModuleInfo[],\n  ) {\n    for (const slotName in this.template.slots) {\n      if (!isBuiltinSlotName(slotName)) {\n        const { files } = await builders[slotName].generateModule(parseResult);\n        buildResult.push({\n          path: this.template.slots[slotName].path,\n          files,\n        });\n      }\n    }\n  }\n}\n\nexport function createProjectBuilder(initOptions: ProjectBuilderInitOptions): IProjectBuilder {\n  return new ProjectBuilder(initOptions);\n}\n\nfunction getDirFromRoot(root: ResultDir, path: string[]): ResultDir {\n  let current: ResultDir = root;\n  path.forEach((p) => {\n    const exist = current.dirs.find((d) => d.name === p);\n    if (exist) {\n      current = exist;\n    } else {\n      const newDir = createResultDir(p);\n      addDirectory(current, newDir);\n      current = newDir;\n    }\n  });\n\n  return current;\n}\n"
  },
  {
    "path": "modules/code-generator/src/index.ts",
    "content": "/**\n * 低代码引擎的出码模块，负责将编排产出的 Schema 转换成实际可执行的代码。\n * 注意：为了保持 API 的稳定性，这里所有导出的 API 均要显式命名方式导出\n *     （即用 export { xxx } from 'xx' 的方式，不要直接 export * from 'xxx')\n *      而且所有导出的 API 务必在 tests/public 中编写单元测试\n */\nimport { createProjectBuilder } from './generator/ProjectBuilder';\nimport { createModuleBuilder } from './generator/ModuleBuilder';\nimport { createDiskPublisher } from './publisher/disk';\nimport { createZipPublisher } from './publisher/zip';\nimport createIceJsProjectBuilder, { plugins as icejsPlugins } from './solutions/icejs';\nimport createIceJs3ProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3';\nimport createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app';\n\n// 引入说明\nimport { REACT_CHUNK_NAME } from './plugins/component/react/const';\nimport { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from './const/generator';\n\n// 引入通用插件组\nimport esmodule from './plugins/common/esmodule';\nimport requireUtils from './plugins/common/requireUtils';\nimport styleImport from './plugins/common/styleImport';\n\nimport css from './plugins/component/style/css';\nimport constants from './plugins/project/constants';\nimport i18n from './plugins/project/i18n';\nimport utils from './plugins/project/utils';\nimport prettier from './postprocessor/prettier';\n\n// 引入全局常用工具\nimport * as globalUtils from './utils';\n\nimport * as CONSTANTS from './const';\n\n// 引入内置解决方案模块\nimport icejs from './plugins/project/framework/icejs';\nimport icejs3 from './plugins/project/framework/icejs3';\nimport rax from './plugins/project/framework/rax';\n\nexport default {\n  createProjectBuilder,\n  createModuleBuilder,\n  solutions: {\n    icejs: createIceJsProjectBuilder,\n    icejs3: createIceJs3ProjectBuilder,\n    rax: createRaxAppProjectBuilder,\n  },\n  solutionParts: {\n    icejs,\n    icejs3,\n    rax,\n  },\n  publishers: {\n    disk: createDiskPublisher,\n    zip: createZipPublisher,\n  },\n  plugins: {\n    common: {\n\n      /**\n       * 处理 ES Module\n       * @deprecated please use esModule\n       */\n      esmodule,\n      esModule: esmodule,\n      requireUtils,\n      styleImport,\n    },\n    style: {\n      css,\n    },\n    project: {\n      constants,\n      i18n,\n      utils,\n    },\n    icejs: {\n      ...icejsPlugins,\n    },\n    icejs3: {\n      ...icejs3Plugins,\n    },\n    rax: {\n      ...raxPlugins,\n    },\n\n    /**\n     * @deprecated please use icejs\n     */\n    react: {\n      ...icejsPlugins,\n    },\n  },\n  postprocessor: {\n    prettier,\n  },\n  utils: globalUtils,\n  chunkNames: {\n    COMMON_CHUNK_NAME,\n    CLASS_DEFINE_CHUNK_NAME,\n    REACT_CHUNK_NAME,\n  },\n  defaultLinkAfter: {\n    COMMON_DEFAULT_LINK_AFTER: DEFAULT_LINK_AFTER,\n  },\n  constants: CONSTANTS,\n};\n\n// 一些类型定义\nexport * from './types';\n\n// 一些常量定义\nexport * from './const';\n\n// 一些工具函数\nexport * from './analyzer/componentAnalyzer';\nexport * from './parser/SchemaParser';\nexport * from './generator/ChunkBuilder';\nexport * from './generator/CodeBuilder';\nexport * from './generator/ModuleBuilder';\nexport * from './generator/ProjectBuilder';\n"
  },
  {
    "path": "modules/code-generator/src/parser/SchemaParser.ts",
    "content": "/**\n * 解析器是对输入的固定格式数据做拆解，使其符合引擎后续步骤预期，完成统一处理逻辑的步骤。\n * 本解析器面向的是标准 schema 协议。\n */\nimport changeCase from 'change-case';\nimport {\n  IPublicTypeUtilItem,\n  IPublicTypeNodeDataType,\n  IPublicTypeNodeSchema,\n  IPublicTypeContainerSchema,\n  IPublicTypeProjectSchema,\n  IPublicTypePropsMap,\n  IPublicTypeNodeData,\n  IPublicTypeNpmInfo,\n} from '@alilc/lowcode-types';\nimport {\n  IPageMeta,\n  CodeGeneratorError,\n  CompatibilityError,\n  DependencyType,\n  IContainerInfo,\n  IDependency,\n  IExternalDependency,\n  IInternalDependency,\n  InternalDependencyType,\n  IParseResult,\n  ISchemaParser,\n  INpmPackage,\n  IRouterInfo,\n} from '../types';\n\nimport { SUPPORT_SCHEMA_VERSION_LIST } from '../const';\n\nimport { getErrorMessage } from '../utils/errors';\nimport { handleSubNodes, isValidContainerType, ContainerType } from '../utils/schema';\nimport { uniqueArray } from '../utils/common';\nimport { componentAnalyzer } from '../analyzer/componentAnalyzer';\nimport { ensureValidClassName } from '../utils/validate';\nimport type { ProjectRemark } from '../types/intermediate';\n\nconst defaultContainer: IContainerInfo = {\n  containerType: 'Component',\n  componentName: 'Component',\n  moduleName: 'Index',\n  fileName: 'Index',\n  css: '',\n  props: {},\n};\n\nfunction getRootComponentName(typeName: string, maps: Record<string, IExternalDependency>): string {\n  if (maps[typeName]) {\n    const rec = maps[typeName];\n    if (rec.destructuring) {\n      return rec.componentName || typeName;\n    }\n\n    const peerName = Object.keys(maps).find((depName: string) => {\n      const depInfo = maps[depName];\n      return (\n        depName !== typeName &&\n        !depInfo.destructuring &&\n        depInfo.package === rec.package &&\n        depInfo.version === rec.version &&\n        depInfo.main === rec.main &&\n        depInfo.exportName === rec.exportName &&\n        depInfo.subName === rec.subName\n      );\n    });\n\n    return peerName || typeName;\n  }\n  return typeName;\n}\n\nfunction processChildren(schema: IPublicTypeNodeSchema): void {\n  if (schema.props) {\n    if (Array.isArray(schema.props)) {\n      // FIXME: is array type props description\n    } else {\n      const nodeProps = schema.props as IPublicTypePropsMap;\n      if (nodeProps.children) {\n        if (!schema.children) {\n          // eslint-disable-next-line no-param-reassign\n          schema.children = nodeProps.children as IPublicTypeNodeDataType;\n        } else {\n          let _children: IPublicTypeNodeData[] = [];\n\n          if (Array.isArray(schema.children)) {\n            _children = _children.concat(schema.children);\n          } else {\n            _children.push(schema.children);\n          }\n\n          if (Array.isArray(nodeProps.children)) {\n            _children = _children.concat(nodeProps.children as IPublicTypeNodeData[]);\n          } else {\n            _children.push(nodeProps.children as IPublicTypeNodeData);\n          }\n\n          // eslint-disable-next-line no-param-reassign\n          schema.children = _children;\n        }\n        delete nodeProps.children;\n      }\n    }\n  }\n}\n\nfunction getInternalDep(internalDeps: Record<string, IInternalDependency>, depName: string) {\n  const dep = internalDeps[depName];\n  return (dep && dep.type !== InternalDependencyType.PAGE) ? dep : null;\n}\n\nexport class SchemaParser implements ISchemaParser {\n  validate(schema: IPublicTypeProjectSchema): boolean {\n    if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) {\n      throw new CompatibilityError(`Not support schema with version [${schema.version}]`);\n    }\n\n    return true;\n  }\n\n  parse(schemaSrc: IPublicTypeProjectSchema | string): IParseResult {\n    // TODO: collect utils depends in JSExpression\n    const compDeps: Record<string, IExternalDependency> = {};\n    const internalDeps: Record<string, IInternalDependency> = {};\n    let utilsDeps: IExternalDependency[] = [];\n\n    const schema = this.decodeSchema(schemaSrc);\n\n    // 解析三方组件依赖\n    schema.componentsMap.forEach((info: any) => {\n      if (info.componentName) {\n        compDeps[info.componentName] = {\n          ...info,\n          dependencyType: DependencyType.External,\n          componentName: info.componentName,\n          exportName: info.exportName ?? info.componentName,\n          version: info.version || '*',\n          destructuring: info.destructuring ?? false,\n        };\n      }\n    });\n\n    let containers: IContainerInfo[];\n    // Test if this is a lowcode component without container\n    if (schema.componentsTree.length > 0) {\n      const firstRoot: IPublicTypeContainerSchema = schema.componentsTree[0] as IPublicTypeContainerSchema;\n\n      if (!firstRoot.fileName && !isValidContainerType(firstRoot)) {\n        // 整个 schema 描述一个容器，且无根节点定义\n        const container: IContainerInfo = {\n          ...firstRoot,\n          ...defaultContainer,\n          props: firstRoot.props || defaultContainer.props,\n          css: firstRoot.css || defaultContainer.css,\n          moduleName: (firstRoot as IContainerInfo).moduleName || defaultContainer.moduleName,\n          children: schema.componentsTree as IPublicTypeNodeSchema[],\n        };\n        containers = [container];\n      } else {\n        // 普通带 1 到多个容器的 schema\n        containers = schema.componentsTree.map((n) => {\n          const subRoot = n as IPublicTypeContainerSchema;\n          const container: IContainerInfo = {\n            ...subRoot,\n            componentName: getRootComponentName(subRoot.componentName, compDeps),\n            containerType: subRoot.componentName,\n            moduleName: ensureValidClassName(subRoot.componentName === ContainerType.Component ?\n              subRoot.fileName : changeCase.pascalCase(subRoot.fileName)),\n          };\n          return container;\n        });\n      }\n    } else {\n      throw new CodeGeneratorError(\"Can't find anything to generate.\");\n    }\n\n    // 分析引用能力的依赖\n    containers = containers.map((con) => ({\n      ...con,\n      analyzeResult: componentAnalyzer(con as IPublicTypeContainerSchema),\n    }));\n\n    // 建立所有容器的内部依赖索引\n    containers.forEach((container) => {\n      let type;\n      switch (container.containerType) {\n        case 'Page':\n          type = InternalDependencyType.PAGE;\n          break;\n        case 'Block':\n          type = InternalDependencyType.BLOCK;\n          break;\n        default:\n          type = InternalDependencyType.COMPONENT;\n          break;\n      }\n\n      const dep: IInternalDependency = {\n        type,\n        moduleName: container.moduleName,\n        destructuring: false,\n        exportName: container.moduleName,\n        dependencyType: DependencyType.Internal,\n      };\n\n      internalDeps[dep.moduleName] = dep;\n    });\n\n    const containersDeps = ([] as IDependency[]).concat(...containers.map((c) => c.deps || []));\n    // TODO: 不应该在出码部分解决？\n    // 处理 children 写在了 props 里的情况\n    containers.forEach((container) => {\n      if (container.children) {\n        // eslint-disable-next-line @typescript-eslint/no-invalid-void-type\n        handleSubNodes<void>(\n          container.children,\n          {\n            node: (i: IPublicTypeNodeSchema) => processChildren(i),\n          },\n          {\n            rerun: true,\n          },\n        );\n      }\n    });\n\n    containers.forEach((container) => {\n      const depNames = this.getComponentNames(container);\n      // eslint-disable-next-line no-param-reassign\n      container.deps = uniqueArray<string>(depNames, (i: string) => i)\n        .map((depName) => getInternalDep(internalDeps, depName) || compDeps[depName])\n        .filter(Boolean);\n      // container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]);\n    });\n\n    // 分析路由配置\n    const routes: IRouterInfo['routes'] = containers\n      .filter((container) => container.containerType === 'Page')\n      .map((page) => {\n        const { meta } = page;\n        if (meta) {\n          return {\n            path: (meta as IPageMeta).router || `/${page.fileName}`, // 如果无法找到页面路由信息，则用 fileName 做兜底\n            fileName: page.fileName,\n            componentName: page.moduleName,\n          };\n        }\n\n        return {\n          path: '',\n          fileName: page.fileName,\n          componentName: page.moduleName,\n        };\n      });\n\n    const routerDeps = routes\n      .map((r) => internalDeps[r.componentName] || compDeps[r.componentName])\n      .filter((dep) => !!dep);\n\n    // 分析 Utils 依赖\n    let utils: IPublicTypeUtilItem[];\n    if (schema.utils) {\n      utils = schema.utils;\n      utilsDeps = schema.utils\n        .filter(\n          (u): u is { name: string; type: 'npm' | 'tnpm'; content: IPublicTypeNpmInfo } => u.type !== 'function',\n        )\n        .map(\n          (u): IExternalDependency => ({\n            ...u.content,\n            componentName: u.name,\n            version: u.content.version || '*',\n            destructuring: u.content.destructuring ?? false,\n            exportName: u.content.exportName ?? u.name,\n          }),\n        );\n    } else {\n      utils = [];\n    }\n\n    // 分析项目 npm 依赖\n    let npms: INpmPackage[] = [];\n    containers.forEach((con) => {\n      const p = (con.deps || [])\n        .map((dep) => {\n          return dep.dependencyType === DependencyType.External ? dep : null;\n        })\n        .filter((dep) => dep !== null);\n      const npmInfos: INpmPackage[] = p.filter(Boolean).map((i) => ({\n        package: (i as IExternalDependency).package,\n        version: (i as IExternalDependency).version,\n      }));\n      npms.push(...npmInfos);\n    });\n\n    npms.push(\n      ...utilsDeps.map((utilsDep) => ({\n        package: utilsDep.package,\n        version: utilsDep.version,\n      })),\n    );\n\n    npms = uniqueArray<INpmPackage>(npms, (i) => i.package).filter(Boolean);\n\n    return {\n      containers,\n      globalUtils: {\n        utils,\n        deps: utilsDeps,\n      },\n      globalI18n: schema.i18n,\n      globalRouter: {\n        routes,\n        deps: routerDeps,\n      },\n      project: {\n        css: schema.css,\n        constants: schema.constants,\n        config: schema.config || {},\n        meta: schema.meta || {},\n        i18n: schema.i18n,\n        containersDeps,\n        utilsDeps,\n        packages: npms || [],\n        dataSourcesTypes: this.collectDataSourcesTypes(schema),\n        projectRemark: this.getProjectRemark(containers),\n      },\n    };\n  }\n\n  getProjectRemark(containers: IContainerInfo[]): ProjectRemark {\n    return {\n      isSingleComponent: containers.length === 1 && containers[0].containerType === 'Component',\n    };\n  }\n\n  getComponentNames(children: IPublicTypeNodeDataType): string[] {\n    return handleSubNodes<string>(\n      children,\n      {\n        node: (i: IPublicTypeNodeSchema) => i.componentName,\n      },\n      {\n        rerun: true,\n      },\n    );\n  }\n\n  decodeSchema(schemaSrc: string | IPublicTypeProjectSchema): IPublicTypeProjectSchema {\n    let schema: IPublicTypeProjectSchema;\n    if (typeof schemaSrc === 'string') {\n      try {\n        schema = JSON.parse(schemaSrc);\n      } catch (error) {\n        throw new CodeGeneratorError(\n          `Parse schema failed: ${getErrorMessage(error) || 'unknown reason'}`,\n        );\n      }\n    } else {\n      schema = schemaSrc;\n    }\n    return schema;\n  }\n\n  private collectDataSourcesTypes(schema: IPublicTypeProjectSchema): string[] {\n    const dataSourcesTypes = new Set<string>();\n\n    // 数据源的默认类型为 fetch\n    const defaultDataSourceType = 'fetch';\n\n    // 收集应用级别的数据源\n    schema.dataSource?.list?.forEach((ds) => {\n      dataSourcesTypes.add(ds.type || defaultDataSourceType);\n    });\n\n    // 收集容器级别的数据源（页面/组件/区块）\n    schema.componentsTree.forEach((rootNode) => {\n      rootNode.dataSource?.list?.forEach((ds) => {\n        dataSourcesTypes.add(ds.type || defaultDataSourceType);\n      });\n    });\n\n    return Array.from(dataSourcesTypes.values());\n  }\n}\n\nexport default SchemaParser;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/common/esmodule.ts",
    "content": "import { flatMap, camelCase, get } from 'lodash';\nimport { COMMON_CHUNK_NAME } from '../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  CodeGeneratorError,\n  DependencyType,\n  FileType,\n  ICodeChunk,\n  ICodeStruct,\n  IDependency,\n  IExternalDependency,\n  IInternalDependency,\n  IWithDependency,\n} from '../../types';\n\nimport { isValidIdentifier } from '../../utils/validate';\n\n// TODO: main 这个信息到底怎么用，是不是外部包不需要使用？\nconst DEP_MAIN_BLOCKLIST = ['lib', 'lib/index', 'es', 'es/index', 'main'];\nconst DEFAULT_EXPORT_NAME = '__default__';\n\nfunction groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {\n  const depMap: Record<string, IDependency[]> = {};\n\n  const addDep = (pkg: string, dep: IDependency) => {\n    if (!depMap[pkg]) {\n      depMap[pkg] = [];\n    }\n    depMap[pkg].push(dep);\n  };\n\n  deps.forEach((dep) => {\n    if (dep.dependencyType === DependencyType.Internal) {\n      addDep(`${(dep as IInternalDependency).moduleName}${dep.main ? `/${dep.main}` : ''}`, dep);\n    } else {\n      let depMain = '';\n      // TODO: 部分类型的 main 暂时认为没用\n      if (dep.main && DEP_MAIN_BLOCKLIST.indexOf(dep.main) < 0) {\n        depMain = dep.main;\n      }\n      if (depMain.substring(0, 1) === '/') {\n        depMain = depMain.substring(1);\n      }\n      addDep(`${(dep as IExternalDependency).package}${depMain ? `/${depMain}` : ''}`, dep);\n    }\n  });\n\n  return depMap;\n}\n\ninterface IDependencyItem {\n  exportName: string;\n  aliasName?: string;\n  isDefault?: boolean;\n  subName?: string;\n  nodeIdentifier?: string; // 与使用处的映射关系，理论上是不可变更的，如需变更需要提供额外信息\n  source: IDependency;\n}\n\ninterface IExportItem {\n  exportName: string;\n  aliasNames: string[];\n  isDefault?: boolean;\n  needOriginExport: boolean;\n}\n\nfunction getDependencyIdentifier(info: IDependencyItem): string {\n  return info.aliasName || info.exportName;\n}\n\nfunction getExportNameOfDep(dep: IDependency): string {\n  if (dep.destructuring) {\n    return (\n      dep.exportName ||\n      dep.componentName ||\n      throwNewError('destructuring dependency must have exportName or componentName')\n    );\n  }\n\n  if (!dep.subName) {\n    return (\n      dep.componentName ||\n      dep.exportName ||\n      throwNewError('dependency item must have componentName or exportName')\n    );\n  }\n\n  return (\n    dep.exportName ||\n    `__$${camelCase(\n      get(dep, 'moduleName') ||\n        get(dep, 'package') ||\n        throwNewError('dep.moduleName or dep.package is undefined'),\n    )}_default`\n  );\n}\n\nfunction throwNewError(msg: string): never {\n  throw new Error(msg);\n}\n\nfunction buildPackageImport(\n  pkg: string,\n  deps: IDependency[],\n  targetFileType: string,\n  useAliasName: boolean,\n): ICodeChunk[] {\n  // 如果压根没有包，则不生成对应的 import 语句（生成了没有任何意义）\n  if (!pkg || pkg === 'undefined' || pkg === 'null') {\n    // TODO: 要不要加个 warning？\n    return [];\n  }\n\n  const chunks: ICodeChunk[] = [];\n\n  const exportItems: Record<string, IExportItem> = {};\n  const defaultExportNames: string[] = [];\n\n  const depsInfo: IDependencyItem[] = deps.map((dep) => {\n    const info: IDependencyItem = {\n      exportName: getExportNameOfDep(dep),\n      isDefault: !dep.destructuring,\n      subName: dep.subName || undefined,\n      nodeIdentifier: dep.componentName || undefined,\n      source: dep,\n    };\n\n    // 下面 5 个逻辑是清理不必要的冗余信息，做到数据结构归一化\n    if (info.isDefault) {\n      if (defaultExportNames.indexOf(info.exportName) < 0) {\n        defaultExportNames.push(info.exportName);\n      }\n    }\n\n    if (!info.subName) {\n      if (info.nodeIdentifier === info.exportName) {\n        info.nodeIdentifier = undefined;\n      }\n\n      if (info.isDefault) {\n        info.aliasName = info.nodeIdentifier || info.exportName;\n        info.exportName = DEFAULT_EXPORT_NAME;\n      }\n\n      if (info.nodeIdentifier) {\n        info.aliasName = info.nodeIdentifier;\n        info.nodeIdentifier = undefined;\n      }\n    } else {\n      if (info.isDefault) {\n        info.aliasName = info.exportName;\n        info.exportName = DEFAULT_EXPORT_NAME;\n      }\n\n      if (info.nodeIdentifier === `${info.exportName}.${info.subName}`) {\n        info.nodeIdentifier = undefined;\n      }\n    }\n\n    return info;\n  });\n\n  // 建立 export 项目的列表\n  depsInfo.forEach((info) => {\n    if (!exportItems[info.exportName]) {\n      exportItems[info.exportName] = {\n        exportName: info.exportName,\n        isDefault: info.isDefault,\n        aliasNames: [],\n        needOriginExport: false,\n      };\n    }\n\n    if (!info.nodeIdentifier && !info.aliasName) {\n      exportItems[info.exportName].needOriginExport = true;\n    }\n  });\n\n  // 建立别名字典\n  depsInfo.forEach((info) => {\n    if (info.aliasName) {\n      const { aliasNames } = exportItems[info.exportName];\n      if (aliasNames.indexOf(info.aliasName) < 0) {\n        aliasNames.push(info.aliasName);\n      }\n    }\n  });\n\n  // fix: 父组件ImportAliasDefine, 与子组件import的父组件冲突情况\n  depsInfo.forEach((info) => {\n    if (info.nodeIdentifier) {\n      const exportItem = exportItems[info.exportName];\n      if (!exportItem.needOriginExport && exportItem.aliasNames.length > 0) {\n        // eslint-disable-next-line no-param-reassign\n        info.aliasName = exportItem.aliasNames[0];\n      }\n    }\n  });\n\n  // 发现 nodeIdentifier 与 exportName 或者 aliasName 冲突的场景\n  const nodeIdentifiers = depsInfo.map((info) => info.nodeIdentifier).filter(Boolean);\n  const conflictInfos = flatMap(Object.keys(exportItems), (exportName) => {\n    const exportItem = exportItems[exportName];\n    const usedNames = [\n      ...exportItem.aliasNames,\n      ...(exportItem.needOriginExport || exportItem.aliasNames.length <= 0 ? [exportName] : []),\n    ];\n    const conflictNames = usedNames.filter((n) => nodeIdentifiers.indexOf(n) >= 0);\n    if (conflictNames.length > 0) {\n      return [\n        ...(conflictNames.indexOf(exportName) >= 0 ? [[exportName, true, exportItem]] : []),\n        ...conflictNames.filter((n) => n !== exportName).map((n) => [n, false, exportItem]),\n      ];\n    }\n    return [];\n  });\n\n  const conflictExports = conflictInfos.filter((c) => c[1]).map((c) => c[0] as string);\n  const conflictAlias = conflictInfos.filter((c) => !c[1]).map((c) => c[0] as string);\n\n  const solutions: Record<string, string> = {};\n\n  depsInfo.forEach((info) => {\n    if (info.aliasName && conflictAlias.indexOf(info.aliasName) >= 0) {\n      // find solution\n      let solution = solutions[info.aliasName];\n      if (!solution) {\n        solution = `${info.aliasName}Alias`;\n        const conflictItem = (conflictInfos.find((c) => c[0] === info.aliasName) ||\n          [])[2] as IExportItem;\n        conflictItem.aliasNames = conflictItem.aliasNames.filter((a) => a !== info.aliasName);\n        conflictItem.aliasNames.push(solution);\n        solutions[info.aliasName] = solution;\n      }\n      // eslint-disable-next-line no-param-reassign\n      info.aliasName = solution;\n    }\n\n    if (conflictExports.indexOf(info.exportName) >= 0) {\n      // find solution\n      let solution = solutions[info.exportName];\n      if (!solution) {\n        solution = `${info.exportName}Export`;\n        const conflictItem = (conflictInfos.find((c) => c[0] === info.exportName) ||\n          [])[2] as IExportItem;\n        conflictItem.aliasNames.push(solution);\n        conflictItem.needOriginExport = false;\n        solutions[info.exportName] = solution;\n      }\n      // eslint-disable-next-line no-param-reassign\n      info.aliasName = solution;\n    }\n  });\n\n  // 判断是否所有依赖都有合法的 Identifier\n  depsInfo.forEach((info) => {\n    const name = info.aliasName || info.exportName;\n    if (!isValidIdentifier(name)) {\n      throw new CodeGeneratorError(`Invalid Identifier [${name}]`);\n    }\n    if (info.nodeIdentifier && !isValidIdentifier(info.nodeIdentifier)) {\n      throw new CodeGeneratorError(`Invalid Identifier [${info.nodeIdentifier}]`);\n    }\n  });\n\n  const aliasDefineStatements: Record<string, string> = {};\n  if (useAliasName) {\n    Object.keys(exportItems).forEach((exportName) => {\n      const aliasList = exportItems[exportName]?.aliasNames || [];\n      if (aliasList.length > 0) {\n        const srcName = exportItems[exportName].needOriginExport ? exportName : aliasList[0];\n        const aliasNameList = exportItems[exportName].needOriginExport\n          ? aliasList\n          : aliasList.slice(1);\n        aliasNameList.forEach((a) => {\n          if (!aliasDefineStatements[a]) {\n            aliasDefineStatements[a] = `const ${a} = ${srcName};`;\n          }\n        });\n      }\n    });\n  }\n\n  function getDefaultExportName(info: IDependencyItem): string {\n    if (info.isDefault) {\n      return defaultExportNames[0];\n    }\n    return info.exportName;\n  }\n\n  depsInfo.forEach((info) => {\n    // 如果是子组件，则导出父组件，并且根据自组件命名规则，判断是否需要定义标识符\n    if (info.nodeIdentifier) {\n      // 前提，存在 nodeIdentifier 一定是有 subName 的，不然前面会优化掉\n      const ownerName = getDependencyIdentifier(info);\n\n      chunks.push({\n        type: ChunkType.STRING,\n        fileType: targetFileType,\n        name: COMMON_CHUNK_NAME.ImportAliasDefine,\n        content: useAliasName ? `const ${info.nodeIdentifier} = ${ownerName}.${info.subName};` : '',\n        linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport],\n        ext: {\n          originalName: `${getDefaultExportName(info)}.${info.subName}`,\n          aliasName: info.nodeIdentifier,\n          dependency: info.source,\n        },\n      });\n    } else if (info.aliasName) {\n      // default 方式的导入会生成单独de import 语句，无需生成赋值语句\n      if (info.isDefault && defaultExportNames.find((n) => n === info.aliasName)) {\n        delete aliasDefineStatements[info.aliasName];\n        return;\n      }\n\n      let contentStatement = '';\n      if (aliasDefineStatements[info.aliasName]) {\n        contentStatement = aliasDefineStatements[info.aliasName];\n        delete aliasDefineStatements[info.aliasName];\n      }\n\n      chunks.push({\n        type: ChunkType.STRING,\n        fileType: targetFileType,\n        name: COMMON_CHUNK_NAME.ImportAliasDefine,\n        content: contentStatement,\n        linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport],\n        ext: {\n          originalName: getDefaultExportName(info),\n          aliasName: info.aliasName,\n          dependency: info.source,\n        },\n      });\n    }\n  });\n\n  // 可能会剩余一些存在二次转换的定义\n  Object.keys(aliasDefineStatements).forEach((a) => {\n    chunks.push({\n      type: ChunkType.STRING,\n      fileType: targetFileType,\n      name: COMMON_CHUNK_NAME.ImportAliasDefine,\n      content: aliasDefineStatements[a],\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport],\n    });\n  });\n\n  const exportItemList = Object.keys(exportItems).map((k) => exportItems[k]);\n  const defaultExport = exportItemList.filter((item) => item.isDefault);\n  const otherExports = exportItemList.filter((item) => !item.isDefault);\n\n  const statementL = ['import'];\n  if (defaultExport.length > 0) {\n    if (useAliasName) {\n      statementL.push(defaultExportNames[0]);\n    } else {\n      statementL.push(defaultExport[0].aliasNames[0]);\n    }\n    if (otherExports.length > 0) {\n      statementL.push(', ');\n    }\n  }\n  if (otherExports.length > 0) {\n    const items = otherExports.map((item) => {\n      return !useAliasName || item.needOriginExport || item.aliasNames.length <= 0\n        ? item.exportName\n        : `${item.exportName} as ${item.aliasNames[0]}`;\n    });\n    statementL.push(`{ ${items.join(', ')} }`);\n  }\n  statementL.push('from');\n\n  const getInternalDependencyModuleId = () => `@/${(deps[0] as IInternalDependency).type}/${pkg}`;\n\n  if (deps[0].dependencyType === DependencyType.Internal) {\n    // TODO: Internal Deps path use project slot setting\n    statementL.push(`'${getInternalDependencyModuleId()}';`);\n    chunks.push({\n      type: ChunkType.STRING,\n      fileType: targetFileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: statementL.join(' '),\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n  } else {\n    statementL.push(`'${pkg}';`);\n    chunks.push({\n      type: ChunkType.STRING,\n      fileType: targetFileType,\n      name: COMMON_CHUNK_NAME.ExternalDepsImport,\n      content: statementL.join(' '),\n      linkAfter: [],\n    });\n  }\n\n  // 处理下一些额外的 default 方式的导入\n  if (defaultExportNames.length > 1) {\n    if (deps[0].dependencyType === DependencyType.Internal) {\n      defaultExportNames.slice(1).forEach((exportName) => {\n        chunks.push({\n          type: ChunkType.STRING,\n          fileType: targetFileType,\n          name: COMMON_CHUNK_NAME.InternalDepsImport,\n          content: `import ${exportName} from '${getInternalDependencyModuleId()}';`,\n          linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n        });\n      });\n    } else {\n      defaultExportNames.slice(1).forEach((exportName) => {\n        chunks.push({\n          type: ChunkType.STRING,\n          fileType: targetFileType,\n          name: COMMON_CHUNK_NAME.ExternalDepsImport,\n          content: `import ${exportName} from '${pkg}';`,\n          linkAfter: [],\n        });\n\n        chunks.push({\n          type: ChunkType.STRING,\n          fileType: targetFileType,\n          name: COMMON_CHUNK_NAME.ImportAliasDefine,\n          content: '',\n          linkAfter: [],\n          ext: {\n            aliasName: exportName,\n            originalName: exportName,\n            dependency: {\n              package: pkg,\n              componentName: exportName,\n            },\n          },\n        });\n      });\n    }\n  }\n\n  return chunks;\n}\n\nexport interface PluginConfig {\n  fileType?: string; // 导出的文件类型\n  useAliasName?: boolean; // 是否使用 componentName 重命名组件 identifier\n  filter?: (deps: IDependency[]) => IDependency[]; // 支持过滤能力\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?: PluginConfig) => {\n  const cfg = {\n    fileType: FileType.JS,\n    useAliasName: true,\n    ...(config || {}),\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IWithDependency;\n\n    if (ir && ir.deps && ir.deps.length > 0) {\n      const deps = cfg.filter ? cfg.filter(ir.deps) : ir.deps;\n      const packs = groupDepsByPack(deps);\n\n      Object.keys(packs).forEach((pkg) => {\n        const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType, cfg.useAliasName);\n        next.chunks.push(...chunks);\n      });\n    }\n\n    return next;\n  };\n\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/common/requireUtils.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../const/generator';\n\nimport { BuilderComponentPlugin, BuilderComponentPluginFactory, ChunkType, FileType, ICodeStruct } from '../../types';\n\n// TODO: How to merge this logic to common deps\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: 'import * from \\'react\\';',\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/common/styleImport.ts",
    "content": "import changeCase from 'change-case';\nimport {\n  FileType,\n  BuilderComponentPluginFactory,\n  BuilderComponentPlugin,\n  ICodeStruct,\n  IWithDependency,\n  ChunkType,\n} from '../../types';\n\nimport { COMMON_CHUNK_NAME } from '../../const/generator';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IWithDependency;\n    const { chunks } = next;\n\n    if (ir && ir.deps && ir.deps.length > 0) {\n      let lowcodeMaterialsStyleAdded = false;\n      let fusionUIStyleAdded = false;\n      let nextStyleAddedMap: Record<string, boolean> = {};\n      ir.deps.forEach((dep: any) => {\n        if (dep.package === '@alifd/next' && !nextStyleAddedMap[dep.exportName]) {\n          chunks.push({\n            type: ChunkType.STRING,\n            fileType: FileType.JSX,\n            name: COMMON_CHUNK_NAME.InternalDepsImport,\n            content: `import '@alifd/next/lib/${changeCase.paramCase(dep.exportName)}/style';`,\n            linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n          });\n          nextStyleAddedMap[dep.exportName] = true;\n        } else if (dep.package === '@alilc/lowcode-materials' && !lowcodeMaterialsStyleAdded) {\n          chunks.push({\n            type: ChunkType.STRING,\n            fileType: FileType.JSX,\n            name: COMMON_CHUNK_NAME.InternalDepsImport,\n            content: 'import \\'@alilc/lowcode-materials/lib/style\\';',\n            linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n          });\n          lowcodeMaterialsStyleAdded = true;\n        } else if (dep.package === '@alifd/fusion-ui' && !fusionUIStyleAdded) {\n          chunks.push({\n            type: ChunkType.STRING,\n            fileType: FileType.JSX,\n            name: COMMON_CHUNK_NAME.InternalDepsImport,\n            content: 'import \\'@alifd/fusion-ui/lib/style\\';',\n            linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n          });\n          fusionUIStyleAdded = true;\n        }\n      });\n    }\n\n    return next;\n  };\n\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/commonDeps.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.ExternalDepsImport,\n      content: `\n        // 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n        // 例外：rax 框架的导出名和各种组件名除外。\n        import { createElement, Component } from 'rax';\n        import { getSearchParams as __$$getSearchParams } from 'rax-app';\n      `,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/const.ts",
    "content": "export const RAX_CHUNK_NAME = {\n  ClassDidMountBegin: 'RaxComponentClassDidMountBegin',\n  ClassDidMountContent: 'RaxComponentClassDidMountContent',\n  ClassDidMountEnd: 'RaxComponentClassDidMountEnd',\n  ClassWillUnmountBegin: 'RaxComponentClassWillUnmountBegin',\n  ClassWillUnmountContent: 'RaxComponentClassWillUnmountContent',\n  ClassWillUnmountEnd: 'RaxComponentClassWillUnmountEnd',\n  ClassRenderBegin: 'RaxComponentClassRenderBegin',\n  ClassRenderPre: 'RaxComponentClassRenderPre',\n  ClassRenderJSX: 'RaxComponentClassRenderJSX',\n  ClassRenderEnd: 'RaxComponentClassRenderEnd',\n  MethodsBegin: 'RaxComponentMethodsBegin',\n  MethodsContent: 'RaxComponentMethodsContent',\n  MethodsEnd: 'RaxComponentMethodsEnd',\n  LifeCyclesBegin: 'RaxComponentLifeCyclesBegin',\n  LifeCyclesContent: 'RaxComponentLifeCyclesContent',\n  LifeCyclesEnd: 'RaxComponentLifeCyclesEnd',\n};\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/containerClass.ts",
    "content": "import changeCase from 'change-case';\nimport {\n  COMMON_CHUNK_NAME,\n  CLASS_DEFINE_CHUNK_NAME,\n  DEFAULT_LINK_AFTER,\n} from '../../../const/generator';\nimport { RAX_CHUNK_NAME } from './const';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { ensureValidClassName } from '../../../utils/validate';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n\n    // 将模块名转换成 PascalCase 的格式，并添加特定后缀，防止命名冲突\n    const componentClassName = ensureValidClassName(\n      `${changeCase.pascalCase(ir.moduleName)}$$Page`,\n    );\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.Start,\n      content: `class ${componentClassName} extends Component {`,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.End,\n      content: '}',\n      linkAfter: [\n        CLASS_DEFINE_CHUNK_NAME.Start,\n        CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,\n        RAX_CHUNK_NAME.ClassRenderEnd,\n        RAX_CHUNK_NAME.MethodsEnd,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart,\n      content: 'constructor(props, context) { super(props); ',\n      linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,\n      content: '} /* end of constructor */',\n      linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: RAX_CHUNK_NAME.ClassDidMountBegin,\n      content: 'componentDidMount() {',\n      linkAfter: [\n        CLASS_DEFINE_CHUNK_NAME.Start,\n        CLASS_DEFINE_CHUNK_NAME.InsVar,\n        CLASS_DEFINE_CHUNK_NAME.InsMethod,\n        CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: RAX_CHUNK_NAME.ClassDidMountEnd,\n      content: '} /* end of componentDidMount */',\n      linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin, RAX_CHUNK_NAME.ClassDidMountContent],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: RAX_CHUNK_NAME.ClassWillUnmountBegin,\n      content: 'componentWillUnmount() {',\n      linkAfter: [\n        CLASS_DEFINE_CHUNK_NAME.Start,\n        CLASS_DEFINE_CHUNK_NAME.InsVar,\n        CLASS_DEFINE_CHUNK_NAME.InsMethod,\n        RAX_CHUNK_NAME.ClassDidMountEnd,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: RAX_CHUNK_NAME.ClassWillUnmountEnd,\n      content: '} /* end of componentWillUnmount */',\n      linkAfter: [RAX_CHUNK_NAME.ClassWillUnmountBegin, RAX_CHUNK_NAME.ClassWillUnmountContent],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: RAX_CHUNK_NAME.ClassRenderBegin,\n      content: 'render() {',\n      linkAfter: [RAX_CHUNK_NAME.ClassDidMountEnd, RAX_CHUNK_NAME.ClassWillUnmountEnd],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: RAX_CHUNK_NAME.ClassRenderEnd,\n      content: '} /* end of render */',\n      linkAfter: [\n        RAX_CHUNK_NAME.ClassRenderBegin,\n        RAX_CHUNK_NAME.ClassRenderPre,\n        RAX_CHUNK_NAME.ClassRenderJSX,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.FileExport,\n      content: `export default ${componentClassName};`,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n        CLASS_DEFINE_CHUNK_NAME.End,\n      ],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/containerInitState.ts",
    "content": "import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';\n\nimport { generateCompositeType } from '../../../utils/compositeType';\nimport { Scope } from '../../../utils/Scope';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\n\nexport interface PluginConfig {\n  fileType: string;\n  implementType: 'inConstructor' | 'insMember' | 'hooks';\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    implementType: 'insMember',\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    const scope = Scope.createRootScope();\n\n    const state = ir.state || {};\n    const fields = Object.keys(state).map<string>((stateName) => {\n      // TODO: 这里用什么 handlers?\n      const value = generateCompositeType(state[stateName], scope);\n      return `${JSON.stringify(stateName)}: ${value}`;\n    });\n\n    if (cfg.implementType === 'inConstructor') {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n        content: `this.state = { ${fields.join(',')} };`,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],\n      });\n    } else if (cfg.implementType === 'insMember') {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: `state = { ${fields.join(',')} };`,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],\n      });\n    }\n    // TODO: hooks state??\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/containerInjectContext.ts",
    "content": "/* eslint-disable @typescript-eslint/indent */\nimport { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { RAX_CHUNK_NAME } from './const';\nimport { DEFAULT_LINK_AFTER } from '../../../const';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    const useRef = !!ir.analyzeResult?.isUsingRef;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: \"import __$$constants from '../../constants';\",\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    // TODO: i18n 是可选的，如果没有 i18n 这个文件怎么办？该怎么判断？\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: \"import * as __$$i18n from '../../i18n';\",\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n      content: `\n        __$$i18n._inject2(this);\n      `,\n      linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n      content: `\n        _context = this._createContext();\n      `,\n      linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],\n    });\n\n    // TODO: 按照目前的实现方案，代码的插拔能力太弱了，需要有一些变化。\n    //   Step 1: 增加前置的分析器\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,\n      content: `\n        _createContext() {\n          const self = this;\n          const context = {\n            get state() {\n              return self.state;\n            },\n            setState(newState, callback) {\n              self.setState(newState, callback);\n            },\n            get dataSourceMap() {\n              return self._dataSourceEngine.dataSourceMap || {};\n            },\n            async reloadDataSource() {\n              await self._dataSourceEngine.reloadDataSource();\n            },\n            get utils() {\n              return self._utils;\n            },\n            get page() {\n              return context;\n            },\n            get component() {\n              return context;\n            },\n            get props() {\n              return self.props;\n            },\n            get constants() {\n              return __$$constants;\n            },\n            i18n: __$$i18n.i18n,\n            i18nFormat: __$$i18n.i18nFormat,\n            getLocale: __$$i18n.getLocale,\n            setLocale(locale) {\n              __$$i18n.setLocale(locale);\n              self.forceUpdate();\n            },${\n              useRef\n                ? `\n                  $(refName) {\n                    return self._refsManager.get(refName);\n                  },\n                  $$(refName) {\n                    return self._refsManager.getAll(refName);\n                  },\n                  get _refsManager() {\n                    if (!self._refsManager) {\n                      self._refsManager = new RefsManager();\n                    }\n                    return self._refsManager;\n                  },\n                `\n                : ''\n            }\n            ...this._methods,\n          };\n\n          return context;\n        }\n      `,\n      linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts",
    "content": "/* eslint-disable @typescript-eslint/indent */\n\nimport {\n  IPublicTypeCompositeValue,\n  IPublicTypeJSExpression,\n  InterpretDataSourceConfig,\n  isJSExpression,\n  isJSFunction,\n} from '@alilc/lowcode-types';\nimport changeCase from 'change-case';\n\nimport { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator';\nimport { Scope } from '../../../utils/Scope';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IScope,\n} from '../../../types';\n\nimport { generateCompositeType } from '../../../utils/compositeType';\nimport { parseExpressionConvertThis2Context } from '../../../utils/expressionParser';\nimport { isContainerSchema } from '../../../utils/schema';\nimport { RaxFrameworkOptions } from '../../project/framework/rax/types/RaxFrameworkOptions';\nimport { RAX_CHUNK_NAME } from './const';\n\nexport interface PluginConfig extends RaxFrameworkOptions {\n  fileType?: string;\n\n  /**\n   * 数据源的 handlers 的映射配置\n   * @deprecated 请使用 datasourceConfig.handlersPackages 来配置\n   */\n  dataSourceHandlersPackageMap?: Record<string, string>;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n    dataSourceHandlersPackageMap:\n      config?.dataSourceHandlersPackageMap || config?.datasourceConfig?.handlersPackages,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const scope = Scope.createRootScope();\n    const dataSourceConfig = isContainerSchema(pre.ir) ? pre.ir.dataSource : null;\n    const dataSourceItems: InterpretDataSourceConfig[] =\n      (dataSourceConfig && dataSourceConfig.list) || [];\n    const dataSourceEngineOptions = { runtimeConfig: true };\n    if (dataSourceItems.length > 0) {\n      const requestHandlersMap: Record<string, IPublicTypeJSExpression> = {};\n\n      dataSourceItems.forEach((ds) => {\n        const dsType = ds.type || 'fetch';\n        if (!(dsType in requestHandlersMap) && dsType !== 'custom') {\n          const handlerFactoryName = `__$$create${changeCase.pascal(dsType)}RequestHandler`;\n\n          requestHandlersMap[dsType] = {\n            type: 'JSExpression',\n            value: `${handlerFactoryName}(${\n              dsType === 'urlParams' ? '__$$getSearchParams()' : ''\n            })`,\n          };\n\n          const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`;\n          const handlerPkgName =\n            cfg.dataSourceHandlersPackageMap?.[dsType] ||\n            `@alilc/lowcode-datasource-${changeCase.kebab(dsType)}-handler`;\n\n          next.chunks.push({\n            type: ChunkType.STRING,\n            fileType: FileType.JSX,\n            name: COMMON_CHUNK_NAME.ExternalDepsImport,\n            content: `\n              import { ${handlerFactoryExportName} as ${handlerFactoryName} } from '${handlerPkgName}';\n            `,\n            linkAfter: [],\n          });\n        }\n      });\n\n      Object.assign(dataSourceEngineOptions, { requestHandlersMap });\n    }\n\n    const datasourceEnginePackageName =\n      cfg.datasourceConfig?.enginePackage || '@alilc/lowcode-datasource-engine';\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.ExternalDepsImport,\n      content: `\n        import { create as __$$createDataSourceEngine } from '${datasourceEnginePackageName}/runtime';\n      `,\n      linkAfter: [],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType!,\n      name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n      content: `\n        _dataSourceConfig = this._defineDataSourceConfig();\n        _dataSourceEngine = __$$createDataSourceEngine(\n          this._dataSourceConfig,\n          this._context,\n          ${generateCompositeType(dataSourceEngineOptions, scope)}\n        );`,\n      linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType!,\n      name: RAX_CHUNK_NAME.ClassDidMountContent,\n      content: `\n        this._dataSourceEngine.reloadDataSource();\n      `,\n      linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType!,\n      name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,\n      content: `\n_defineDataSourceConfig() {\n  const __$$context = this._context;\n  return (${generateCompositeType(\n    {\n      ...dataSourceConfig,\n      list: [\n        ...dataSourceItems.map((item) => ({\n          // 数据源引擎默认的 errorHandler 是空的，而且并不会触发组件重新渲染……\n          // 这会导致页面状态不能正常展示，故这里处理下:\n          errorHandler: {\n            type: 'JSFunction',\n            value: `function (err){\n              setTimeout(() => {\n                this.setState({ __refresh: Date.now() + Math.random() });\n              }, 0);\n              throw err;\n            }`,\n          },\n          ...item,\n          isInit:\n            typeof item.isInit === 'boolean' || typeof item.isInit === 'undefined'\n              ? item.isInit ?? true\n              : wrapAsFunction(item.isInit, scope),\n          options: wrapAsFunction(item.options, scope),\n        })),\n      ],\n    },\n    scope,\n    {\n      handlers: {\n        function: (jsFunc) => parseExpressionConvertThis2Context(jsFunc.value, '__$$context'),\n        expression: (jsExpr) => parseExpressionConvertThis2Context(jsExpr.value, '__$$context'),\n      },\n    },\n  )});\n}\n      `,\n      linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n\nfunction wrapAsFunction(value: IPublicTypeCompositeValue, scope: IScope): IPublicTypeCompositeValue {\n  if (isJSExpression(value) || isJSFunction(value)) {\n    return {\n      type: 'JSExpression',\n      value: `function(){ return ((${value.value}))}`,\n    };\n  }\n\n  return {\n    type: 'JSExpression',\n    value: `function(){return((${generateCompositeType(value, scope)}))}`,\n  };\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/containerInjectUtils.ts",
    "content": "import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { RAX_CHUNK_NAME } from './const';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    const useRef = !!ir.analyzeResult?.isUsingRef;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      // TODO: 下面这个路径有没有更好的方式来获取？而非写死\n      content: `\n        import __$$projectUtils${useRef ? ', { RefsManager }' : ''} from '../../utils';\n      `,\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n      content: '_utils = this._defineUtils();',\n      linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,\n\n      content: `\n        _defineUtils() {\n          return {\n            ...__$$projectUtils,\n          };\n        }`,\n      linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts",
    "content": "import _ from 'lodash';\nimport { isJSExpression, isJSFunction } from '@alilc/lowcode-types';\n\nimport { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';\nimport { RAX_CHUNK_NAME } from './const';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  FileType,\n  ChunkType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { debug } from '../../../utils/debug';\nimport { isJSExpressionFn } from '../../../utils/common';\n\nexport interface PluginConfig {\n  fileType: string;\n  exportNameMapping: Record<string, string>;\n  normalizeNameMapping: Record<string, string>;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    exportNameMapping: {},\n    normalizeNameMapping: {\n      didMount: 'componentDidMount',\n      willUnmount: 'componentWillUnmount',\n    },\n    ...config,\n  };\n\n  const exportNameMapping = new Map(Object.entries(cfg.exportNameMapping));\n  const normalizeNameMapping = new Map(Object.entries(cfg.normalizeNameMapping));\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    // Rax 先只支持 didMount 和 willUnmount 吧\n\n    const ir = next.ir as IContainerInfo;\n    const { lifeCycles } = ir;\n\n    if (lifeCycles && !_.isEmpty(lifeCycles)) {\n      Object.entries(lifeCycles).forEach(([lifeCycleName, lifeCycleMethodExpr]) => {\n        // 过滤掉非法数据（有些场景下会误传入空字符串或 null)\n        if (\n          !isJSFunction(lifeCycles[lifeCycleName]) &&\n          !isJSExpressionFn(lifeCycles[lifeCycleName]) &&\n          !isJSExpression(lifeCycles[lifeCycleName])\n        ) {\n          return;\n        }\n\n        const normalizeName = normalizeNameMapping.get(lifeCycleName) || lifeCycleName;\n        const exportName = exportNameMapping.get(lifeCycleName) || lifeCycleName;\n\n        next.chunks.push({\n          type: ChunkType.STRING,\n          fileType: cfg.fileType,\n          name: RAX_CHUNK_NAME.LifeCyclesContent,\n          content: `${exportName}: (${lifeCycleMethodExpr.value}),`,\n          linkAfter: [RAX_CHUNK_NAME.LifeCyclesBegin],\n        });\n\n        if (normalizeName === 'constructor') {\n          next.chunks.push({\n            type: ChunkType.STRING,\n            fileType: cfg.fileType,\n            name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n            content: `this._lifeCycles.${exportName}();`,\n            linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],\n          });\n        } else if (normalizeName === 'componentDidMount') {\n          next.chunks.push({\n            type: ChunkType.STRING,\n            fileType: cfg.fileType,\n            name: RAX_CHUNK_NAME.ClassDidMountContent,\n            content: `this._lifeCycles.${exportName}();`,\n            linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin],\n          });\n        } else if (normalizeName === 'componentWillUnmount') {\n          next.chunks.push({\n            type: ChunkType.STRING,\n            fileType: cfg.fileType,\n            name: RAX_CHUNK_NAME.ClassWillUnmountContent,\n            content: `this._lifeCycles.${exportName}();`,\n            linkAfter: [RAX_CHUNK_NAME.ClassWillUnmountBegin],\n          });\n        } else {\n          debug(`[CodeGen]: unknown life cycle: ${lifeCycleName}`);\n        }\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: '_lifeCycles = this._defineLifeCycles();',\n        linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: RAX_CHUNK_NAME.LifeCyclesBegin,\n        content: `\n          _defineLifeCycles() {\n            const __$$lifeCycles = ({\n        `,\n        linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd, CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: RAX_CHUNK_NAME.LifeCyclesEnd,\n        content: `\n            });\n\n            // 为所有的方法绑定上下文\n            Object.entries(__$$lifeCycles).forEach(([lifeCycleName, lifeCycleMethod]) => {\n              if (typeof lifeCycleMethod === 'function') {\n                __$$lifeCycles[lifeCycleName] = (...args) => {\n                  return lifeCycleMethod.apply(this._context, args);\n                }\n              }\n            });\n\n            return __$$lifeCycles;\n          }\n        `,\n        linkAfter: [RAX_CHUNK_NAME.LifeCyclesBegin, RAX_CHUNK_NAME.LifeCyclesContent],\n      });\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/containerMethods.ts",
    "content": "import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\n\nimport { RAX_CHUNK_NAME } from './const';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n      content: `\n         _methods = this._defineMethods();\n      `,\n      linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: RAX_CHUNK_NAME.MethodsBegin,\n      content: `\n        _defineMethods() {\n          return ({\n      `,\n      linkAfter: [\n        RAX_CHUNK_NAME.ClassRenderEnd,\n        CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,\n        RAX_CHUNK_NAME.LifeCyclesEnd,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: RAX_CHUNK_NAME.MethodsEnd,\n      content: `\n          });\n        }\n      `,\n      linkAfter: [RAX_CHUNK_NAME.MethodsBegin, RAX_CHUNK_NAME.MethodsContent],\n    });\n\n    if (ir.methods && Object.keys(ir.methods).length > 0) {\n      Object.entries(ir.methods).forEach(([methodName, methodDefine]) => {\n        next.chunks.push({\n          type: ChunkType.STRING,\n          fileType: cfg.fileType,\n          name: RAX_CHUNK_NAME.MethodsContent,\n          content: `${methodName}: (${methodDefine.value}),`,\n          linkAfter: [RAX_CHUNK_NAME.MethodsBegin],\n        });\n      });\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/rax/jsx.ts",
    "content": "import {\n  IPublicTypeNodeSchema,\n  IPublicTypeJSExpression,\n  IPublicTypeNpmInfo,\n  IPublicTypeCompositeValue,\n  isJSExpression,\n} from '@alilc/lowcode-types';\n\nimport _ from 'lodash';\nimport changeCase from 'change-case';\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  CodePiece,\n  FileType,\n  ICodeChunk,\n  ICodeStruct,\n  IContainerInfo,\n  PIECE_TYPE,\n  HandlerSet,\n  IScope,\n  NodeGeneratorConfig,\n  NodePlugin,\n  AttrPlugin,\n} from '../../../types';\n\nimport { RAX_CHUNK_NAME } from './const';\nimport { COMMON_CHUNK_NAME } from '../../../const/generator';\n\nimport { generateExpression } from '../../../utils/jsExpression';\nimport {\n  createNodeGenerator,\n  generateConditionReactCtrl,\n  generateReactExprInJS,\n} from '../../../utils/nodeToJSX';\nimport { generateCompositeType } from '../../../utils/compositeType';\nimport { Scope } from '../../../utils/Scope';\nimport { parseExpressionGetGlobalVariables } from '../../../utils/expressionParser';\nimport { transformThis2Context } from '../../../core/jsx/handlers/transformThis2Context';\nimport { transformJsExpr } from '../../../core/jsx/handlers/transformJsExpression';\n\nexport interface PluginConfig {\n  fileType: string;\n\n  /** 是否要忽略小程序 */\n  ignoreMiniApp?: boolean;\n}\n\n// TODO: componentName 若并非大写字符打头，甚至并非是一个有效的 JS 标识符怎么办？？\n// FIXME: 我想了下，这块应该放到解析阶段就去做掉，对所有 componentName 做 identifier validate，然后对不合法的做统一替换。\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    const rootScope = Scope.createRootScope();\n    const { tolerateEvalErrors = true, evalErrorsHandler = '' } = next.contextData;\n\n    // Rax 构建到小程序的时候，不能给组件起起别名，得直接引用，故这里将所有的别名替换掉\n    // 先收集下所有的 alias 的映射\n    const componentsNameAliasMap = new Map<string, string>();\n    next.chunks.forEach((chunk) => {\n      if (isImportAliasDefineChunk(chunk)) {\n        componentsNameAliasMap.set(chunk.ext.aliasName, chunk.ext.originalName);\n      }\n    });\n\n    // 注意：这里其实隐含了一个假设：schema 中的 componentName 应该是一个有效的 JS 标识符，而且是大写字母打头的\n    // FIXME: 为了快速修复临时加的逻辑，需要用 pre-process 的方式替代处理。\n    const mapComponentNameToAliasOrKeepIt = (componentName: string) => componentsNameAliasMap.get(componentName) || componentName;\n\n    // 然后过滤掉所有的别名 chunks\n    next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk));\n\n    // 如果直接按目前的 React 的方式之间出码 JSX 的话，会有 3 个问题：\n    // 1. 小程序出码的时候，循环变量没法拿到\n    // 2. 小程序出码的时候，很容易出现 Uncaught TypeError: Cannot read property 'avatar' of undefined 这样的异常(如下图的 50 行) -- 因为若直接出码，Rax 构建到小程序的时候会立即计算所有在视图中用到的变量\n    // 3. 通过 this.xxx 能拿到的东西太多了，而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东\n    const customHandlers: HandlerSet<string> = {\n      expression(input: IPublicTypeJSExpression, scope: IScope) {\n        return transformJsExpr(generateExpression(input, scope), scope, {\n          dontWrapEval: !tolerateEvalErrors,\n        });\n      },\n      function(input, scope: IScope) {\n        return transformThis2Context(input.value || 'null', scope);\n      },\n    };\n\n    // 创建代码生成器\n    const commonNodeGenerator = createNodeGenerator({\n      handlers: customHandlers,\n      tagMapping: mapComponentNameToAliasOrKeepIt,\n      nodePlugins: [generateReactExprInJS, generateConditionReactCtrl, generateRaxLoopCtrl],\n      attrPlugins: [generateNodeAttrForRax.bind({ cfg })],\n    });\n\n    // 生成 JSX 代码\n    const jsxContent = commonNodeGenerator(ir, rootScope);\n\n    if (!cfg.ignoreMiniApp) {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: COMMON_CHUNK_NAME.ExternalDepsImport,\n        content: \"import { isMiniApp as __$$isMiniApp } from 'universal-env';\",\n        linkAfter: [],\n      });\n    }\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: RAX_CHUNK_NAME.ClassRenderPre,\n      // TODO: setState, dataSourceMap, reloadDataSource, utils, i18n, i18nFormat, getLocale, setLocale 这些在 Rax 的编译模式下不能在视图中直接访问，需要转化成 this.xxx\n      content: `\n        const __$$context = this._context;\n        const { state, setState, dataSourceMap, reloadDataSource, utils, constants, i18n, i18nFormat, getLocale, setLocale } = __$$context;\n      `,\n      linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: RAX_CHUNK_NAME.ClassRenderJSX,\n      content: `return ${jsxContent};`,\n      linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin, RAX_CHUNK_NAME.ClassRenderPre],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.CustomContent,\n      content: [\n        tolerateEvalErrors &&\n          `\n        function __$$eval(expr) {\n          try {\n            return expr();\n          } catch (error) {\n            ${evalErrorsHandler}\n          }\n        }\n\n        function __$$evalArray(expr) {\n          const res = __$$eval(expr);\n          return Array.isArray(res) ? res : [];\n        }\n        `,\n        `\n        function __$$createChildContext(oldContext, ext) {\n          return Object.assign({}, oldContext, ext);\n        }\n      `,\n      ]\n        .filter(Boolean)\n        .join('\\n'),\n      linkAfter: [COMMON_CHUNK_NAME.FileExport],\n    });\n\n    return next;\n\n    function generateRaxLoopCtrl(\n      nodeItem: IPublicTypeNodeSchema,\n      scope: IScope,\n      config?: NodeGeneratorConfig,\n      next?: NodePlugin,\n    ): CodePiece[] {\n      if (nodeItem.loop) {\n        const loopItemName = nodeItem.loopArgs?.[0] || 'item';\n        const loopIndexName = nodeItem.loopArgs?.[1] || 'index';\n        const subScope = scope.createSubScope([loopItemName, loopIndexName]);\n        const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : [];\n\n        const loopDataExpr = tolerateEvalErrors\n          ? `__$$evalArray(() => (${transformThis2Context(\n              generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }),\n              scope,\n            )}))`\n          : `(${transformThis2Context(\n              generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }),\n              scope,\n            )})`;\n\n        pieces.unshift({\n          value: `${loopDataExpr}.map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`,\n          type: PIECE_TYPE.BEFORE,\n        });\n\n        pieces.push({\n          value: `))(__$$createChildContext(__$$context, { ${loopItemName}, ${loopIndexName} })))`,\n          type: PIECE_TYPE.AFTER,\n        });\n\n        return pieces;\n      }\n\n      return next ? next(nodeItem, scope, config) : [];\n    }\n  };\n\n  return plugin;\n};\n\nexport default pluginFactory;\n\nfunction isImportAliasDefineChunk(chunk: ICodeChunk): chunk is ICodeChunk & {\n  ext: {\n    aliasName: string;\n    originalName: string;\n    dependency: IPublicTypeNpmInfo;\n  };\n} {\n  return (\n    chunk.name === COMMON_CHUNK_NAME.ImportAliasDefine &&\n    !!chunk.ext &&\n    typeof chunk.ext.aliasName === 'string' &&\n    typeof chunk.ext.originalName === 'string' &&\n    !!(chunk.ext.dependency as IPublicTypeNpmInfo | null)?.componentName\n  );\n}\n\nfunction generateNodeAttrForRax(\n  this: { cfg: PluginConfig },\n  attrData: { attrName: string; attrValue: IPublicTypeCompositeValue },\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n  next?: AttrPlugin,\n): CodePiece[] {\n  if (!this.cfg.ignoreMiniApp && /^on/.test(attrData.attrName)) {\n    // else: onXxx 的都是事件处理函数需要特殊处理下\n    return generateEventHandlerAttrForRax(attrData.attrName, attrData.attrValue, scope, config);\n  }\n\n  if (attrData.attrName === 'ref') {\n    return [\n      {\n        name: attrData.attrName,\n        value: `__$$context._refsManager.linkRef('${attrData.attrValue}')`,\n        type: PIECE_TYPE.ATTR,\n      },\n    ];\n  }\n\n  return next ? next(attrData, scope, config) : [];\n}\n\nfunction generateEventHandlerAttrForRax(\n  attrName: string,\n  attrValue: IPublicTypeCompositeValue,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n): CodePiece[] {\n  // -- 事件处理函数中 JSExpression 转成 JSFunction 来处理，避免当 JSExpression 处理的时候多包一层 eval 而导致 Rax 转码成小程序的时候出问题\n  const valueExpr = generateCompositeType(\n    isJSExpression(attrValue) ? { type: 'JSFunction', value: attrValue.value } : attrValue,\n    scope,\n    {\n      handlers: config?.handlers,\n    },\n  );\n\n  // 查询当前作用域下的变量\n  const currentScopeVariables = scope.bindings?.getAllBindings() || [];\n  if (currentScopeVariables.length <= 0) {\n    return [\n      {\n        type: PIECE_TYPE.ATTR,\n        name: attrName,\n        value: valueExpr,\n      },\n    ];\n  }\n\n  // 提取出所有的未定义的全局变量\n  const undeclaredVariablesInValueExpr = parseExpressionGetGlobalVariables(valueExpr);\n  const referencedLocalVariables = _.intersection(\n    undeclaredVariablesInValueExpr,\n    currentScopeVariables,\n  );\n  if (referencedLocalVariables.length <= 0) {\n    return [\n      {\n        type: PIECE_TYPE.ATTR,\n        name: attrName,\n        value: valueExpr,\n      },\n    ];\n  }\n\n  const wrappedAttrValueExpr = [\n    '(...__$$args) => {',\n    '  if (__$$isMiniApp) {',\n    '    const __$$event = __$$args[0];',\n    ...referencedLocalVariables.map(\n      (localVar) => `const ${localVar} = __$$event.target.dataset.${localVar};`,\n    ),\n    `    return (${valueExpr}).apply(this, __$$args);`,\n    '  } else {',\n    `    return (${valueExpr}).apply(this, __$$args);`,\n    '  }',\n    '}',\n  ].join('\\n');\n\n  return [\n    ...referencedLocalVariables.map((localVar) => ({\n      type: PIECE_TYPE.ATTR,\n      name: `data-${changeCase.snake(localVar)}`,\n      value: localVar,\n    })),\n    {\n      type: PIECE_TYPE.ATTR,\n      name: attrName,\n      value: wrappedAttrValueExpr,\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/const.ts",
    "content": "export const REACT_CHUNK_NAME = {\n  ClassRenderStart: 'ReactComponentClassRenderStart',\n  ClassRenderPre: 'ReactComponentClassRenderPre',\n  ClassRenderEnd: 'ReactComponentClassRenderEnd',\n  ClassRenderJSX: 'ReactComponentClassRenderJSX',\n  ClassDidMountStart: 'ReactComponentClassDidMountStart',\n  ClassDidMountEnd: 'ReactComponentClassDidMountEnd',\n  ClassDidMountContent: 'ReactComponentClassDidMountContent',\n};\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerClass.ts",
    "content": "import changeCase from 'change-case';\nimport {\n  COMMON_CHUNK_NAME,\n  CLASS_DEFINE_CHUNK_NAME,\n  DEFAULT_LINK_AFTER,\n} from '../../../const/generator';\nimport { REACT_CHUNK_NAME } from './const';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { ensureValidClassName } from '../../../utils/validate';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n\n    // 将模块名转换成 PascalCase 的格式，并添加特定后缀，防止命名冲突\n    const componentClassName = ensureValidClassName(\n      `${changeCase.pascalCase(ir.moduleName)}$$${ir.containerType}`,\n    );\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.Start,\n      content: `class ${componentClassName} extends React.Component {`,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n      ],\n    });\n\n    if (ir.containerType === 'Component') {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: FileType.JSX,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: `static displayName = '${ir.moduleName}';`,\n        linkAfter: [\n          CLASS_DEFINE_CHUNK_NAME.Start,\n        ],\n      });\n    }\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.End,\n      content: '}',\n      linkAfter: [\n        ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End],\n        REACT_CHUNK_NAME.ClassRenderEnd,\n        REACT_CHUNK_NAME.ClassDidMountEnd,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart,\n      content: 'constructor(props, context) { super(props); ',\n      linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,\n      content: '}',\n      linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: REACT_CHUNK_NAME.ClassDidMountStart,\n      content: 'componentDidMount() {',\n      linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End]],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: REACT_CHUNK_NAME.ClassDidMountEnd,\n      content: '}',\n      linkAfter: [REACT_CHUNK_NAME.ClassDidMountContent, REACT_CHUNK_NAME.ClassDidMountStart],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: REACT_CHUNK_NAME.ClassRenderStart,\n      content: 'render() {',\n      linkAfter: [\n        ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End],\n        REACT_CHUNK_NAME.ClassDidMountEnd,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: REACT_CHUNK_NAME.ClassRenderEnd,\n      content: '}',\n      linkAfter: [\n        REACT_CHUNK_NAME.ClassRenderStart,\n        REACT_CHUNK_NAME.ClassRenderPre,\n        REACT_CHUNK_NAME.ClassRenderJSX,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.FileExport,\n      content: `export default ${componentClassName};`,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n        CLASS_DEFINE_CHUNK_NAME.End,\n      ],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerInitState.ts",
    "content": "import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';\n\nimport { generateCompositeType } from '../../../utils/compositeType';\nimport { Scope } from '../../../utils/Scope';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\n\nexport interface PluginConfig {\n  fileType?: string;\n  implementType: 'inConstructor' | 'insMember' | 'hooks';\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig & { fileType: string } = {\n    fileType: FileType.JSX,\n    implementType: 'inConstructor',\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    const scope = Scope.createRootScope();\n\n    const state = ir.state || {};\n    const fields = Object.keys(state).map<string>((stateName) => {\n      const value = generateCompositeType(state[stateName], scope);\n      return `${stateName}: ${value},`;\n    });\n\n    if (cfg.implementType === 'inConstructor') {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n        content: `this.state = { ${fields.join('')} };`,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],\n      });\n    } else if (cfg.implementType === 'insMember') {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: `state = { ${fields.join('')} };`,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],\n      });\n    }\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerInjectConstants.ts",
    "content": "import {\n  CLASS_DEFINE_CHUNK_NAME,\n  COMMON_CHUNK_NAME,\n  DEFAULT_LINK_AFTER,\n} from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../types';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: \"import __$$constants from '../../constants';\",\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n      content: `\n        get constants() {\n          return __$$constants || {};\n        }\n        `,\n      linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerInjectContext.ts",
    "content": "import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';\n\nimport { Scope } from '../../../utils/Scope';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { DEFAULT_LINK_AFTER } from '../../../const';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    const scope = Scope.createRootScope();\n\n    const { inStrictMode } = next.contextData;\n    if (!inStrictMode) {\n      // 非严格模式下，上下文就是自己\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: `\n          _context = this;\n        `,\n        linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],\n      });\n    } else {\n      // 严格模式下的上下文只保留协议中规定的那些\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: `\n          _context = this._createContext();\n        `,\n        linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod,\n        content: `\n          _createContext() {\n            const self = this;\n            const context = {\n              get state() { return self.state; },\n              setState(newState, callback) { self.setState(newState, callback); },\n              get dataSourceMap() { return self._dataSourceEngine.dataSourceMap || {}; },\n              async reloadDataSource() { await self._dataSourceEngine.reloadDataSource(); },\n              get utils() { return self.utils; },\n              get page() { return context; },\n              get component() { return context; },\n              get props() { return self.props; },\n              get constants() { return self.constants; },\n              get $() { return self.$ },\n              get $$() { return self.$$ },\n              ...this._methods,\n            };\n  \n            return context;\n          }\n        `,\n        linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod],\n      });\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts",
    "content": "/* eslint-disable @typescript-eslint/indent */\n\nimport {\n  IPublicTypeCompositeValue,\n  IPublicTypeJSExpression,\n  InterpretDataSourceConfig,\n  isJSExpression,\n  isJSFunction,\n} from '@alilc/lowcode-types';\nimport changeCase from 'change-case';\n\nimport {\n  CLASS_DEFINE_CHUNK_NAME,\n  COMMON_CHUNK_NAME,\n  DEFAULT_LINK_AFTER,\n} from '../../../const/generator';\nimport { Scope } from '../../../utils/Scope';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IScope,\n} from '../../../types';\n\nimport { generateCompositeType } from '../../../utils/compositeType';\nimport { parseExpressionConvertThis2Context } from '../../../utils/expressionParser';\nimport { isValidContainerType } from '../../../utils/schema';\nimport { REACT_CHUNK_NAME } from './const';\nimport { isJSExpressionFn } from '../../../utils/common';\n\nexport interface PluginConfig {\n  fileType?: string;\n\n  /**\n   * 数据源配置\n   */\n  datasourceConfig?: {\n\n    /** 数据源引擎的版本 */\n    engineVersion?: string;\n\n    /** 数据源引擎的包名 */\n    enginePackage?: string;\n\n    /** 数据源 handlers 的版本 */\n    handlersVersion?: {\n      [key: string]: string;\n    };\n\n    /** 数据源 handlers 的包名 */\n    handlersPackages?: {\n      [key: string]: string;\n    };\n  };\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg = {\n    ...config,\n    fileType: config?.fileType || FileType.JSX,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const scope = Scope.createRootScope();\n    const dataSourceConfig = isValidContainerType(pre.ir) ? pre.ir.dataSource : null;\n    const dataSourceItems: InterpretDataSourceConfig[] =\n      (dataSourceConfig && dataSourceConfig.list) || [];\n    const dataSourceEngineOptions = { runtimeConfig: true };\n    if (dataSourceItems.length > 0) {\n      const requestHandlersMap: Record<string, IPublicTypeJSExpression> = {};\n\n      dataSourceItems.forEach((ds) => {\n        const dsType = ds.type || 'fetch';\n        if (!(dsType in requestHandlersMap) && dsType !== 'custom') {\n          const handlerFactoryName = `__$$create${changeCase.pascal(dsType)}RequestHandler`;\n\n          requestHandlersMap[dsType] = {\n            type: 'JSExpression',\n            value:\n              handlerFactoryName + (dsType === 'urlParams' ? '(window.location.search)' : '()'),\n          };\n\n          const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`;\n          const handlerPkgName =\n            cfg.datasourceConfig?.handlersPackages?.[dsType] ||\n            `@alilc/lowcode-datasource-${changeCase.kebab(dsType)}-handler`;\n\n          next.chunks.push({\n            type: ChunkType.STRING,\n            fileType: FileType.JSX,\n            name: COMMON_CHUNK_NAME.ExternalDepsImport,\n            content: `\n              import { ${handlerFactoryExportName} as ${handlerFactoryName} } from '${handlerPkgName}';\n            `,\n            linkAfter: [],\n          });\n        }\n      });\n\n      Object.assign(dataSourceEngineOptions, { requestHandlersMap });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: FileType.JSX,\n        name: COMMON_CHUNK_NAME.ExternalDepsImport,\n        content: `\n          import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n        `,\n        linkAfter: [],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: `\n          _dataSourceConfig = this._defineDataSourceConfig();\n          _dataSourceEngine = __$$createDataSourceEngine(\n            this._dataSourceConfig,\n            this,\n            ${generateCompositeType(dataSourceEngineOptions, scope)}\n          );\n\n          get dataSourceMap() {\n            return this._dataSourceEngine.dataSourceMap || {};\n          }\n\n          reloadDataSource = async () => {\n            await this._dataSourceEngine.reloadDataSource();\n          }\n\n          `,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],\n      });\n\n      next.chunks.unshift({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: REACT_CHUNK_NAME.ClassDidMountContent,\n        content: `\n          this._dataSourceEngine.reloadDataSource();\n        `,\n        linkAfter: [REACT_CHUNK_NAME.ClassDidMountStart],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsMethod,\n        content: `\n  _defineDataSourceConfig() {\n    const _this = this;\n    return (${generateCompositeType(\n      {\n        ...dataSourceConfig,\n        list: [\n          ...dataSourceItems.map((item) => ({\n            ...item,\n            isInit: wrapAsFunction(item.isInit, scope),\n            options: wrapAsFunction(item.options, scope),\n          })),\n        ],\n      },\n      scope,\n      {\n        handlers: {\n          function: (jsFunc) => parseExpressionConvertThis2Context(jsFunc.value, '_this'),\n          expression: (jsExpr) => parseExpressionConvertThis2Context(jsExpr.value, '_this'),\n        },\n      },\n    )});\n  }\n        `,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],\n      });\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n\nfunction wrapAsFunction(value: IPublicTypeCompositeValue, scope: IScope): IPublicTypeCompositeValue {\n  if (isJSExpression(value) || isJSFunction(value) || isJSExpressionFn(value)) {\n    return {\n      type: 'JSExpression',\n      value: `function(){ return ((${value.value}))}.bind(this)`,\n    };\n  }\n\n  return {\n    type: 'JSExpression',\n    value: `function(){return((${generateCompositeType(value, scope)}))}.bind(this)`,\n  };\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerInjectI18n.ts",
    "content": "import {\n  CLASS_DEFINE_CHUNK_NAME,\n  COMMON_CHUNK_NAME,\n  DEFAULT_LINK_AFTER,\n} from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../types';\nimport { getSlotRelativePath } from '../../../utils/pathHelper';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: `\n        import * as __$$i18n from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'i18n' })}';\n      `,\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n      content: `\n        __$$i18n._inject2(this);\n      `,\n      linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerInjectUtils.ts",
    "content": "import {\n  CLASS_DEFINE_CHUNK_NAME,\n  COMMON_CHUNK_NAME,\n  DEFAULT_LINK_AFTER,\n} from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { getSlotRelativePath } from '../../../utils/pathHelper';\n\nexport interface PluginConfig {\n  fileType?: string;\n\n  /** prefer using class property to define utils */\n  preferClassProperty?: boolean;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig & { fileType: string } = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    next.contextData.useRefApi = true;\n    const useRef = !!ir.analyzeResult?.isUsingRef;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: `\n        import utils${useRef ? ', { RefsManager }' : ''} from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'utils' })}';\n      `,\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    if (cfg.preferClassProperty) {\n      // mode: class property\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsVar,\n        content: 'utils = utils;',\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],\n      });\n    } else {\n      // mode: assign in constructor\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n        content: 'this.utils = utils;',\n        linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],\n      });\n    }\n\n    if (useRef) {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n        content: 'this._refsManager = new RefsManager();',\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsMethod,\n        content: `\n          $ = (refName) => {\n            return this._refsManager.get(refName);\n          }\n        `,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsMethod,\n        content: `\n          $$ = (refName) => {\n            return this._refsManager.getAll(refName);\n          }\n        `,\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],\n      });\n    } else {\n      // useRef 为 false 的时候是指没有组件在 props 中配置 ref 属性，但这个时候其实也可能有代码访问 this.$/$$ 所以还是加上个空的代码\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsMethod,\n        content: ' $ = () => null; ',\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.InsMethod,\n        content: ' $$ = () => [];        ',\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],\n      });\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerLifeCycle.ts",
    "content": "import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';\nimport { REACT_CHUNK_NAME } from './const';\n\nimport { generateFunction } from '../../../utils/jsExpression';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeChunk,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { isJSFunction, isJSExpression } from '@alilc/lowcode-types';\nimport { isJSExpressionFn } from '../../../utils/common';\n\nexport interface PluginConfig {\n  fileType?: string;\n  exportNameMapping?: Record<string, string>;\n  normalizeNameMapping?: Record<string, string>;\n  exclude?: string[];\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg = {\n    fileType: FileType.JSX,\n    exportNameMapping: {},\n    normalizeNameMapping: {},\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n\n    if (ir.lifeCycles) {\n      const { lifeCycles } = ir;\n      const chunks = Object.keys(lifeCycles).map<ICodeChunk | null>((lifeCycleName) => {\n        // 过滤掉非法数据（有些场景下会误传入空字符串或 null)\n        if (\n          !isJSFunction(lifeCycles[lifeCycleName]) &&\n          !isJSExpressionFn(lifeCycles[lifeCycleName]) &&\n          !isJSExpression(lifeCycles[lifeCycleName])\n        ) {\n          return null;\n        }\n\n        let normalizeName;\n        // constructor会取到对象的构造函数\n        if (lifeCycleName === 'constructor') {\n          normalizeName = lifeCycleName;\n        } else {\n          normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName;\n        }\n\n        if (cfg?.exclude?.includes(normalizeName)) {\n          return null;\n        }\n\n        const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName;\n        if (normalizeName === 'constructor') {\n          return {\n            type: ChunkType.STRING,\n            fileType: cfg.fileType,\n            name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n            content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }),\n            linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]],\n          };\n        }\n\n        if (normalizeName === 'componentDidMount') {\n          return {\n            type: ChunkType.STRING,\n            fileType: cfg.fileType,\n            name: REACT_CHUNK_NAME.ClassDidMountContent,\n            content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }),\n            linkAfter: [REACT_CHUNK_NAME.ClassDidMountStart],\n          };\n        }\n\n        if (normalizeName === 'render') {\n          return {\n            type: ChunkType.STRING,\n            fileType: cfg.fileType,\n            name: REACT_CHUNK_NAME.ClassRenderPre,\n            content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }),\n            linkAfter: [REACT_CHUNK_NAME.ClassRenderStart],\n          };\n        }\n\n        return {\n          type: ChunkType.STRING,\n          fileType: cfg.fileType,\n          name: CLASS_DEFINE_CHUNK_NAME.InsMethod,\n          content: generateFunction(lifeCycles[lifeCycleName], {\n            name: exportName,\n            isMember: true,\n          }),\n          linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],\n        };\n      }).filter((i) => !!i);\n\n      next.chunks.push(...chunks.filter((x): x is ICodeChunk => x !== null));\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/containerMethod.ts",
    "content": "import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';\n\nimport { generateFunction } from '../../../utils/jsExpression';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeChunk,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\nimport { isValidIdentifier } from '../../../utils/validate';\n\nexport interface PluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n    const { inStrictMode } = next.contextData;\n\n    if (!ir.methods) {\n      return next;\n    }\n\n    // 将这些 methods 都定义到 class 上\n    const { methods } = ir;\n    const chunks = Object.keys(methods).map<ICodeChunk>((methodName) => ({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: CLASS_DEFINE_CHUNK_NAME.InsMethod,\n      content: generateFunction(methods[methodName], { name: methodName, isMember: true }),\n      linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],\n    }));\n    next.chunks.push(...chunks);\n\n    // 严格模式下需要将这些方法都挂到上下文中\n    if (inStrictMode) {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: cfg.fileType,\n        name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,\n        content: Object.keys(ir.methods)\n          .map((methodName) =>\n            isValidIdentifier(methodName) ? `.${methodName}` : `[${JSON.stringify(methodName)}]`,\n          )\n          .map((method) => `this._context${method} = this${method};`)\n          .join('\\n'),\n        linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],\n      });\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/jsx.ts",
    "content": "import {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  HandlerSet,\n  ICodeStruct,\n  IContainerInfo,\n  IScope,\n  NodeGeneratorConfig,\n  PIECE_TYPE,\n} from '../../../types';\n\nimport { REACT_CHUNK_NAME } from './const';\nimport { COMMON_CHUNK_NAME } from '../../../const/generator';\n\nimport { createReactNodeGenerator } from '../../../utils/nodeToJSX';\nimport { Scope } from '../../../utils/Scope';\nimport { IPublicTypeJSExpression } from '@alilc/lowcode-types';\nimport { generateExpression } from '../../../utils/jsExpression';\nimport { transformJsExpr } from '../../../core/jsx/handlers/transformJsExpression';\nimport { transformThis2Context } from '../../../core/jsx/handlers/transformThis2Context';\nimport { generateCompositeType } from '../../../utils/compositeType';\n\nexport interface PluginConfig {\n  fileType?: string;\n  nodeTypeMapping?: Record<string, string>;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg = {\n    fileType: FileType.JSX,\n    // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n    nodeTypeMapping: {} as Record<string, string>,\n    ...config,\n  };\n\n  const { nodeTypeMapping } = cfg;\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const { tolerateEvalErrors = true, evalErrorsHandler = '' } = next.contextData;\n\n    // 这里会将内部的一些子上下文的访问(this.xxx)转换为 __$$context.xxx 的形式\n    // 与 Rax 所不同的是，这里不会将最顶层的 this 转换掉\n    const customHandlers: HandlerSet<string> = {\n      expression(input: IPublicTypeJSExpression, scope: IScope, config) {\n        return transformJsExpr(generateExpression(input, scope), scope, {\n          dontWrapEval: !(config?.tolerateEvalErrors ?? tolerateEvalErrors),\n          dontTransformThis2ContextAtRootScope: true,\n        });\n      },\n      function(input, scope: IScope) {\n        return transformThis2Context(\n          generateCompositeType(\n            {\n              type: 'JSFunction',\n              value: input.value || 'function () {}',\n            },\n            Scope.createRootScope(),\n          ),\n          scope,\n          { ignoreRootScope: true },\n        );\n      },\n    };\n\n    const generatorPlugins: NodeGeneratorConfig = {\n      handlers: customHandlers,\n      tagMapping: (v) => nodeTypeMapping[v] || v,\n      tolerateEvalErrors,\n    };\n\n    if (next.contextData.useRefApi) {\n      generatorPlugins.attrPlugins = [\n        (attrData, scope, pluginCfg, nextFunc) => {\n          if (attrData.attrName === 'ref') {\n            return [\n              {\n                name: attrData.attrName,\n                value: `this._refsManager.linkRef('${attrData.attrValue}')`,\n                type: PIECE_TYPE.ATTR,\n              },\n            ];\n          }\n\n          return nextFunc ? nextFunc(attrData, scope, pluginCfg) : [];\n        },\n      ];\n    }\n\n    const generator = createReactNodeGenerator(generatorPlugins);\n\n    const ir = next.ir as IContainerInfo;\n    const scope: IScope = Scope.createRootScope();\n    const jsxContent = generator(ir, scope);\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: REACT_CHUNK_NAME.ClassRenderJSX,\n      content: `\n        const __$$context = this._context || this;\n        const { state } = __$$context;\n        return ${jsxContent};\n      `,\n      linkAfter: [REACT_CHUNK_NAME.ClassRenderStart, REACT_CHUNK_NAME.ClassRenderPre],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.CustomContent,\n      content: [\n        tolerateEvalErrors &&\n          `\n          function __$$eval(expr) {\n            try {\n              return expr();\n            } catch (error) {\n              ${evalErrorsHandler}\n            }\n          }\n\n          function __$$evalArray(expr) {\n            const res = __$$eval(expr);\n            return Array.isArray(res) ? res : [];\n          }\n      `,\n        `\n        function __$$createChildContext(oldContext, ext) {\n          const childContext = {\n            ...oldContext,\n            ...ext,\n          };\n          childContext.__proto__ = oldContext;\n          return childContext;\n        }\n      `,\n      ]\n        .filter(Boolean)\n        .join('\\n'),\n      linkAfter: [COMMON_CHUNK_NAME.FileExport],\n    });\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/react/reactCommonDeps.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.ExternalDepsImport,\n      content: `\n// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from \\'react\\';`,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/component/style/css.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IContainerInfo,\n} from '../../../types';\n\nexport interface PluginConfig {\n  fileType: string;\n  moduleFileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => {\n  const cfg: PluginConfig = {\n    fileType: FileType.CSS,\n    moduleFileType: FileType.JSX,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IContainerInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.StyleCssContent,\n      content: ir.css,\n      linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.moduleFileType,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: `import './index.${cfg.fileType}';`,\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/constants.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../const/generator';\nimport { generateCompositeType } from '../../utils/compositeType';\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../types';\nimport { Scope } from '../../utils/Scope';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n    const scope = Scope.createRootScope();\n    const constantStr = generateCompositeType(ir.constants || {}, scope);\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileVarDefine,\n      content: `\n        const __$$constants = (${constantStr});\n      `,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileExport,\n      content: `\n        export default __$$constants;\n      `,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n        COMMON_CHUNK_NAME.FileMainContent,\n      ],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/index.ts",
    "content": "import template from './template';\nimport entry from './plugins/entry';\nimport entryHtml from './plugins/entryHtml';\nimport globalStyle from './plugins/globalStyle';\nimport packageJSON from './plugins/packageJSON';\nimport router from './plugins/router';\n\nexport default {\n  template,\n  plugins: {\n    entry,\n    entryHtml,\n    globalStyle,\n    packageJSON,\n    router,\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.ExternalDepsImport,\n      content: `\n        import { createApp } from 'ice';\n      `,\n      linkAfter: [],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: `\n        const appConfig = {\n          app: {\n            rootId: 'app',\n          },\n          router: {\n            type: 'hash',\n          },\n        };\n        createApp(appConfig);\n      `,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n      ],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.HTML,\n      name: COMMON_CHUNK_NAME.HtmlContent,\n      content: `\n        <!DOCTYPE html>\n        <html>\n          <head>\n            <meta charset=\"utf-8\" />\n            <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n            <meta name=\"viewport\" content=\"width=device-width\" />\n            <title>${ir?.meta?.name || 'Ice App'}</title>\n          </head>\n          <body>\n            <div id=\"app\"></div>\n          </body>\n        </html>\n      `,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.SCSS,\n      name: COMMON_CHUNK_NAME.StyleDepsImport,\n      content: `\n        // 引入默认全局样式\n        @import '@alifd/next/reset.scss';\n      `,\n      linkAfter: [],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.SCSS,\n      name: COMMON_CHUNK_NAME.StyleCssContent,\n      content: `\n        body {\n          -webkit-font-smoothing: antialiased;\n        }\n      `,\n      linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.SCSS,\n      name: COMMON_CHUNK_NAME.StyleCssContent,\n      content: ir.css || '',\n      linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts",
    "content": "import { PackageJSON } from '@alilc/lowcode-types';\n\nimport { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\nimport { buildDataSourceDependencies } from '../../../../../utils/dataSource';\n\ninterface IIceJsPackageJSON extends PackageJSON {\n  ideMode: {\n    name: string;\n  };\n  iceworks: {\n    type: string;\n    adapter: string;\n  };\n  originTemplate: string;\n}\n\nexport type IceJsPackageJsonPluginConfig = {\n  /**\n   * 数据源配置\n   */\n  datasourceConfig?: {\n    /** 数据源引擎的版本 */\n    engineVersion?: string;\n    /** 数据源引擎的包名 */\n    enginePackage?: string;\n    /** 数据源 handlers 的版本 */\n    handlersVersion?: {\n      [key: string]: string;\n    };\n    /** 数据源 handlers 的包名 */\n    handlersPackages?: {\n      [key: string]: string;\n    };\n  };\n  /** 包名 */\n  packageName?: string;\n  /** 版本 */\n  packageVersion?: string;\n};\n\nconst pluginFactory: BuilderComponentPluginFactory<IceJsPackageJsonPluginConfig> = (cfg) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    const packageJson: IIceJsPackageJSON = {\n      name: cfg?.packageName || 'icejs-demo-app',\n      version: cfg?.packageVersion || '0.1.5',\n      description: '轻量级模板，使用 JavaScript，仅包含基础的 Layout。',\n      dependencies: {\n        moment: '^2.24.0',\n        react: '^16.4.1',\n        'react-dom': '^16.4.1',\n        'react-router': '^5.2.1',\n        '@alifd/theme-design-pro': '^0.x',\n        'intl-messageformat': '^9.3.6',\n        '@ice/store': '^1.4.3',\n        '@loadable/component': '^5.15.2',\n\n        // 数据源相关的依赖:\n        ...buildDataSourceDependencies(ir, cfg?.datasourceConfig),\n      },\n      devDependencies: {\n        '@ice/spec': '^1.0.0',\n        'build-plugin-fusion': '^0.1.0',\n        'build-plugin-moment-locales': '^0.1.0',\n        eslint: '^6.0.1',\n        'ice.js': '^1.0.0',\n        stylelint: '^13.2.0',\n      },\n      scripts: {\n        start: 'icejs start',\n        build: 'icejs build',\n        lint: 'npm run eslint && npm run stylelint',\n        eslint: 'eslint --cache --ext .js,.jsx ./',\n        stylelint: 'stylelint ./**/*.scss',\n      },\n      ideMode: {\n        name: 'ice-react',\n      },\n      iceworks: {\n        type: 'react',\n        adapter: 'adapter-react-v3',\n      },\n      engines: {\n        node: '>=8.0.0',\n      },\n      repository: {\n        type: 'git',\n        url: 'http://gitlab.xxx.com/msd/leak-scan/tree/master',\n      },\n      private: true,\n      originTemplate: '@alifd/scaffold-lite-js',\n    };\n\n    ir.packages.forEach((packageInfo) => {\n      packageJson.dependencies[packageInfo.package] = packageInfo.version;\n    });\n\n    next.chunks.push({\n      type: ChunkType.JSON,\n      fileType: FileType.JSON,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: packageJson,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/plugins/router.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IRouterInfo,\n} from '../../../../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IRouterInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.InternalDepsImport,\n      content: `\n        import BasicLayout from '@/layouts/BasicLayout';\n      `,\n      linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileVarDefine,\n      content: `\n        const routerConfig = [\n          {\n            path: '/',\n            component: BasicLayout,\n            children: [\n              ${ir.routes\n    .map(\n      (route) => `\n                    {\n                      path: '${route.path}',\n                      component: ${route.componentName},\n                    }\n                  `,\n    )\n    .join(',')}\n            ],\n          },\n        ];\n      `,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileExport,\n      content: `\n        export default routerConfig;\n      `,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileMainContent,\n      ],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'README',\n    'md',\n    `\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n\\`\\`\\`bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n\\`\\`\\`\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n\\`\\`\\`md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n\\`\\`\\`\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    [],\n    {\n      name: 'abc',\n      ext: 'json',\n      content: `\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    `,\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    [],\n    {\n      name: 'build',\n      ext: 'json',\n      content: `\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      `,\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.editorconfig',\n    '',\n    `\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.eslintignore',\n    '',\n    `\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.eslintrc',\n    'js',\n    `\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.gitignore',\n    '',\n    `\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'jsconfig',\n    'json',\n    `\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.prettierignore',\n    '',\n    `\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.prettierrc',\n    'js',\n    `\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'module.scss',\n    `\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'module.scss',\n    `\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'PageNav'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/menuConfig.js.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'menuConfig',\n    'js',\n    `\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/stylelintignore.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.stylelintignore',\n    '',\n    `\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/stylelintrc.js.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.stylelintrc',\n    'js',\n    `\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/files/tsconfig.json.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'tsconfig',\n    'json',\n    `\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/index.ts",
    "content": "import { ResultDir } from '@alilc/lowcode-types';\nimport { IProjectTemplate } from '../../../../../types';\nimport { generateStaticFiles } from './static-files';\n\nconst icejsTemplate: IProjectTemplate = {\n  slots: {\n    components: {\n      path: ['src', 'components'],\n    },\n    pages: {\n      path: ['src', 'pages'],\n    },\n    router: {\n      path: ['src'],\n      fileName: 'routes',\n    },\n    entry: {\n      path: ['src'],\n      fileName: 'app',\n    },\n    constants: {\n      path: ['src'],\n      fileName: 'constants',\n    },\n    utils: {\n      path: ['src'],\n      fileName: 'utils',\n    },\n    i18n: {\n      path: ['src'],\n      fileName: 'i18n',\n    },\n    globalStyle: {\n      path: ['src'],\n      fileName: 'global',\n    },\n    htmlEntry: {\n      path: ['public'],\n      fileName: 'index',\n    },\n    packageJSON: {\n      path: [],\n      fileName: 'package',\n    },\n  },\n\n  generateTemplate(): ResultDir {\n    return generateStaticFiles();\n  },\n};\n\nexport default icejsTemplate;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs/template/static-files.ts",
    "content": "import { ResultDir } from '@alilc/lowcode-types';\n\nimport { createResultDir } from '../../../../../utils/resultHelper';\nimport { runFileGenerator } from '../../../../../utils/templateHelper';\n\nimport file12 from './files/abc.json';\nimport file11 from './files/build.json';\nimport file10 from './files/editorconfig';\nimport file9 from './files/eslintignore';\nimport file8 from './files/eslintrc.js';\nimport file7 from './files/gitignore';\nimport file6 from './files/jsconfig.json';\nimport file5 from './files/prettierignore';\nimport file4 from './files/prettierrc.js';\nimport file13 from './files/README.md';\nimport file16 from './files/src/layouts/BasicLayout/components/Footer/index.jsx';\nimport file17 from './files/src/layouts/BasicLayout/components/Footer/index.style';\nimport file18 from './files/src/layouts/BasicLayout/components/Logo/index.jsx';\nimport file19 from './files/src/layouts/BasicLayout/components/Logo/index.style';\nimport file20 from './files/src/layouts/BasicLayout/components/PageNav/index.jsx';\nimport file14 from './files/src/layouts/BasicLayout/index.jsx';\nimport file15 from './files/src/layouts/BasicLayout/menuConfig.js';\nimport file3 from './files/stylelintignore';\nimport file2 from './files/stylelintrc.js';\nimport file1 from './files/tsconfig.json';\n\nexport function generateStaticFiles(root = createResultDir('.')): ResultDir {\n  runFileGenerator(root, file1);\n  runFileGenerator(root, file2);\n  runFileGenerator(root, file3);\n  runFileGenerator(root, file4);\n  runFileGenerator(root, file5);\n  runFileGenerator(root, file6);\n  runFileGenerator(root, file7);\n  runFileGenerator(root, file8);\n  runFileGenerator(root, file9);\n  runFileGenerator(root, file10);\n  runFileGenerator(root, file11);\n  runFileGenerator(root, file12);\n  runFileGenerator(root, file13);\n  runFileGenerator(root, file14);\n  runFileGenerator(root, file15);\n  runFileGenerator(root, file16);\n  runFileGenerator(root, file17);\n  runFileGenerator(root, file18);\n  runFileGenerator(root, file19);\n  runFileGenerator(root, file20);\n\n  return root;\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/index.ts",
    "content": "import template from './template';\nimport globalStyle from './plugins/globalStyle';\nimport packageJSON from './plugins/packageJSON';\nimport layout from './plugins/layout';\nimport appConfig from './plugins/appConfig';\nimport buildConfig from './plugins/buildConfig';\n\nexport default {\n  template,\n  plugins: {\n    appConfig,\n    buildConfig,\n    globalStyle,\n    packageJSON,\n    layout,\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/plugins/appConfig.ts",
    "content": "import {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../../../types';\nimport { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nexport interface AppConfigPluginConfig {\n\n}\n\nfunction getContent() {\n  return `import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));`;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<AppConfigPluginConfig> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.TS,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: getContent(),\n      linkAfter: [],\n    });\n\n    return next;\n  };\n\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts",
    "content": "import {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../../../types';\nimport { COMMON_CHUNK_NAME } from '../../../../../const/generator';\nimport { format } from '../../../../../utils/format';\nimport { getThemeInfo } from '../../../../../utils/theme';\n\nexport interface BuildConfigPluginConfig {\n\n  /** 包名 */\n  themePackage?: string;\n}\n\nfunction getContent(cfg?: BuildConfigPluginConfig, routesContent?: string) {\n  return `\nimport { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        }\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = \\`\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          \\`;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n  ${routesContent}\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion(${cfg?.themePackage ? `{\n      importStyle: 'sass',\n      themePackage: '${getThemeInfo(cfg.themePackage).name}',\n    }` : `{\n      importStyle: 'sass',\n    }`}),\n    locales(),\n    plugin(),\n  ]\n}));\n  `;\n}\n\nfunction getRoutesContent(navData: any, needShell = true) {\n  const routes = [\n    'routes: {',\n    '  defineRoutes: route => {',\n  ];\n  function _getRoutes(nav: any, _routes: string[] = []) {\n    const { slug, children } = nav;\n    if (children && children.length > 0) {\n      children.forEach((_nav: any) => _getRoutes(_nav, _routes));\n    } else if (slug) {\n      _routes.push(`route('/${slug}', '${slug}/index.jsx');`);\n    }\n  }\n  if (needShell) {\n    routes.push(\"    route('/', 'layout.jsx', () => {\");\n  }\n  navData?.forEach((nav: any) => {\n    _getRoutes(nav, routes);\n  });\n  if (needShell) {\n    routes.push('    });');\n  }\n  routes.push('  }'); // end of defineRoutes\n  routes.push('  },'); // end of routes\n  return routes.join('\\n');\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<BuildConfigPluginConfig> = (cfg?) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const { navConfig } = next.contextData;\n    const routesContent = navConfig?.data ? getRoutesContent(navConfig.data, true) : '';\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.MTS,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: format(getContent(cfg, routesContent)),\n      linkAfter: [],\n    });\n\n    return next;\n  };\n\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/plugins/globalStyle.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.SCSS,\n      name: COMMON_CHUNK_NAME.StyleDepsImport,\n      content: `\n        // 引入默认全局样式\n        @import '@alifd/next/reset.scss';\n      `,\n      linkAfter: [],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.SCSS,\n      name: COMMON_CHUNK_NAME.StyleCssContent,\n      content: `\n        body {\n          -webkit-font-smoothing: antialiased;\n        }\n      `,\n      linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.SCSS,\n      name: COMMON_CHUNK_NAME.StyleCssContent,\n      content: ir.css || '',\n      linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/plugins/layout.ts",
    "content": "import {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../../../types';\nimport { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: `\n      import { Outlet } from 'ice';\n      import BasicLayout from '@/layouts/BasicLayout';\n\n      export default function Layout() {\n        return (\n          <BasicLayout>\n            <Outlet />\n          </BasicLayout>\n        );;\n      }\n      `,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts",
    "content": "import { PackageJSON } from '@alilc/lowcode-types';\n\nimport { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\nimport { buildDataSourceDependencies } from '../../../../../utils/dataSource';\n\ninterface IIceJs3PackageJSON extends PackageJSON {\n  originTemplate: string;\n}\n\nexport type IceJs3PackageJsonPluginConfig = {\n\n  /**\n   * 数据源配置\n   */\n  datasourceConfig?: {\n\n    /** 数据源引擎的版本 */\n    engineVersion?: string;\n\n    /** 数据源引擎的包名 */\n    enginePackage?: string;\n\n    /** 数据源 handlers 的版本 */\n    handlersVersion?: {\n      [key: string]: string;\n    };\n\n    /** 数据源 handlers 的包名 */\n    handlersPackages?: {\n      [key: string]: string;\n    };\n  };\n\n  /** 包名 */\n  packageName?: string;\n\n  /** 版本 */\n  packageVersion?: string;\n};\n\nconst pluginFactory: BuilderComponentPluginFactory<IceJs3PackageJsonPluginConfig> = (cfg) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    const packageJson: IIceJs3PackageJSON = {\n      name: cfg?.packageName || 'icejs3-demo-app',\n      version: cfg?.packageVersion || '0.1.5',\n      description: 'icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。',\n      dependencies: {\n        moment: '^2.24.0',\n        react: '^18.2.0',\n        'react-dom': '^18.2.0',\n        'react-router': '^6.9.0',\n        'react-router-dom': '^6.9.0',\n        'intl-messageformat': '^9.3.6',\n        '@alifd/next': '1.26.15',\n        '@ice/runtime': '~1.1.0',\n        // 数据源相关的依赖:\n        ...buildDataSourceDependencies(ir, cfg?.datasourceConfig),\n      },\n      devDependencies: {\n        '@ice/app': '~3.1.0',\n        '@types/react': '^18.0.0',\n        '@types/react-dom': '^18.0.0',\n        '@types/node': '^18.11.17',\n        '@ice/plugin-fusion': '^1.0.1',\n        '@ice/plugin-moment-locales': '^1.0.0',\n        eslint: '^6.0.1',\n        stylelint: '^13.2.0',\n      },\n      scripts: {\n        start: 'ice start',\n        build: 'ice build',\n        lint: 'npm run eslint && npm run stylelint',\n        eslint: 'eslint --cache --ext .js,.jsx ./',\n        stylelint: 'stylelint ./**/*.scss',\n      },\n      engines: {\n        node: '>=14.0.0',\n      },\n      repository: {\n        type: 'git',\n        url: 'http://gitlab.xxx.com/msd/leak-scan/tree/master',\n      },\n      private: true,\n      originTemplate: '@alifd/scaffold-lite-js',\n    };\n\n    ir.packages.forEach((packageInfo) => {\n      packageJson.dependencies[packageInfo.package] = packageInfo.version;\n    });\n\n    next.chunks.push({\n      type: ChunkType.JSON,\n      fileType: FileType.JSON,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: packageJson,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/README.md.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'README',\n    'md',\n    'This project is generated by lowcode-code-generator & lowcode-solution-icejs3.',\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/browserslistrc.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.browserslistrc',\n    '',\n    `defaults\nios_saf 9\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\n/* eslint-disable max-len */\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'document',\n    'tsx',\n    `import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}`,\n  );\n\n  return [['src'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/gitignore.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    '.gitignore',\n    '',\n    `\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'module.scss',\n    `\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'module.scss',\n    `\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout', 'components', 'PageNav'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/index.jsx.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'index',\n    'jsx',\n    `\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/menuConfig.js.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'menuConfig',\n    'js',\n    `\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    `,\n  );\n\n  return [['src', 'layouts', 'BasicLayout'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/tsconfig.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'tsconfig',\n    'json',\n    `\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"ESNext\",\n    \"target\": \"ESNext\",\n    \"lib\": [\"DOM\", \"ESNext\", \"DOM.Iterable\"],\n    \"jsx\": \"react-jsx\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice\"]\n    }\n  },\n  \"include\": [\"src\", \".ice\"],\n  \"exclude\": [\"build\"]\n}\n    `,\n  );\n\n  return [[], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/files/typings.ts",
    "content": "import { ResultFile } from '@alilc/lowcode-types';\nimport { createResultFile } from '../../../../../../utils/resultHelper';\n\nexport default function getFile(): [string[], ResultFile] {\n  const file = createResultFile(\n    'typings.d',\n    'ts',\n    `/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    `,\n  );\n\n  return [['src'], file];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/index.ts",
    "content": "import { IProjectTemplate } from '../../../../../types';\nimport { generateStaticFiles } from './static-files';\n\nconst icejs3Template: IProjectTemplate = {\n  slots: {\n    components: {\n      path: ['src', 'components'],\n      fileName: 'index',\n    },\n    pages: {\n      path: ['src', 'pages'],\n      fileName: 'index',\n    },\n    entry: {\n      path: ['src'],\n      fileName: 'app',\n    },\n    constants: {\n      path: ['src'],\n      fileName: 'constants',\n    },\n    utils: {\n      path: ['src'],\n      fileName: 'utils',\n    },\n    i18n: {\n      path: ['src'],\n      fileName: 'i18n',\n    },\n    globalStyle: {\n      path: ['src'],\n      fileName: 'global',\n    },\n    packageJSON: {\n      path: [],\n      fileName: 'package',\n    },\n    appConfig: {\n      path: ['src'],\n      fileName: 'app',\n    },\n    buildConfig: {\n      path: [],\n      fileName: 'ice.config',\n    },\n    layout: {\n      path: ['src', 'pages'],\n      fileName: 'layout',\n    },\n  },\n\n  generateTemplate() {\n    return generateStaticFiles();\n  },\n};\n\nexport default icejs3Template;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/icejs3/template/static-files.ts",
    "content": "import { ResultDir } from '@alilc/lowcode-types';\nimport { createResultDir } from '../../../../../utils/resultHelper';\nimport { runFileGenerator } from '../../../../../utils/templateHelper';\n\nimport file1 from './files/gitignore';\nimport file2 from './files/README.md';\nimport file3 from './files/browserslistrc';\nimport file4 from './files/typings';\nimport file5 from './files/document';\nimport file6 from './files/src/layouts/BasicLayout/components/Footer/index.jsx';\nimport file7 from './files/src/layouts/BasicLayout/components/Footer/index.style';\nimport file8 from './files/src/layouts/BasicLayout/components/Logo/index.jsx';\nimport file9 from './files/src/layouts/BasicLayout/components/Logo/index.style';\nimport file10 from './files/src/layouts/BasicLayout/components/PageNav/index.jsx';\nimport file11 from './files/src/layouts/BasicLayout/index.jsx';\nimport file12 from './files/src/layouts/BasicLayout/menuConfig.js';\n\nexport function generateStaticFiles(root = createResultDir('.')): ResultDir {\n  runFileGenerator(root, file1);\n  runFileGenerator(root, file2);\n  runFileGenerator(root, file3);\n  runFileGenerator(root, file4);\n  runFileGenerator(root, file5);\n  runFileGenerator(root, file6);\n  runFileGenerator(root, file7);\n  runFileGenerator(root, file8);\n  runFileGenerator(root, file9);\n  runFileGenerator(root, file10);\n  runFileGenerator(root, file11);\n  runFileGenerator(root, file12);\n\n  return root;\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/index.ts",
    "content": "import template from './template';\nimport entry from './plugins/entry';\nimport appConfig from './plugins/appConfig';\nimport buildConfig from './plugins/buildConfig';\nimport entryDocument from './plugins/entryDocument';\nimport globalStyle from './plugins/globalStyle';\nimport packageJSON from './plugins/packageJSON';\n\nexport default {\n  template,\n  plugins: {\n    appConfig,\n    buildConfig,\n    entry,\n    entryDocument,\n    globalStyle,\n    packageJSON,\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/plugins/appConfig.ts",
    "content": "import changeCase from 'change-case';\nimport { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IParseResult,\n} from '../../../../../types';\nimport { ensureValidClassName } from '../../../../../utils/validate';\nimport { RaxFrameworkOptions } from '../types/RaxFrameworkOptions';\n\nconst pluginFactory: BuilderComponentPluginFactory<RaxFrameworkOptions> = (cfg) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IParseResult;\n\n    const routes = ir.globalRouter?.routes?.map((route) => ({\n      path: route.path,\n      source: `pages/${ensureValidClassName(changeCase.pascalCase(route.fileName))}/index`,\n    })) || [{ path: '/', source: 'pages/Home/index' }];\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSON,\n      name: COMMON_CHUNK_NAME.CustomContent,\n      content: `\n{\n  \"routes\": ${JSON.stringify(routes, null, 2)},\n  \"window\": {\n    \"title\": ${JSON.stringify(\n      cfg?.title || ir.project?.meta?.title || ir.project?.meta?.name || '',\n    )}\n  }\n}\n      `,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/plugins/buildConfig.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IParseResult,\n} from '../../../../../types';\nimport type { RaxFrameworkOptions } from '../types/RaxFrameworkOptions';\n\nconst pluginFactory: BuilderComponentPluginFactory<RaxFrameworkOptions> = (cfg) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IParseResult;\n\n    const miniAppBuildType =\n      cfg?.buildConfig?.miniAppBuildType || ir.project?.config?.miniAppBuildType;\n    const targets = cfg?.targets || ['web'];\n\n    const buildCfg = {\n      inlineStyle: false,\n      plugins: [],\n      targets,\n      miniapp: miniAppBuildType\n        ? {\n            buildType: miniAppBuildType,\n            ...cfg?.buildConfig?.miniapp,\n          }\n        : cfg?.buildConfig?.miniapp,\n      ...cfg?.buildConfig,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSON,\n      name: COMMON_CHUNK_NAME.CustomContent,\n      content: `${JSON.stringify(buildCfg, null, 2)}\\n`,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/plugins/entry.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n} from '../../../../../types';\nimport { RaxFrameworkOptions } from '../types/RaxFrameworkOptions';\n\nconst pluginFactory: BuilderComponentPluginFactory<RaxFrameworkOptions> = (cfg) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.ExternalDepsImport,\n      content: `\nimport { runApp } from 'rax-app';\n\nimport './global.${cfg?.globalStylesFileType || 'css'}';\n`,\n      linkAfter: [],\n    });\n\n    // 应用配置\n    const appConfig = cfg?.appConfig || {};\n    Object.assign(appConfig, {\n      // 路由配置\n      router: {\n        mode: 'hash',\n        ...appConfig.router,\n      },\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: `\nrunApp(${JSON.stringify(appConfig, null, 2)});\n`,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n      ],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/plugins/entryDocument.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\nimport { RaxFrameworkOptions } from '../types/RaxFrameworkOptions';\n\n/**\n * 这种方式已经不推荐使用了\n */\nconst pluginFactory: BuilderComponentPluginFactory<RaxFrameworkOptions> = (cfg) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JSX,\n      name: COMMON_CHUNK_NAME.CustomContent,\n      content: `\nimport { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>${cfg?.title || ir?.meta?.name || 'Rax App'}</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n`,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/plugins/globalStyle.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\n\nexport interface GlobalStylePluginConfig {\n  fileType: string;\n}\n\nconst pluginFactory: BuilderComponentPluginFactory<GlobalStylePluginConfig> = (\n  config?: Partial<GlobalStylePluginConfig>,\n) => {\n  const cfg: GlobalStylePluginConfig = {\n    fileType: FileType.SCSS,\n    ...config,\n  };\n\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.StyleDepsImport,\n      content: '',\n      linkAfter: [],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.StyleCssContent,\n      content: `\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n`,\n      linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: cfg.fileType,\n      name: COMMON_CHUNK_NAME.StyleCssContent,\n      content: ir.css || '',\n      linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/plugins/packageJSON.ts",
    "content": "import { IPublicTypeNpmInfo, PackageJSON } from '@alilc/lowcode-types';\nimport { COMMON_CHUNK_NAME } from '../../../../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../../../../types';\nimport { isNpmInfo } from '../../../../../utils/schema';\nimport { getErrorMessage } from '../../../../../utils/errors';\nimport { calcCompatibleVersion } from '../../../../../utils/version';\nimport { RaxFrameworkOptions } from '../types/RaxFrameworkOptions';\nimport { buildDataSourceDependencies } from '../../../../../utils/dataSource';\n\nconst pluginFactory: BuilderComponentPluginFactory<RaxFrameworkOptions> = (cfg) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n\n    const npmDeps = getNpmDependencies(ir);\n\n    const packageJson: PackageJSON = {\n      name: cfg?.packageName || 'rax-demo-app',\n      private: true,\n      version: cfg?.packageVersion || '1.0.0',\n      scripts: {\n        start: 'rax-app start',\n        build: 'rax-app build',\n        eslint: 'eslint --ext .js,.jsx ./',\n        stylelint: 'stylelint \"**/*.{css,scss,less}\"',\n        prettier: 'prettier **/* --write',\n        lint: 'npm run eslint && npm run stylelint',\n      },\n      dependencies: {\n        // 数据源相关的依赖:\n        ...buildDataSourceDependencies(ir, cfg?.datasourceConfig),\n\n        // 环境判断\n        'universal-env': '^3.2.0',\n\n        // 国际化相关依赖:\n        'intl-messageformat': '^9.3.6',\n\n        // 基础库\n        rax: '^1.1.0',\n        'rax-document': '^0.1.6',\n\n        // 其他组件库\n        ...npmDeps.reduce<Record<string, string>>(\n          (acc, npm) => ({\n            ...acc,\n            [npm.package]: npm.version || '*',\n          }),\n          {},\n        ),\n      },\n      devDependencies: {\n        '@iceworks/spec': '^1.0.0',\n        'rax-app': '^3.0.0',\n        eslint: '^6.8.0',\n        prettier: '^2.1.2',\n        stylelint: '^13.7.2',\n      },\n    };\n\n    next.chunks.push({\n      type: ChunkType.JSON,\n      fileType: FileType.JSON,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: packageJson,\n      linkAfter: [],\n    });\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n\nfunction getNpmDependencies(project: IProjectInfo): IPublicTypeNpmInfo[] {\n  const npmDeps: IPublicTypeNpmInfo[] = [];\n  const npmNameToPkgMap = new Map<string, IPublicTypeNpmInfo>();\n\n  const allDeps = project.packages;\n\n  allDeps.forEach((dep) => {\n    if (!isNpmInfo(dep)) {\n      return;\n    }\n\n    const existing = npmNameToPkgMap.get(dep.package);\n    if (!existing) {\n      npmNameToPkgMap.set(dep.package, dep);\n      npmDeps.push(dep);\n      return;\n    }\n\n    if (existing.version !== dep.version) {\n      try {\n        npmNameToPkgMap.set(dep.package, {\n          ...existing,\n          version: calcCompatibleVersion(existing.version, dep.version),\n        });\n      } catch (e) {\n        throw new Error(\n          `Cannot find compatible version for ${dep.package}. Detail: ${getErrorMessage(e)}`,\n        );\n      }\n    }\n  });\n\n  return npmDeps;\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/.eslintignore.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/.eslintignore.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: '.eslintignore',\n      ext: '',\n      content: 'node_modules/\\nlib/\\ndist/\\nbuild/\\ncoverage/\\ndemo/\\nes/\\n.rax/\\n',\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/.eslintrc.js.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/.eslintrc.js.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: '.eslintrc',\n      ext: 'js',\n      content:\n        \"const { getESLintConfig } = require('@iceworks/spec');\\n\\n// https://www.npmjs.com/package/@iceworks/spec\\nmodule.exports = {\\n  ...getESLintConfig('rax'),\\n  rules: {\\n    'max-len': ['error', { code: 200 }],\\n    'function-paren-newline': 'off',\\n    '@typescript-eslint/indent': 'off',\\n    'prettier/prettier': 'off',\\n    'no-empty': 'off',\\n    'no-unused-vars': 'off',\\n    '@iceworks/best-practices/recommend-functional-component': 'off',\\n  },\\n};\\n\",\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/.gitignore.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/.gitignore.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: '.gitignore',\n      ext: '',\n      content:\n        '# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\\n\\n*~\\n*.swp\\n*.log\\n\\n.DS_Store\\n.idea/\\n.temp/\\n\\nbuild/\\ndist/\\nlib/\\ncoverage/\\nnode_modules/\\n.rax/\\n\\ntemplate.yml',\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/.prettierignore.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/.prettierignore.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: '.prettierignore',\n      ext: '',\n      content: 'node_modules/\\nlib/\\ndist/\\nbuild/\\ncoverage/\\ndemo/\\nes/\\n.rax/\\n',\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/.prettierrc.js.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/.prettierrc.js.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: '.prettierrc',\n      ext: 'js',\n      content:\n        \"const { getPrettierConfig } = require('@iceworks/spec');\\n\\nmodule.exports = getPrettierConfig('rax');\\n\",\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/.stylelintignore.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/.stylelintignore.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: '.stylelintignore',\n      ext: '',\n      content: 'node_modules/\\nlib/\\ndist/\\nbuild/\\ncoverage/\\ndemo/\\nes/\\n.rax/\\n',\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/.stylelintrc.js.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/.stylelintrc.js.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: '.stylelintrc',\n      ext: 'js',\n      content:\n        \"const { getStylelintConfig } = require('@iceworks/spec');\\n\\nmodule.exports = getStylelintConfig('rax');\\n\",\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/README.md.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/README.md.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: 'README',\n      ext: 'md',\n      content:\n        '# rax-materials-basic-app\\n\\n## Getting Started\\n\\n### `npm run start`\\n\\nRuns the app in development mode.\\n\\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\\n\\nThe page will reload if you make edits.\\n\\n### `npm run build`\\n\\nBuilds the app for production to the `build` folder.\\n',\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/jsconfig.json.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/jsconfig.json.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: 'jsconfig',\n      ext: 'json',\n      content:\n        '{\\n  \"compilerOptions\": {\\n    \"baseUrl\": \".\",\\n    \"jsx\": \"react\",\\n    \"paths\": {\\n      \"@/*\": [\"./src/*\"],\\n      \"rax-app\": [\".rax/index.ts\"]\\n    }\\n  }\\n}\\n',\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/files/tsconfig.json.ts",
    "content": "/* eslint-disable max-len */\n/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\n/* -- instead, you should modify \"static-files/rax/tsconfig.json.template\" and run \"npm run template\" */\nimport { ResultFile } from '@alilc/lowcode-types';\n\nexport default function getFile(): [string[], ResultFile] {\n  return [\n    ['.'],\n    {\n      name: 'tsconfig',\n      ext: 'json',\n      content:\n        '{\\n  \"compileOnSave\": false,\\n  \"buildOnSave\": false,\\n  \"compilerOptions\": {\\n    \"baseUrl\": \".\",\\n    \"outDir\": \"build\",\\n    \"module\": \"esnext\",\\n    \"target\": \"es6\",\\n    \"jsx\": \"preserve\",\\n    \"jsxFactory\": \"createElement\",\\n    \"moduleResolution\": \"node\",\\n    \"allowSyntheticDefaultImports\": true,\\n    \"lib\": [\"es6\", \"dom\"],\\n    \"sourceMap\": true,\\n    \"allowJs\": true,\\n    \"rootDir\": \"./\",\\n    \"forceConsistentCasingInFileNames\": true,\\n    \"noImplicitReturns\": true,\\n    \"noImplicitThis\": true,\\n    \"noImplicitAny\": false,\\n    \"importHelpers\": true,\\n    \"strictNullChecks\": true,\\n    \"suppressImplicitAnyIndexErrors\": true,\\n    \"noUnusedLocals\": true,\\n    \"skipLibCheck\": true,\\n    \"paths\": {\\n      \"@/*\": [\"./src/*\"],\\n      \"rax-app\": [\".rax/index.ts\"]\\n    }\\n  },\\n  \"include\": [\"src\", \".rax\"],\\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\\n}',\n    },\n  ];\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/index.ts",
    "content": "import { ResultDir } from '@alilc/lowcode-types';\nimport { IProjectTemplate } from '../../../../../types';\nimport { generateStaticFiles } from './static-files';\n\nconst raxAppTemplate: IProjectTemplate = {\n  slots: {\n    components: {\n      path: ['src', 'components'],\n    },\n    pages: {\n      path: ['src', 'pages'],\n    },\n    router: {\n      path: ['src'],\n      fileName: 'router',\n    },\n    entry: {\n      path: ['src'],\n      fileName: 'app',\n    },\n    appConfig: {\n      path: ['src'],\n      fileName: 'app',\n    },\n    buildConfig: {\n      path: [],\n      fileName: 'build',\n    },\n    constants: {\n      path: ['src'],\n      fileName: 'constants',\n    },\n    utils: {\n      path: ['src'],\n      fileName: 'utils',\n    },\n    i18n: {\n      path: ['src'],\n      fileName: 'i18n',\n    },\n    globalStyle: {\n      path: ['src'],\n      fileName: 'global',\n    },\n    htmlEntry: {\n      path: ['src', 'document'],\n      fileName: 'index',\n    },\n    packageJSON: {\n      path: [],\n      fileName: 'package',\n    },\n  },\n\n  async generateTemplate(): Promise<ResultDir> {\n    return generateStaticFiles();\n  },\n};\n\nexport default raxAppTemplate;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/template/static-files.ts",
    "content": "/* Note: this file is generated by \"npm run template\", please dont modify this file directly */\nimport { ResultDir } from '@alilc/lowcode-types';\n\nimport { createResultDir } from '../../../../../utils/resultHelper';\nimport { runFileGenerator } from '../../../../../utils/templateHelper';\nimport file0 from './files/.eslintignore';\nimport file1 from './files/.eslintrc.js';\nimport file2 from './files/.gitignore';\nimport file3 from './files/.prettierignore';\nimport file4 from './files/.prettierrc.js';\nimport file5 from './files/.stylelintignore';\nimport file6 from './files/.stylelintrc.js';\nimport file7 from './files/jsconfig.json';\nimport file8 from './files/README.md';\nimport file9 from './files/tsconfig.json';\n\nexport function generateStaticFiles(root = createResultDir('.')): ResultDir {\n  runFileGenerator(root, file0);\n  runFileGenerator(root, file1);\n  runFileGenerator(root, file2);\n  runFileGenerator(root, file3);\n  runFileGenerator(root, file4);\n  runFileGenerator(root, file5);\n  runFileGenerator(root, file6);\n  runFileGenerator(root, file7);\n  runFileGenerator(root, file8);\n  runFileGenerator(root, file9);\n  return root;\n}\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/framework/rax/types/RaxFrameworkOptions.ts",
    "content": "export type RaxFrameworkOptions = {\n  /**\n   * 默认的页面标题\n   */\n  title?: string;\n\n  /**\n   * 目标环境（默认是仅 web 环境）\n   */\n  targets?: Array<'web' | 'miniapp' | string>;\n\n  /**\n   * 小程序引擎选择，默认为运行时引擎。如需启用编译时引擎，则配置为 compile\n   */\n  miniAppBuildType?: MiniAppBuildType;\n\n  /**\n   * 构建配置\n   */\n  buildConfig?: {\n    inlineStyle?: boolean | { forceEnableCSS: boolean };\n    alias?: { [key: string]: string };\n    publicPath?: string;\n    devPublicPath?: string;\n    sourceMap?: boolean | string;\n    externals?: { [key: string]: string };\n    hash?: boolean | string;\n    polyfill?: string | false;\n    minify?: boolean;\n    outputDir?: string;\n    proxy?: { [key: string]: string };\n    devServer?: { [key: string]: unknown };\n    browserslist?: string | { [key: string]: string };\n    compileDependencies?: string[];\n    miniapp?: { [key: string]: unknown };\n    [key: string]: unknown;\n  };\n\n  /**\n   * 数据源配置\n   */\n  datasourceConfig?: {\n    /** 数据源引擎的版本 */\n    engineVersion?: string;\n\n    /** 数据源引擎的包名 */\n    enginePackage?: string;\n\n    /** 数据源 handlers 的版本 */\n    handlersVersion?: {\n      [key: string]: string;\n    };\n\n    /** 数据源 handlers 的包名 */\n    handlersPackages?: {\n      [key: string]: string;\n    };\n  };\n\n  /** 包名 */\n  packageName?: string;\n\n  /** 版本 */\n  packageVersion?: string;\n\n  /** 全局样式文件的类型 */\n  globalStylesFileType?: 'css' | 'scss' | 'less';\n\n  /** 应用配置 */\n  appConfig?: {\n    /** 路由配置 */\n    router?: {\n      type?: 'browser' | 'hash' | string;\n      basename?: string;\n    };\n  };\n\n  // TODO: [p1]支持 MPA 模式？\n};\n\nexport type MiniAppBuildType = 'compile' | 'runtime';\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/i18n.ts",
    "content": "import { COMMON_CHUNK_NAME } from '../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IProjectInfo,\n} from '../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<unknown> = () => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IProjectInfo;\n    const i18nStr = ir.i18n ? JSON.stringify(ir.i18n, null, 2) : '{}';\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileMainContent,\n      content: `\n        const i18nConfig = ${i18nStr};\n\n        let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\n        const getLocale = () => locale;\n\n        const setLocale = (target) => {\n          locale = target;\n        };\n\n        const isEmptyVariables = variables => (\n          Array.isArray(variables) && variables.length === 0\n          || typeof variables === 'object' && (!variables || Object.keys(variables).length === 0)\n        );\n\n        // 按低代码规范里面的要求进行变量替换\n        const format = (msg, variables) => (\n          typeof msg === 'string'\n            ? msg.replace(/\\\\\\$?\\\\{(\\\\w+)\\\\}/g, (match, key) => variables?.[key] ?? '')\n            : msg\n        );\n\n        const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n          const msg = i18nConfig[locale]?.[id] ??  i18nConfig[locale.replace('-', '_')]?.[id] ??  defaultMessage;\n          if (msg == null) {\n            console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n            return fallback === undefined ? \\`\\${id}\\` : fallback;\n          }\n\n          return format(msg, variables);\n        }\n\n        const i18n = (id, params) => {\n          return i18nFormat({ id }, params);\n        };\n\n        // 将国际化的一些方法注入到目标对象&上下文中\n        const _inject2 = (target) => {\n          target.i18n = i18n;\n          target.getLocale = getLocale;\n          target.setLocale = (locale) => {\n            setLocale(locale);\n            target.forceUpdate();\n          };\n          target._i18nText = (t) => {\n            // 优先取直接传过来的语料\n            const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]\n            if (localMsg != null) {\n              return format(localMsg, t.params);\n            }\n\n            // 其次用项目级别的\n            const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n            if (projectMsg != null) {\n              return projectMsg;\n            }\n\n            // 兜底用 use 指定的或默认语言的\n            return format(t[t.use || \"zh-CN\"] ?? t.en_US, t.params);\n          }\n\n          // 注入到上下文中去\n          if (target._context && target._context !== target) {\n            Object.assign(target._context, {\n              i18n,\n              getLocale, setLocale: target.setLocale\n            });\n          }\n        }\n      `,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n      ],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileExport,\n      content: `\n        export {\n          getLocale,\n          setLocale,\n          i18n,\n          i18nFormat,\n          _inject2,\n        };\n      `,\n      linkAfter: [\n        COMMON_CHUNK_NAME.ExternalDepsImport,\n        COMMON_CHUNK_NAME.InternalDepsImport,\n        COMMON_CHUNK_NAME.ImportAliasDefine,\n        COMMON_CHUNK_NAME.FileVarDefine,\n        COMMON_CHUNK_NAME.FileUtilDefine,\n        COMMON_CHUNK_NAME.FileMainContent,\n      ],\n    });\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/plugins/project/utils.ts",
    "content": "import { COMMON_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../const/generator';\n\nimport {\n  BuilderComponentPlugin,\n  BuilderComponentPluginFactory,\n  ChunkType,\n  FileType,\n  ICodeStruct,\n  IUtilInfo,\n} from '../../types';\n\nconst pluginFactory: BuilderComponentPluginFactory<string> = (baseFramework?: string) => {\n  const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {\n    const framework = baseFramework || 'react';\n    const next: ICodeStruct = {\n      ...pre,\n    };\n\n    const ir = next.ir as IUtilInfo;\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.ExternalDepsImport,\n      content: `\n        import { createRef } from '${framework}';\n      `,\n      linkAfter: [],\n    });\n\n    next.chunks.push({\n      type: ChunkType.STRING,\n      fileType: FileType.JS,\n      name: COMMON_CHUNK_NAME.FileUtilDefine,\n      content: `\n        export class RefsManager {\n          constructor() {\n            this.refInsStore = {};\n          }\n\n          clearNullRefs() {\n            Object.keys(this.refInsStore).forEach((refName) => {\n              const filteredInsList = this.refInsStore[refName].filter(insRef => !!insRef.current);\n              if (filteredInsList.length > 0) {\n                this.refInsStore[refName] = filteredInsList;\n              } else {\n                delete this.refInsStore[refName];\n              }\n            });\n          }\n\n          get(refName) {\n            this.clearNullRefs();\n            if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n              return this.refInsStore[refName][0].current;\n            }\n\n            return null;\n          }\n\n          getAll(refName) {\n            this.clearNullRefs();\n            if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n              return this.refInsStore[refName].map(i => i.current);\n            }\n\n            return [];\n          }\n\n          linkRef(refName) {\n            const refIns = createRef();\n            this.refInsStore[refName] = this.refInsStore[refName] || [];\n            this.refInsStore[refName].push(refIns);\n            return refIns;\n          }\n        }\n      `,\n      linkAfter: [...DEFAULT_LINK_AFTER[COMMON_CHUNK_NAME.FileUtilDefine]],\n    });\n\n    if (ir.utils) {\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: FileType.JS,\n        name: COMMON_CHUNK_NAME.FileExport,\n        content: `\n          export default {\n        `,\n        linkAfter: [\n          COMMON_CHUNK_NAME.ExternalDepsImport,\n          COMMON_CHUNK_NAME.InternalDepsImport,\n          COMMON_CHUNK_NAME.ImportAliasDefine,\n          COMMON_CHUNK_NAME.FileVarDefine,\n          COMMON_CHUNK_NAME.FileUtilDefine,\n          COMMON_CHUNK_NAME.FileMainContent,\n        ],\n      });\n\n      ir.utils.forEach((util) => {\n        if (util.type === 'function') {\n          next.chunks.push({\n            type: ChunkType.STRING,\n            fileType: FileType.JS,\n            name: COMMON_CHUNK_NAME.FileVarDefine,\n            content: `\n              const ${util.name} = ${util.content.value};\n            `,\n            linkAfter: [\n              COMMON_CHUNK_NAME.ExternalDepsImport,\n              COMMON_CHUNK_NAME.InternalDepsImport,\n              COMMON_CHUNK_NAME.ImportAliasDefine,\n            ],\n          });\n        }\n\n        next.chunks.push({\n          type: ChunkType.STRING,\n          fileType: FileType.JS,\n          name: COMMON_CHUNK_NAME.FileExport,\n          content: `${util.name},`,\n          linkAfter: [\n            COMMON_CHUNK_NAME.ExternalDepsImport,\n            COMMON_CHUNK_NAME.InternalDepsImport,\n            COMMON_CHUNK_NAME.ImportAliasDefine,\n            COMMON_CHUNK_NAME.FileVarDefine,\n            COMMON_CHUNK_NAME.FileUtilDefine,\n            COMMON_CHUNK_NAME.FileMainContent,\n          ],\n        });\n      });\n\n      next.chunks.push({\n        type: ChunkType.STRING,\n        fileType: FileType.JS,\n        name: COMMON_CHUNK_NAME.FileExport,\n        content: `\n          };\n        `,\n        linkAfter: [\n          COMMON_CHUNK_NAME.ExternalDepsImport,\n          COMMON_CHUNK_NAME.InternalDepsImport,\n          COMMON_CHUNK_NAME.ImportAliasDefine,\n          COMMON_CHUNK_NAME.FileVarDefine,\n          COMMON_CHUNK_NAME.FileUtilDefine,\n          COMMON_CHUNK_NAME.FileMainContent,\n        ],\n      });\n    }\n\n    return next;\n  };\n  return plugin;\n};\n\nexport default pluginFactory;\n"
  },
  {
    "path": "modules/code-generator/src/polyfills/buffer.ts",
    "content": "import { Buffer } from 'buffer';\n\ndeclare const self: any;\n\nif (self && !self.Buffer) {\n  Object.assign(self, {\n    Buffer,\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/src/postprocessor/index.ts",
    "content": "import prettier from './prettier';\n\nexport { prettier };\n"
  },
  {
    "path": "modules/code-generator/src/postprocessor/prettier/index.ts",
    "content": "import prettier from 'prettier';\nimport parserBabel from 'prettier/parser-babel';\nimport parserPostCss from 'prettier/parser-postcss';\nimport parserHtml from 'prettier/parser-html';\n\nimport { PostProcessor, PostProcessorFactory } from '../../types';\n\nconst PARSERS = ['css', 'scss', 'less', 'json', 'html', 'vue'];\n\nexport interface ProcessorConfig {\n  customFileTypeParser: Record<string, string>;\n  plugins?: prettier.Plugin[];\n}\n\nconst factory: PostProcessorFactory<ProcessorConfig> = (config?: ProcessorConfig) => {\n  const cfg: ProcessorConfig = {\n    customFileTypeParser: {},\n    ...config,\n  };\n\n  const codePrettier: PostProcessor = (content: string, fileType: string) => {\n    let parser: prettier.BuiltInParserName | any;\n    if (fileType === 'js' || fileType === 'jsx' || fileType === 'ts' || fileType === 'tsx') {\n      parser = 'babel-ts';\n    } else if (fileType === 'json') {\n      parser = 'json-stringify';\n    } else if (PARSERS.indexOf(fileType) >= 0) {\n      parser = fileType;\n    } else if (cfg.customFileTypeParser[fileType]) {\n      parser = cfg.customFileTypeParser[fileType];\n    } else {\n      return content;\n    }\n\n    return prettier.format(content, {\n      parser,\n      plugins: [parserBabel, parserPostCss, parserHtml, ...(cfg.plugins || [])],\n      singleQuote: true,\n      jsxSingleQuote: false,\n    });\n  };\n\n  return codePrettier;\n};\n\nexport default factory;\n"
  },
  {
    "path": "modules/code-generator/src/publisher/disk/index.ts",
    "content": "import * as defaultFs from 'fs';\n\nimport { ResultDir } from '@alilc/lowcode-types';\nimport { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types';\nimport { getErrorMessage } from '../../utils/errors';\nimport { writeFolder, IFileSystem } from './utils';\n\nexport interface IDiskFactoryParams extends IPublisherFactoryParams {\n  outputPath?: string;\n  projectSlug?: string;\n  createProjectFolder?: boolean;\n  fs?: IFileSystem;\n}\n\nexport interface IDiskPublisher extends IPublisher<IDiskFactoryParams, string> {\n  getOutputPath: () => string;\n  setOutputPath: (path: string) => void;\n}\n\nexport const createDiskPublisher: PublisherFactory<IDiskFactoryParams, IDiskPublisher> = (\n  params: IDiskFactoryParams = {},\n): IDiskPublisher => {\n  let { project, outputPath = './' } = params;\n  const { fs = defaultFs } = params;\n\n  const getProject = (): ResultDir => {\n    if (!project) {\n      throw new PublisherError('MissingProject');\n    }\n    return project;\n  };\n  const setProject = (projectToSet: ResultDir): void => {\n    project = projectToSet;\n  };\n\n  const getOutputPath = (): string => {\n    return outputPath;\n  };\n  const setOutputPath = (path: string): void => {\n    outputPath = path;\n  };\n\n  const publish = async (options: IDiskFactoryParams = {}) => {\n    const projectToPublish = options.project || project;\n    if (!projectToPublish) {\n      throw new PublisherError('MissingProject');\n    }\n\n    const projectOutputPath = options.outputPath || outputPath;\n    const overrideProjectSlug = options.projectSlug || params.projectSlug;\n    const createProjectFolder = options.createProjectFolder ?? params.createProjectFolder;\n\n    if (overrideProjectSlug) {\n      projectToPublish.name = overrideProjectSlug;\n    }\n\n    try {\n      await writeFolder(projectToPublish, projectOutputPath, createProjectFolder, fs);\n      return { success: true, payload: projectOutputPath };\n    } catch (error) {\n      throw new PublisherError(getErrorMessage(error) || 'UnknownError');\n    }\n  };\n\n  return {\n    publish,\n    getProject,\n    setProject,\n    getOutputPath,\n    setOutputPath,\n  };\n};\n"
  },
  {
    "path": "modules/code-generator/src/publisher/disk/utils.ts",
    "content": "import * as systemFs from 'fs';\nimport { join } from 'path';\nimport { ResultDir, ResultFile } from '@alilc/lowcode-types';\n\nexport interface IFileSystem {\n  existsSync: typeof systemFs.existsSync;\n  mkdir: typeof systemFs.mkdir;\n  writeFile: typeof systemFs.writeFile;\n}\n\nexport const writeFolder = async (\n  folder: ResultDir,\n  currentPath: string,\n  createProjectFolder = true,\n  fs: IFileSystem = systemFs,\n): Promise<void> => {\n  const { name, files, dirs } = folder;\n\n  const folderPath = createProjectFolder ? join(currentPath, name) : currentPath;\n\n  if (!fs.existsSync(folderPath)) {\n    await createDirectory(folderPath, fs);\n  }\n\n  const promises = [\n    writeFilesToFolder(folderPath, files, fs),\n    writeSubFoldersToFolder(folderPath, dirs, fs),\n  ];\n\n  await Promise.all(promises);\n};\n\nconst writeFilesToFolder = async (\n  folderPath: string,\n  files: ResultFile[],\n  fs: IFileSystem,\n): Promise<void> => {\n  const promises = files.map((file) => {\n    const fileName = file.ext ? `${file.name}.${file.ext}` : file.name;\n    const filePath = join(folderPath, fileName);\n    return writeContentToFile(filePath, file.content, 'utf8', fs);\n  });\n\n  await Promise.all(promises);\n};\n\nconst writeSubFoldersToFolder = async (\n  folderPath: string,\n  subFolders: ResultDir[],\n  fs: IFileSystem,\n): Promise<void> => {\n  const promises = subFolders.map((subFolder) => {\n    return writeFolder(subFolder, folderPath, true, fs);\n  });\n\n  await Promise.all(promises);\n};\n\nconst createDirectory = (pathToDir: string, fs: IFileSystem): Promise<void> => {\n  return new Promise((resolve, reject) => {\n    fs.mkdir(pathToDir, { recursive: true }, (err) => {\n      err ? reject(err) : resolve();\n    });\n  });\n};\n\nconst writeContentToFile = (\n  filePath: string,\n  fileContent: string,\n  encoding = 'utf8',\n  fs: IFileSystem,\n): Promise<void> => {\n  return new Promise((resolve, reject) => {\n    fs.writeFile(filePath, fileContent, { encoding: encoding as BufferEncoding }, (err) => {\n      err ? reject(err) : resolve();\n    });\n  });\n};\n"
  },
  {
    "path": "modules/code-generator/src/publisher/zip/index.ts",
    "content": "import { ResultDir } from '@alilc/lowcode-types';\nimport { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types';\nimport { getErrorMessage } from '../../utils/errors';\nimport { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils';\nimport { saveAs } from 'file-saver';\n\nexport type ZipBuffer = Buffer | Blob;\n\ndeclare type ZipPublisherResponse = string | ZipBuffer;\n\nexport interface ZipFactoryParams extends IPublisherFactoryParams {\n  outputPath?: string;\n  projectSlug?: string;\n}\n\nexport interface ZipPublisher extends IPublisher<ZipFactoryParams, ZipPublisherResponse> {\n  getOutputPath: () => string | undefined;\n  setOutputPath: (path: string) => void;\n}\n\nexport const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher> = (\n  params: ZipFactoryParams = {},\n): ZipPublisher => {\n  let { project, outputPath } = params;\n\n  const getProject = () => project;\n  const setProject = (projectToSet: ResultDir) => {\n    project = projectToSet;\n  };\n\n  const getOutputPath = () => outputPath;\n  const setOutputPath = (path: string) => {\n    outputPath = path;\n  };\n\n  const publish = async (options: ZipFactoryParams = {}) => {\n    const projectToPublish = options.project || project;\n    if (!projectToPublish) {\n      throw new PublisherError('MissingProject');\n    }\n\n    const zipName = options.projectSlug || params.projectSlug || projectToPublish.name;\n\n    try {\n      const zipContent = await generateProjectZip(projectToPublish);\n\n      if (isNodeProcess()) {\n        // If not output path is provided on the node side, zip is not written to disk\n        const projectOutputPath = options.outputPath || outputPath;\n        if (projectOutputPath) {\n          await writeZipToDisk(projectOutputPath, zipContent, zipName);\n        }\n      } else {\n        // the browser end does not require a path\n        // auto download zip files\n        saveAs(zipContent as Blob, `${zipName}.zip`);\n      }\n\n      return { success: true, payload: zipContent };\n    } catch (error) {\n      throw new PublisherError(getErrorMessage(error) || 'UnknownError');\n    }\n  };\n\n  return {\n    publish,\n    getProject,\n    setProject,\n    getOutputPath,\n    setOutputPath,\n  };\n};\n"
  },
  {
    "path": "modules/code-generator/src/publisher/zip/utils.ts",
    "content": "import JSZip from 'jszip';\nimport { ResultDir, ResultFile } from '@alilc/lowcode-types';\nimport type { ZipBuffer } from './index';\n\nexport const isNodeProcess = (): boolean => {\n  return (\n    typeof process === 'object' &&\n    typeof process.versions === 'object' &&\n    typeof process.versions.node !== 'undefined'\n  );\n};\n\nexport const writeZipToDisk = (\n  zipFolderPath: string,\n  content: ZipBuffer,\n  zipName: string,\n): void => {\n  if (!isNodeProcess()) {\n    throw new Error('ZipPublisher: writeZipToDisk is only available in NodeJS');\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-var-requires\n  // eslint-disable-next-line @typescript-eslint/no-require-imports\n  const fs = require('fs');\n  // eslint-disable-next-line @typescript-eslint/no-var-requires\n  // eslint-disable-next-line @typescript-eslint/no-require-imports\n  const path = require('path');\n\n  if (!fs.existsSync(zipFolderPath)) {\n    fs.mkdirSync(zipFolderPath, { recursive: true });\n  }\n\n  const zipPath = path.join(zipFolderPath, `${zipName}.zip`);\n\n  const writeStream = fs.createWriteStream(zipPath);\n  writeStream.write(content);\n  writeStream.end();\n};\n\nexport const generateProjectZip = async (project: ResultDir): Promise<ZipBuffer> => {\n  let zip = new JSZip();\n  zip = writeFolderToZip(project, zip, true);\n  const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';\n  return zip.generateAsync({ type: zipType });\n};\n\nconst writeFolderToZip = (folder: ResultDir, parentFolder: JSZip, ignoreFolder = false) => {\n  const zipFolder = ignoreFolder ? parentFolder : parentFolder.folder(folder.name);\n  if (zipFolder !== null) {\n    folder.files.forEach((file: ResultFile) => {\n      // const options = file.contentEncoding === 'base64' ? { base64: true } : {};\n      const options = {};\n      const fileName = file.ext ? `${file.name}.${file.ext}` : file.name;\n      zipFolder.file(fileName, file.content, options);\n    });\n\n    folder.dirs.forEach((subFolder: ResultDir) => {\n      writeFolderToZip(subFolder, zipFolder);\n    });\n  }\n\n  return parentFolder;\n};\n"
  },
  {
    "path": "modules/code-generator/src/solutions/icejs.ts",
    "content": "import { IProjectBuilder, IProjectBuilderOptions } from '../types';\n\nimport { createProjectBuilder } from '../generator/ProjectBuilder';\n\nimport esmodule from '../plugins/common/esmodule';\nimport styleImport from '../plugins/common/styleImport';\nimport containerClass from '../plugins/component/react/containerClass';\nimport containerInitState from '../plugins/component/react/containerInitState';\nimport containerInjectContext from '../plugins/component/react/containerInjectContext';\nimport containerInjectUtils from '../plugins/component/react/containerInjectUtils';\nimport containerInjectDataSourceEngine from '../plugins/component/react/containerInjectDataSourceEngine';\nimport containerInjectConstants from '../plugins/component/react/containerInjectConstants';\nimport containerInjectI18n from '../plugins/component/react/containerInjectI18n';\nimport containerLifeCycle from '../plugins/component/react/containerLifeCycle';\nimport containerMethod from '../plugins/component/react/containerMethod';\nimport jsx from '../plugins/component/react/jsx';\nimport reactCommonDeps from '../plugins/component/react/reactCommonDeps';\nimport css from '../plugins/component/style/css';\nimport constants from '../plugins/project/constants';\nimport i18n from '../plugins/project/i18n';\nimport utils from '../plugins/project/utils';\n\nimport icejs from '../plugins/project/framework/icejs';\n\nimport { prettier } from '../postprocessor';\n\nexport type IceJsProjectBuilderOptions = IProjectBuilderOptions;\n\nexport default function createIceJsProjectBuilder(\n  options?: IceJsProjectBuilderOptions,\n): IProjectBuilder {\n  return createProjectBuilder({\n    inStrictMode: options?.inStrictMode,\n    extraContextData: { ...options },\n    template: icejs.template,\n    plugins: {\n      components: [\n        reactCommonDeps(),\n        esmodule({\n          fileType: 'jsx',\n        }),\n        styleImport(),\n        containerClass(),\n        containerInjectContext(),\n        containerInjectUtils(),\n        containerInjectDataSourceEngine(),\n        containerInjectI18n(),\n        containerInjectConstants(),\n        containerInitState(),\n        containerLifeCycle(),\n        containerMethod(),\n        jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Page: 'div',\n            Block: 'div',\n          },\n        }),\n        css(),\n      ],\n      pages: [\n        reactCommonDeps(),\n        esmodule({\n          fileType: 'jsx',\n        }),\n        styleImport(),\n        containerClass(),\n        containerInjectContext(),\n        containerInjectUtils(),\n        containerInjectDataSourceEngine(),\n        containerInjectI18n(),\n        containerInjectConstants(),\n        containerInitState(),\n        containerLifeCycle(),\n        containerMethod(),\n        jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Page: 'div',\n            Block: 'div',\n            // Box: 'div',\n          },\n        }),\n        css(),\n      ],\n      router: [esmodule(), icejs.plugins.router()],\n      entry: [icejs.plugins.entry()],\n      constants: [constants()],\n      utils: [esmodule(), utils('react')],\n      i18n: [i18n()],\n      globalStyle: [icejs.plugins.globalStyle()],\n      htmlEntry: [icejs.plugins.entryHtml()],\n      packageJSON: [icejs.plugins.packageJSON()],\n    },\n    postProcessors: [prettier()],\n    customizeBuilderOptions: options?.customizeBuilderOptions,\n  });\n}\n\nexport const plugins = {\n  containerClass,\n  containerInjectContext,\n  containerInjectUtils,\n  containerInjectDataSourceEngine,\n  containerInjectI18n,\n  containerInjectConstants,\n  containerInitState,\n  containerLifeCycle,\n  containerMethod,\n  jsx,\n  commonDeps: reactCommonDeps,\n\n  /** @deprecated Please use commonDeps */\n  reactCommonDeps,\n};\n"
  },
  {
    "path": "modules/code-generator/src/solutions/icejs3.ts",
    "content": "import { IProjectBuilder, IProjectBuilderOptions } from '../types';\n\nimport { createProjectBuilder } from '../generator/ProjectBuilder';\n\nimport esmodule from '../plugins/common/esmodule';\nimport styleImport from '../plugins/common/styleImport';\nimport containerClass from '../plugins/component/react/containerClass';\nimport containerInitState from '../plugins/component/react/containerInitState';\nimport containerInjectContext from '../plugins/component/react/containerInjectContext';\nimport containerInjectUtils from '../plugins/component/react/containerInjectUtils';\nimport containerInjectDataSourceEngine from '../plugins/component/react/containerInjectDataSourceEngine';\nimport containerInjectConstants from '../plugins/component/react/containerInjectConstants';\nimport containerInjectI18n from '../plugins/component/react/containerInjectI18n';\nimport containerLifeCycle from '../plugins/component/react/containerLifeCycle';\nimport containerMethod from '../plugins/component/react/containerMethod';\nimport jsx from '../plugins/component/react/jsx';\nimport reactCommonDeps from '../plugins/component/react/reactCommonDeps';\nimport css from '../plugins/component/style/css';\nimport constants from '../plugins/project/constants';\nimport i18n from '../plugins/project/i18n';\nimport utils from '../plugins/project/utils';\n\nimport icejs3 from '../plugins/project/framework/icejs3';\n\nimport { prettier } from '../postprocessor';\n\nexport type IceJs3ProjectBuilderOptions = IProjectBuilderOptions;\n\nexport default function createIceJsProjectBuilder(\n  options?: IceJs3ProjectBuilderOptions,\n): IProjectBuilder {\n  return createProjectBuilder({\n    inStrictMode: options?.inStrictMode,\n    extraContextData: { ...options },\n    template: icejs3.template,\n    plugins: {\n      components: [\n        reactCommonDeps(),\n        esmodule({\n          fileType: 'jsx',\n        }),\n        styleImport(),\n        containerClass(),\n        containerInjectContext(),\n        containerInjectUtils(),\n        containerInjectDataSourceEngine(),\n        containerInjectI18n(),\n        containerInjectConstants(),\n        containerInitState(),\n        containerLifeCycle(),\n        containerMethod(),\n        jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Page: 'div',\n            Block: 'div',\n          },\n        }),\n        css(),\n      ],\n      pages: [\n        reactCommonDeps(),\n        esmodule({\n          fileType: 'jsx',\n        }),\n        styleImport(),\n        containerClass(),\n        containerInjectContext(),\n        containerInjectUtils(),\n        containerInjectDataSourceEngine(),\n        containerInjectI18n(),\n        containerInjectConstants(),\n        containerInitState(),\n        containerLifeCycle(),\n        containerMethod(),\n        jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Page: 'div',\n            Block: 'div',\n            Box: 'div',\n          },\n        }),\n        css(),\n      ],\n      constants: [constants()],\n      utils: [esmodule(), utils('react')],\n      i18n: [i18n()],\n      globalStyle: [icejs3.plugins.globalStyle()],\n      packageJSON: [icejs3.plugins.packageJSON()],\n      buildConfig: [icejs3.plugins.buildConfig()],\n      appConfig: [icejs3.plugins.appConfig()],\n      layout: [icejs3.plugins.layout()],\n    },\n    postProcessors: [prettier()],\n    customizeBuilderOptions: options?.customizeBuilderOptions,\n  });\n}\n\nexport const plugins = {\n  containerClass,\n  containerInitState,\n  containerInjectContext,\n  containerInjectUtils,\n  containerInjectI18n,\n  containerInjectDataSourceEngine,\n  containerLifeCycle,\n  containerMethod,\n  jsx,\n  commonDeps: reactCommonDeps,\n};\n"
  },
  {
    "path": "modules/code-generator/src/solutions/rax-app.ts",
    "content": "import { IProjectBuilder, IProjectBuilderOptions } from '../types';\n\nimport { createProjectBuilder } from '../generator/ProjectBuilder';\n\nimport esModule from '../plugins/common/esmodule';\nimport containerClass from '../plugins/component/rax/containerClass';\nimport containerLifeCycles from '../plugins/component/rax/containerLifeCycle';\nimport containerMethods from '../plugins/component/rax/containerMethods';\nimport containerInitState from '../plugins/component/rax/containerInitState';\nimport containerInjectContext from '../plugins/component/rax/containerInjectContext';\nimport containerInjectDataSourceEngine from '../plugins/component/rax/containerInjectDataSourceEngine';\nimport containerInjectUtils from '../plugins/component/rax/containerInjectUtils';\nimport jsx from '../plugins/component/rax/jsx';\nimport commonDeps from '../plugins/component/rax/commonDeps';\nimport css from '../plugins/component/style/css';\nimport constants from '../plugins/project/constants';\nimport i18n from '../plugins/project/i18n';\nimport utils from '../plugins/project/utils';\n\nimport raxApp from '../plugins/project/framework/rax';\n\nimport { prettier } from '../postprocessor';\nimport { RaxFrameworkOptions } from '../plugins/project/framework/rax/types/RaxFrameworkOptions';\n\nexport interface RaxProjectBuilderOptions extends IProjectBuilderOptions, RaxFrameworkOptions {}\n\nexport default function createRaxProjectBuilder(\n  options?: RaxProjectBuilderOptions,\n): IProjectBuilder {\n  return createProjectBuilder({\n    inStrictMode: options?.inStrictMode,\n    extraContextData: { ...options },\n    template: raxApp.template,\n    plugins: {\n      components: [\n        commonDeps(),\n        esModule({ fileType: 'jsx', useAliasName: false }),\n        containerClass(),\n        containerInitState(),\n        containerMethods(),\n        containerInjectContext(),\n        containerInjectDataSourceEngine(options),\n        containerInjectUtils(),\n        containerLifeCycles(),\n        jsx(),\n        css(),\n      ],\n      pages: [\n        commonDeps(),\n        esModule({ fileType: 'jsx' }),\n        containerClass(),\n        containerInitState(),\n        containerMethods(),\n        containerInjectContext(),\n        containerInjectDataSourceEngine(options),\n        containerInjectUtils(),\n        containerLifeCycles(),\n        jsx(),\n        css(),\n      ],\n      appConfig: [raxApp.plugins.appConfig(options)],\n      buildConfig: [raxApp.plugins.buildConfig(options)],\n      entry: [raxApp.plugins.entry(options)],\n      constants: [constants()],\n      utils: [esModule(), utils('rax')],\n      i18n: [i18n()],\n      globalStyle: [\n        raxApp.plugins.globalStyle({ fileType: options?.globalStylesFileType || 'css' }),\n      ],\n      htmlEntry: [raxApp.plugins.entryDocument(options)],\n      packageJSON: [raxApp.plugins.packageJSON(options)],\n    },\n    postProcessors: [prettier()],\n    customizeBuilderOptions: options?.customizeBuilderOptions,\n  });\n}\n\nexport const plugins = {\n  containerClass,\n  containerLifeCycles,\n  containerMethods,\n  containerInitState,\n  containerInjectContext,\n  containerInjectDataSourceEngine,\n  containerInjectUtils,\n  jsx,\n  commonDeps,\n  raxApp,\n};\n"
  },
  {
    "path": "modules/code-generator/src/standalone-loader.ts",
    "content": "import fetch from 'node-fetch';\nimport type { IPublicTypeProjectSchema, ResultDir } from '@alilc/lowcode-types';\nimport type { FlattenFile } from './types/file';\n\ndeclare const Worker: any;\ndeclare const self: any;\ndeclare const __PACKAGE_VERSION__: string;\n\nconst packageVersion = __PACKAGE_VERSION__ || 'latest';\n\nexport const DEFAULT_WORKER_JS = `https://cdn.jsdelivr.net/npm/@alilc/lowcode-code-generator@${packageVersion}/dist/standalone-worker.min.js`;\n\nexport const DEFAULT_TIMEOUT_IN_MS = 60 * 1000;\n\nconst workerJsCache = new Map<string, { content: string; url: string }>();\n\nexport async function init({\n  workerJsUrl = DEFAULT_WORKER_JS,\n}: {\n  workerJsUrl?: string;\n} = {}) {\n  await loadWorkerJs(workerJsUrl);\n}\n\nexport type Result = ResultDir | FlattenFile[];\n\nexport async function generateCode(options: {\n  solution: 'icejs' | 'rax';\n  schema: IPublicTypeProjectSchema;\n  flattenResult?: boolean;\n  workerJsUrl?: string;\n  timeoutInMs?: number;\n}): Promise<Result> {\n  if (typeof self !== 'object') {\n    throw new Error('self is not defined');\n  }\n\n  if (typeof Worker !== 'function') {\n    throw new Error('Worker is not supported');\n  }\n\n  const workerJsUrl = options.workerJsUrl || DEFAULT_WORKER_JS;\n\n  const workerJs = await loadWorkerJs(workerJsUrl);\n\n  const worker = new Worker(workerJs.url, {\n    type: 'classic',\n    credentials: 'omit',\n  });\n\n  return new Promise((resolve, reject) => {\n    const timer = setTimeout(() => {\n      reject(new Error('timeout'));\n      worker.terminate();\n    }, options.timeoutInMs || DEFAULT_TIMEOUT_IN_MS);\n\n    worker.onmessage = (event: any) => {\n      const msg = event.data;\n      switch (msg.type) {\n        case 'ready':\n          print('worker is ready.');\n          break;\n\n        case 'run:begin':\n          print('worker is running...');\n          break;\n        case 'run:end':\n          print('worker is done.');\n          resolve(msg.result);\n          clearTimeout(timer);\n          worker.terminate();\n          break;\n        case 'run:error':\n          printErr(`worker error: ${msg.errorMsg}`);\n          clearTimeout(timer);\n          reject(new Error(msg.errorMsg || 'unknown error'));\n          worker.terminate();\n          break;\n        default:\n          print('got unknown msg: %o', msg);\n          break;\n      }\n    };\n\n    worker.onerror = (err: any) => {\n      printErr('worker error: %o', err);\n      clearTimeout(timer);\n      reject(err);\n      worker.terminate();\n    };\n\n    worker.postMessage({\n      type: 'run',\n      solution: options.solution,\n      schema: options.schema,\n      flattenResult: options.flattenResult,\n    });\n  });\n}\n\nasync function loadWorkerJs(workerJsUrl: string) {\n  const cached = workerJsCache.get(workerJsUrl);\n  if (cached) {\n    return cached;\n  }\n\n  const workerJsContent = await fetch(workerJsUrl)\n    .then((res) => res.text())\n    .catch((err) => {\n      throw new Error(`Failed to fetch worker js: ${err}`);\n    });\n\n  const workerJs = {\n    content: workerJsContent,\n    url: self.URL.createObjectURL(\n      new self.Blob([workerJsContent], { type: 'application/javascript' }),\n    ),\n  };\n\n  workerJsCache.set(workerJsUrl, workerJs);\n\n  return workerJs;\n}\n\nfunction print(msg: string, ...args: unknown[]) {\n  // eslint-disable-next-line no-console\n  console.debug(`[code-generator/loader]: ${msg}`, ...args);\n}\n\nfunction printErr(msg: string, ...args: unknown[]) {\n  // eslint-disable-next-line no-console\n  console.debug(`[code-generator/loader]: %c${msg}`, 'color:red', ...args);\n}\n"
  },
  {
    "path": "modules/code-generator/src/standalone-worker.ts",
    "content": "/* eslint-disable no-console */\nimport type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport CodeGen from './standalone';\n\ndeclare const self: any;\n\nself.onmessage = (event: any) => {\n  const msg = event.data || {};\n  if (msg.type === 'run') {\n    run(msg);\n  }\n};\n\nself.postMessage({ type: 'ready' });\n\nasync function run(msg: { solution: string; schema: IPublicTypeProjectSchema; flattenResult?: boolean }) {\n  try {\n    print('begin run...');\n    self.postMessage({ type: 'run:begin' });\n\n    const { solution } = msg;\n    if (!solution) {\n      throw new Error('solution is required');\n    }\n\n    const createAppBuilder = CodeGen.solutions[solution as 'icejs' | 'rax'];\n    if (typeof createAppBuilder !== 'function') {\n      throw new Error(`solution '${solution}' is invalid`);\n    }\n\n    const appBuilder = createAppBuilder();\n\n    print('generating from schema: %o', msg.schema);\n\n    const result = await appBuilder.generateProject(msg.schema);\n\n    print('generated result: %o', result);\n\n    const finalResult = msg.flattenResult\n      ? CodeGen.utils.resultHelper.flattenResult(result)\n      : result;\n\n    if (msg.flattenResult) {\n      print('flatten result: %o', finalResult);\n    }\n\n    self.postMessage({\n      type: 'run:end',\n      result: finalResult,\n    });\n  } catch (e) {\n    printErr(`${e}`);\n    self.postMessage({\n      type: 'run:error',\n      errorMsg: `${(e as Error | null)?.message || e}`,\n      errorDetail: `${e}`,\n    });\n  }\n}\n\nfunction print(text: string, ...args: any[]) {\n  console.debug(`[code-generator/worker]: ${text}`, ...args);\n  self.postMessage({\n    type: 'stdout',\n    data: text,\n    args,\n  });\n}\n\nfunction printErr(text: string, ...args: any[]) {\n  console.debug(`[code-generator/worker]: %c${text}`, 'color:red', ...args);\n  self.postMessage({\n    type: 'stderr',\n    data: text,\n    args,\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/src/standalone.ts",
    "content": "/**\n * 低代码引擎的出码模块，负责将编排产出的 Schema 转换成实际可执行的代码。\n * 注意：为了保持 API 的稳定性, 这里所有导出的 API 均要显式命名方式导出\n *     （即用 export { xxx } from 'xx' 的方式，不要直接 export * from 'xxx')\n *      而且所有导出的 API 务必在 tests/public 中编写单元测试\n */\nimport './polyfills/buffer';\nimport { createProjectBuilder } from './generator/ProjectBuilder';\nimport { createModuleBuilder } from './generator/ModuleBuilder';\nimport { createZipPublisher } from './publisher/zip';\nimport createIceJsProjectBuilder, { plugins as icejsPlugins } from './solutions/icejs';\nimport createIceJs3ProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3';\nimport createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app';\n\n// 引入说明\nimport { REACT_CHUNK_NAME } from './plugins/component/react/const';\nimport { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from './const/generator';\n\n// 引入通用插件组\nimport esmodule from './plugins/common/esmodule';\nimport requireUtils from './plugins/common/requireUtils';\nimport styleImport from './plugins/common/styleImport';\n\nimport css from './plugins/component/style/css';\nimport constants from './plugins/project/constants';\nimport i18n from './plugins/project/i18n';\nimport utils from './plugins/project/utils';\nimport prettier from './postprocessor/prettier';\n\n// 引入全局常用工具\nimport * as globalUtils from './utils';\n\nimport * as CONSTANTS from './const';\n\n// 引入内置解决方案模块\nimport icejs from './plugins/project/framework/icejs';\nimport icejs3 from './plugins/project/framework/icejs3';\nimport rax from './plugins/project/framework/rax';\n\nexport default {\n  createProjectBuilder,\n  createModuleBuilder,\n  solutions: {\n    icejs: createIceJsProjectBuilder,\n    icejs3: createIceJs3ProjectBuilder,\n    rax: createRaxAppProjectBuilder,\n  },\n  solutionParts: {\n    icejs,\n    icejs3,\n    rax,\n  },\n  publishers: {\n    zip: createZipPublisher,\n  },\n  plugins: {\n    common: {\n\n      /**\n       * 处理 ES Module\n       * @deprecated please use esModule\n       */\n      esmodule,\n      esModule: esmodule,\n      requireUtils,\n      styleImport,\n    },\n    style: {\n      css,\n    },\n    project: {\n      constants,\n      i18n,\n      utils,\n    },\n    icejs: {\n      ...icejsPlugins,\n    },\n    icejs3: {\n      ...icejs3Plugins,\n    },\n    rax: {\n      ...raxPlugins,\n    },\n\n    /**\n     * @deprecated please use icejs\n     */\n    react: {\n      ...icejsPlugins,\n    },\n  },\n  postprocessor: {\n    prettier,\n  },\n  utils: globalUtils,\n  chunkNames: {\n    COMMON_CHUNK_NAME,\n    CLASS_DEFINE_CHUNK_NAME,\n    REACT_CHUNK_NAME,\n  },\n  defaultLinkAfter: {\n    COMMON_DEFAULT_LINK_AFTER: DEFAULT_LINK_AFTER,\n  },\n  constants: CONSTANTS,\n};\n\n// 一些类型定义\nexport * from './types';\n\n// 一些常量定义\nexport * from './const';\n\n// 一些工具函数\nexport * from './analyzer/componentAnalyzer';\nexport * from './parser/SchemaParser';\nexport * from './generator/ChunkBuilder';\nexport * from './generator/CodeBuilder';\nexport * from './generator/ModuleBuilder';\nexport * from './generator/ProjectBuilder';\n"
  },
  {
    "path": "modules/code-generator/src/types/analyze.ts",
    "content": "import type { IPublicTypeContainerSchema } from '@alilc/lowcode-types';\n\nexport interface ICompAnalyzeResult {\n  isUsingRef: boolean;\n}\n\nexport type TComponentAnalyzer = (container: IPublicTypeContainerSchema) => ICompAnalyzeResult;\n"
  },
  {
    "path": "modules/code-generator/src/types/core.ts",
    "content": "import {\n  IPublicTypeCompositeArray,\n  IPublicTypeCompositeObject, IPublicTypeJSExpression,\n  IPublicTypeJSFunction, IPublicTypeJSONArray,\n  IPublicTypeJSONObject, IPublicTypeJSSlot, IPublicTypeNodeDataType,\n  IPublicTypeProjectSchema, ResultDir,\n  ResultFile,\n} from '@alilc/lowcode-types';\n\nimport type { ProjectBuilderInitOptions } from '../generator/ProjectBuilder';\nimport { IScopeBindings } from '../utils/ScopeBindings';\nimport { IParseResult } from './intermediate';\n\nexport enum FileType {\n  CSS = 'css',\n  SCSS = 'scss',\n  LESS = 'less',\n  HTML = 'html',\n  JS = 'js',\n  MJS = 'mjs',\n  JSX = 'jsx',\n  TS = 'ts',\n  MTS = 'mts',\n  TSX = 'tsx',\n  JSON = 'json',\n  MD = 'md',\n}\n\nexport enum ChunkType {\n  AST = 'ast',\n  STRING = 'string',\n  JSON = 'json',\n}\n\nexport enum PluginType {\n  COMPONENT = 'component',\n  UTILS = 'utils',\n  I18N = 'i18n',\n}\n\nexport type ChunkContent = string | any;\nexport type CodeGeneratorFunction<T> = (content: T) => string;\n\nexport interface ICodeChunk {\n  type: ChunkType;\n  fileType: string;\n  name: string;\n  subModule?: string;\n  content: ChunkContent;\n  linkAfter: string[];\n  ext?: Record<string, unknown>;\n}\n\nexport interface IBaseCodeStruct {\n  chunks: ICodeChunk[];\n  depNames: string[];\n}\n\nexport interface ICodeStruct extends IBaseCodeStruct {\n  ir: any;\n  contextData: IContextData;\n}\n\n/** 上下文数据，用来在插件之间共享一些数据 */\nexport interface IContextData extends IProjectBuilderOptions {\n\n  /**\n   * 其他自定义数据\n   * （三方自定义插件也可以在此放一些数据，建议起个长一点的名称，用自己的插件名做前缀，以防冲突）\n   */\n  [key: string]: any;\n\n  /**\n   * 是否使用了 Ref 的 API (this.$/this.$$)\n   * */\n  useRefApi?: boolean;\n}\n\nexport type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise<ICodeStruct>;\n\nexport type BuilderComponentPluginFactory<T> = (config?: T) => BuilderComponentPlugin;\n\nexport interface IChunkBuilder {\n  run: (ir: any, initialStructure?: ICodeStruct) => Promise<{ chunks: ICodeChunk[][] }>;\n  getPlugins: () => BuilderComponentPlugin[];\n  addPlugin: (plugin: BuilderComponentPlugin) => void;\n}\n\nexport interface ICodeBuilder {\n  link: (chunkDefinitions: ICodeChunk[]) => string;\n  generateByType: (type: string, content: unknown) => string;\n}\n\nexport interface ICompiledModule {\n  files: ResultFile[];\n}\n\nexport interface IModuleBuilder {\n  generateModule: (input: unknown) => Promise<ICompiledModule>;\n  generateModuleCode: (schema: IPublicTypeProjectSchema | string) => Promise<ResultDir>;\n  linkCodeChunks: (chunks: Record<string, ICodeChunk[]>, fileName: string) => ResultFile[];\n  addPlugin: (plugin: BuilderComponentPlugin) => void;\n}\n\n/**\n * 引擎对外接口\n *\n * @export\n * @interface ICodeGenerator\n */\nexport interface ICodeGenerator {\n\n  /**\n   * 出码接口，把 Schema 转换成代码文件系统描述\n   *\n   * @param {(IPublicTypeProjectSchema)} schema 传入的 Schema\n   * @returns {ResultDir}\n   * @memberof ICodeGenerator\n   */\n  toCode: (schema: IPublicTypeProjectSchema) => Promise<ResultDir>;\n}\n\nexport interface ISchemaParser {\n  validate: (schema: IPublicTypeProjectSchema) => boolean;\n  parse: (schema: IPublicTypeProjectSchema | string) => IParseResult;\n}\n\nexport interface IProjectTemplate {\n  slots: Record<string, IProjectSlot>;\n  generateTemplate: (data: IParseResult) => ResultDir | Promise<ResultDir>;\n}\n\nexport interface IProjectSlot {\n  path: string[];\n  fileName?: string;\n}\n\nexport interface IProjectPlugins {\n  [slotName: string]: BuilderComponentPlugin[];\n}\n\nexport interface IProjectBuilderOptions {\n\n  /** 是否处于严格模式 (默认：否) */\n  inStrictMode?: boolean;\n\n  /**\n   * 是否要容忍对 JSExpression 求值时的异常\n   * 默认：true\n   * 注：如果容忍异常，则会在求值时包裹 try-catch 块，\n   *     catch 到异常时默认会抛出一个 CustomEvent 事件里面包含异常信息和求值的表达式\n   */\n  tolerateEvalErrors?: boolean;\n\n  /**\n   * 容忍异常的时候的的错误处理语句块\n   * 默认：无\n   * 您可以设置为一个语句块，比如：\n   *  window.dispatchEvent(new CustomEvent('lowcode-eval-error', { error, expr }))\n   *\n   * 一般可以结合埋点监控模块用来监控求值异常\n   *\n   * 其中：\n   * - error: 异常信息\n   * - expr: 求值的表达式\n   */\n  evalErrorsHandler?: string;\n\n  /**\n   * Hook which is used to customize original options, we can reorder/add/remove plugins/processors\n   * of the existing solution.\n   */\n  customizeBuilderOptions?(originalOptions: ProjectBuilderInitOptions): ProjectBuilderInitOptions;\n}\n\nexport interface IProjectBuilder {\n  generateProject: (schema: IPublicTypeProjectSchema | string) => Promise<ResultDir>;\n}\n\n/** 项目级别的前置处理器 */\nexport type ProjectPreProcessor = (schema: IPublicTypeProjectSchema) =>\n  Promise<IPublicTypeProjectSchema> | IPublicTypeProjectSchema;\n\nexport interface ProjectPostProcessorOptions {\n  parseResult?: IParseResult;\n  template?: IProjectTemplate;\n}\n\n/** 项目级别的后置处理器 */\nexport type ProjectPostProcessor = (\n  result: ResultDir,\n  schema: IPublicTypeProjectSchema,\n  originalSchema: IPublicTypeProjectSchema | string,\n  options: ProjectPostProcessorOptions,\n) => Promise<ResultDir> | ResultDir;\n\n/** 模块级别的后置处理器的工厂方法 */\nexport type PostProcessorFactory<T> = (config?: T) => PostProcessor;\n\n/** 模块级别的后置处理器 */\nexport type PostProcessor = (content: string, fileType: string, name?: string) => string;\n\n// TODO: temp interface, need modify\nexport interface IPluginOptions {\n  fileDirDepth: number;\n}\n\nexport type BaseGenerator<I, T, C> = (\n  input: I,\n  scope: IScope,\n  config?: C,\n  next?: BaseGenerator<I, T, C>,\n) => T;\ntype CompositeTypeGenerator<I, T> =\n  | BaseGenerator<I, T, CompositeValueGeneratorOptions>\n  | Array<BaseGenerator<I, T, CompositeValueGeneratorOptions>>;\n\nexport type NodeGenerator<T> = (nodeItem: IPublicTypeNodeDataType, scope: IScope) => T;\n\n// FIXME: 在新的实现中，添加了第一参数 this: CustomHandlerSet 作为上下文。究其本质\n// scopeBindings?: IScopeBindings;\n// 这个组合只用来用来处理 IPublicTypeCompositeValue 类型，不是这个类型的不要放在这里\nexport interface HandlerSet<T> {\n  string?: CompositeTypeGenerator<string, T>;\n  boolean?: CompositeTypeGenerator<boolean, T>;\n  number?: CompositeTypeGenerator<number, T>;\n  expression?: CompositeTypeGenerator<IPublicTypeJSExpression, T>;\n  function?: CompositeTypeGenerator<IPublicTypeJSFunction, T>;\n  slot?: CompositeTypeGenerator<IPublicTypeJSSlot, T>;\n  array?: CompositeTypeGenerator<IPublicTypeJSONArray | IPublicTypeCompositeArray, T>;\n  object?: CompositeTypeGenerator<IPublicTypeJSONObject | IPublicTypeCompositeObject, T>;\n}\n\nexport interface CompositeValueGeneratorOptions {\n  handlers?: HandlerSet<string>;\n  nodeGenerator?: NodeGenerator<string>;\n  tolerateEvalErrors?: boolean;\n}\n\n/**\n * 作用域定义，维护作用域内定义，支持作用域链上溯\n */\nexport interface IScope {\n  // 父级作用域（如果是根作用域则为 null）\n  readonly parent: IScope | null;\n\n  // 作用域内定义的变量/函数等 bindings\n  readonly bindings?: IScopeBindings;\n\n  // TODO: 需要有上下文信息吗？ 描述什么内容\n  createSubScope: (ownIndentifiers: string[]) => IScope;\n}\n"
  },
  {
    "path": "modules/code-generator/src/types/deps.ts",
    "content": "export interface INpmPackage {\n  package: string; // 组件包的名称\n  version: string; // 组件包的版本\n}\n\n/**\n * 外部依赖描述\n *\n * @export\n * @interface IExternalDependency\n */\nexport interface IExternalDependency extends INpmPackage, IDependency {}\n\nexport enum InternalDependencyType {\n  PAGE = 'pages',\n  BLOCK = 'components',\n  COMPONENT = 'components',\n  UTILS = 'utils',\n}\n\nexport enum DependencyType {\n  External = 'External',\n  Internal = 'Internal',\n}\n\nexport interface IInternalDependency extends IDependency {\n  type: InternalDependencyType;\n  moduleName: string;\n}\n\nexport interface IDependency {\n  destructuring: boolean; // 组件是否是解构方式方式导出\n  exportName: string; // 导出命名\n  subName?: string; // 下标子组件名称\n  main?: string; // 包导出组件入口文件路径 /lib/input\n  dependencyType?: DependencyType; // 依赖类型 内/外\n  componentName?: string; // 导入后名称\n}"
  },
  {
    "path": "modules/code-generator/src/types/error.ts",
    "content": "/* eslint-disable @typescript-eslint/no-useless-constructor */\nexport class CodeGeneratorError extends Error {\n  readonly detail?: unknown;\n\n  constructor(message: string, detail?: unknown) {\n    super(message);\n    this.name = this.constructor.name;\n    this.detail = detail;\n    Object.setPrototypeOf(this, new.target.prototype);\n  }\n}\n\nexport class ComponentValidationError extends CodeGeneratorError {}\n\nexport class CompatibilityError extends CodeGeneratorError {}\n\nexport class PublisherError extends CodeGeneratorError {}\n"
  },
  {
    "path": "modules/code-generator/src/types/file.ts",
    "content": "/**\n * 扁平文件信息（层级结构隐含在 pathName 中）\n */\nexport interface FlattenFile {\n  /**\n   * 文件路径\n   */\n  pathName: string;\n\n  /**\n   * 文件内容\n   */\n  content: string | Buffer;\n}\n"
  },
  {
    "path": "modules/code-generator/src/types/index.ts",
    "content": "export * from './core';\nexport * from './deps';\nexport * from './error';\nexport * from './analyze';\nexport * from './intermediate';\nexport * from './publisher';\nexport * from './jsx';\n"
  },
  {
    "path": "modules/code-generator/src/types/intermediate.ts",
    "content": "import {\n  IPublicTypeI18nMap,\n  IPublicTypeUtilsMap,\n  IPublicTypeContainerSchema,\n  IPublicTypeJSONObject,\n} from '@alilc/lowcode-types';\n\nimport { IDependency, INpmPackage } from './deps';\nimport { ICompAnalyzeResult } from './analyze';\n\nexport interface IParseResult {\n  containers: IContainerInfo[];\n  globalUtils?: IUtilInfo;\n  globalI18n?: IPublicTypeI18nMap;\n  globalRouter?: IRouterInfo;\n  project?: IProjectInfo;\n}\n\nexport interface IWithDependency {\n  deps?: IDependency[];\n}\n\nexport interface IContainerInfo extends IPublicTypeContainerSchema, IWithDependency {\n  containerType: string;\n  moduleName: string;\n  analyzeResult?: ICompAnalyzeResult;\n}\n\nexport interface IUtilInfo extends IWithDependency {\n  utils: IPublicTypeUtilsMap;\n}\n\nexport interface IRouterInfo extends IWithDependency {\n  routes: Array<{\n    path: string;\n    fileName: string;\n    componentName: string;\n  }>;\n}\n\n/**\n * project's remarks\n */\nexport interface ProjectRemark {\n\n  /** if current project only contain one container which type is `Component` */\n  isSingleComponent?: boolean;\n}\n\nexport interface IProjectInfo {\n  css?: string;\n  containersDeps?: IDependency[];\n  utilsDeps?: IDependency[];\n  constants?: IPublicTypeJSONObject;\n  i18n?: IPublicTypeI18nMap;\n  packages: INpmPackage[];\n  meta?: { name?: string; title?: string } | Record<string, any>;\n  config?: Record<string, any>;\n  dataSourcesTypes?: string[];\n  projectRemark?: ProjectRemark;\n}\n\nexport interface IPageMeta {\n  router?: string;\n}\n\n/**\n * From meta\n * page title\n * router\n * spmb\n *\n * Utils\n *\n * constants\n *\n * i18n\n *\n * components\n *\n * pages\n *\n * layout\n */\n"
  },
  {
    "path": "modules/code-generator/src/types/jsx.ts",
    "content": "import { IPublicTypeNodeSchema, IPublicTypeCompositeValue } from '@alilc/lowcode-types';\nimport { HandlerSet, BaseGenerator, NodeGenerator } from './core';\n\nexport enum PIECE_TYPE {\n  BEFORE = 'NodeCodePieceBefore',\n  TAG = 'NodeCodePieceTag',\n  ATTR = 'NodeCodePieceAttr',\n  CHILDREN = 'NodeCodePieceChildren',\n  AFTER = 'NodeCodePieceAfter',\n}\n\nexport interface CodePiece {\n  name?: string;\n  value: string;\n  type: PIECE_TYPE;\n}\n\nexport interface AttrData {\n  attrName: string;\n  attrValue: IPublicTypeCompositeValue;\n}\n// 对 JSX 出码的理解，目前定制点包含【包装】【标签名】【属性】\nexport type AttrPlugin = BaseGenerator<AttrData, CodePiece[], NodeGeneratorConfig>;\nexport type NodePlugin = BaseGenerator<IPublicTypeNodeSchema, CodePiece[], NodeGeneratorConfig>;\n\nexport interface NodeGeneratorConfig {\n  handlers?: HandlerSet<string>;\n  tagMapping?: (input: string) => string;\n  attrPlugins?: AttrPlugin[];\n  nodePlugins?: NodePlugin[];\n  self?: NodeGenerator<string>;\n\n  /**\n   * 是否要容忍对 JSExpression 求值时的异常\n   * 默认：true\n   * 注：如果容忍异常，则会在求值时包裹 try-catch 块 -- 通过 __$$eval / __$$evalArray\n   *     catch 到异常时默认会抛出一个 CustomEvent 事件里面包含异常信息和求值的表达式\n   */\n  tolerateEvalErrors?: boolean;\n}\n"
  },
  {
    "path": "modules/code-generator/src/types/publisher.ts",
    "content": "import { ResultDir } from '@alilc/lowcode-types';\n\nexport type PublisherFactory<T, U> = (configuration?: Partial<T>) => U;\n\nexport interface IPublisher<T, U> {\n  publish: (options?: T) => Promise<IPublisherResponse<U>>;\n  getProject: (() => ResultDir) | (() => void);\n  setProject: (project: ResultDir) => void;\n}\n\nexport interface IPublisherFactoryParams {\n  project?: ResultDir;\n}\nexport interface IPublisherResponse<T> {\n  success: boolean;\n  payload?: T;\n}\n"
  },
  {
    "path": "modules/code-generator/src/typings.d.ts",
    "content": "declare module 'nanomatch';\n"
  },
  {
    "path": "modules/code-generator/src/utils/OrderedSet.ts",
    "content": "export class OrderedSet<T> {\n  private _set = new Set<T>();\n  private _arr: T[] = [];\n\n  constructor(items?: T[]) {\n    if (items) {\n      this._set = new Set(items);\n      this._arr = items.slice(0);\n    }\n  }\n\n  add(item: T) {\n    if (!this._set.has(item)) {\n      this._set.add(item);\n      this._arr.push(item);\n    }\n  }\n\n  delete(item: T) {\n    if (this._set.has(item)) {\n      this._set.delete(item);\n      this._arr.splice(this._arr.indexOf(item), 1);\n    }\n  }\n\n  has(item: T) {\n    return this._set.has(item);\n  }\n\n  toArray() {\n    return this._arr.slice(0);\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/Scope.ts",
    "content": "import { IScope } from '../types/core';\nimport { IScopeBindings, ScopeBindings } from './ScopeBindings';\n\nexport class Scope implements IScope {\n  /**\n   * 创建根部 Scope，根据需要被上溯的作用域链决定是否开启新的\n   */\n  static createRootScope(): IScope {\n    return new Scope();\n  }\n\n  bindings?: IScopeBindings;\n\n  constructor(public readonly parent: IScope | null = null) {\n    this.bindings = undefined;\n  }\n\n  createSubScope(ownIdentifiers: string[]): IScope {\n    const originalScopeBindings = this.bindings;\n    const newScopeBindings = new ScopeBindings(originalScopeBindings);\n    ownIdentifiers.forEach((identifier) => {\n      newScopeBindings.addBinding(identifier);\n    });\n    const newScope = new Scope(this);\n    newScope.bindings = newScopeBindings;\n    return newScope;\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/ScopeBindings.ts",
    "content": "import { OrderedSet } from './OrderedSet';\n\nexport interface IScopeBindings {\n  readonly parent: IScopeBindings | null;\n\n  hasBinding: (varName: string) => boolean;\n  hasOwnBinding: (varName: string) => boolean;\n\n  addBinding: (varName: string) => void;\n  removeBinding: (varName: string) => void;\n\n  getAllBindings: () => string[];\n  getAllOwnedBindings: () => string[];\n}\n\nexport class ScopeBindings implements IScopeBindings {\n  readonly parent: IScopeBindings | null;\n\n  private _bindings = new OrderedSet<string>();\n\n  constructor(p: IScopeBindings | null = null) {\n    this.parent = p;\n  }\n\n  hasBinding(varName: string): boolean {\n    return this._bindings.has(varName) || !!this.parent?.hasBinding(varName);\n  }\n\n  hasOwnBinding(varName: string): boolean {\n    return this._bindings.has(varName);\n  }\n\n  addBinding(varName: string): void {\n    this._bindings.add(varName);\n  }\n\n  removeBinding(varName: string): void {\n    this._bindings.delete(varName);\n  }\n\n  getAllBindings(): string[] {\n    const allBindings = new OrderedSet(this._bindings.toArray());\n\n    for (let { parent } = this; parent; parent = parent?.parent) {\n      parent.getAllOwnedBindings().forEach((varName) => {\n        allBindings.add(varName);\n      });\n    }\n\n    return allBindings.toArray();\n  }\n\n  getAllOwnedBindings(): string[] {\n    return this._bindings.toArray();\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/aopHelper.ts",
    "content": "import { BaseGenerator, IScope } from '../types/core';\n\nexport function executeFunctionStack<I, T, C>(\n  input: I,\n  scope: IScope,\n  funcs: BaseGenerator<I, T, C> | Array<BaseGenerator<I, T, C>>,\n  baseFunc: BaseGenerator<I, T, C>,\n  config?: C,\n): T {\n  const funcList: Array<BaseGenerator<I, T, C>> = [];\n  if (Array.isArray(funcs)) {\n    funcList.push(...funcs);\n  } else {\n    funcList.push(funcs);\n  }\n\n  let next: BaseGenerator<I, T, C> = baseFunc;\n  while (funcList.length > 0) {\n    const func = funcList.pop();\n    if (func) {\n      const warppedFunc = ((nextFunc) => (i: I, s: IScope, cfg?: C) => func(i, s, cfg, nextFunc))(next);\n      next = warppedFunc;\n    }\n  }\n\n  return next(input, scope, config);\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/common.ts",
    "content": "import type { IPublicTypeJSExpression, IPublicTypeJSFunction } from '@alilc/lowcode-types';\nimport changeCase from 'change-case';\nimport short from 'short-uuid';\nimport { DependencyType, IDependency, IExternalDependency, IInternalDependency } from '../types';\n\n// Doc: https://www.npmjs.com/package/change-case\n\nexport function camel2dash(input: string): string {\n  return changeCase.paramCase(input);\n}\n\n/**\n * 转为驼峰\n */\nexport function camelize(str: string): string {\n  return changeCase.camelCase(str);\n}\n\nexport function generateID(): string {\n  return short.generate();\n}\n\nexport function upperCaseFirst(inputValue: string): string {\n  return changeCase.upperCaseFirst(inputValue);\n}\n\nexport function uniqueArray<T>(arr: T[], by: (i: T) => string) {\n  const map: Record<string, T> = {};\n  arr.forEach((item) => {\n    map[by(item)] = item;\n  });\n  // FIXME: Babel 编译存在问题，暂时替换实现\n  // const uniqueKeys = [...new Set<string>(Object.keys(map))];\n  const uniqueKeys = Array.from(new Set<string>(Object.keys(map)));\n  const uniqueItems = uniqueKeys.map((key) => map[key]);\n  return uniqueItems;\n}\n\nexport function getStaticExprValue<T>(expr: string): T {\n  // TODO: 需要安全性检查\n  // eslint-disable-next-line no-new-func\n  return Function(`\"use strict\";return (${expr})`)();\n}\n\nexport function isJSExpressionFn(data: any): data is IPublicTypeJSFunction {\n  return data?.type === 'JSExpression' && data?.extType === 'function';\n}\n\nexport function isInternalDependency(\n  dependency: IDependency,\n): dependency is IInternalDependency {\n  return dependency.dependencyType === DependencyType.Internal;\n}\n\nexport function isExternalDependency(\n  dependency: IDependency,\n): dependency is IExternalDependency {\n  return dependency.dependencyType === DependencyType.External;\n}"
  },
  {
    "path": "modules/code-generator/src/utils/compositeType.ts",
    "content": "import {\n  IPublicTypeCompositeArray,\n  IPublicTypeCompositeValue,\n  IPublicTypeCompositeObject,\n  IPublicTypeJSFunction,\n  IPublicTypeJSExpression,\n  isJSExpression,\n  isJSFunction,\n  isJSSlot,\n  IPublicTypeJSSlot,\n} from '@alilc/lowcode-types';\nimport _ from 'lodash';\n\nimport { IScope, CompositeValueGeneratorOptions, CodeGeneratorError } from '../types';\nimport { generateExpression, generateFunction } from './jsExpression';\nimport { generateJsSlot } from './jsSlot';\nimport { executeFunctionStack } from './aopHelper';\nimport { parseExpressionGetKeywords } from './expressionParser';\nimport { isJSExpressionFn } from './common';\n\ninterface ILegaoVariable {\n  type: 'variable';\n  value: string;\n  variable: string;\n}\n\nfunction isVariable(v: any): v is ILegaoVariable {\n  if (_.isObject(v) && (v as ILegaoVariable).type === 'variable') {\n    return true;\n  }\n  return false;\n}\n\ninterface DataSource {\n  type: 'DataSource';\n  id: string;\n}\n\n/**\n * 判断是否是数据源类型\n */\nfunction isDataSource(v: unknown): v is DataSource {\n  return typeof v === 'object' && v != null && (v as Partial<DataSource>).type === 'DataSource';\n}\n\nfunction generateArray(\n  value: IPublicTypeCompositeArray,\n  scope: IScope,\n  options: CompositeValueGeneratorOptions = {},\n): string {\n  const body = value.map((v) => generateUnknownType(v, scope, options)).join(',');\n  return `[${body}]`;\n}\n\nfunction generateObject(\n  value: IPublicTypeCompositeObject,\n  scope: IScope,\n  options: CompositeValueGeneratorOptions = {},\n): string {\n  if (value.type === 'i18n') {\n    // params 可能会绑定变量，这里需要处理下\n    if (value.params && typeof value.params === 'object') {\n      return `this._i18nText(${generateUnknownType(_.omit(value, 'type'), scope, options)})`;\n    }\n    return `this._i18nText(${JSON.stringify(_.omit(value, 'type'))})`; // TODO: 优化：这里可以考虑提取成个常量...\n  }\n\n  const body = Object.keys(value)\n    .map((key) => {\n      const propName = JSON.stringify(key);\n      const v = generateUnknownType(value[key], scope, options);\n      return `${propName}: ${v}`;\n    })\n    .join(',\\n');\n\n  return `{${body}}`;\n}\n\nfunction generateString(value: string): string {\n  // 有的字符串里面会有特殊字符，比如换行或引号之类的，这里我们借助 JSON 的字符串转义功能来做下转义并加上双引号\n  return JSON.stringify(value);\n}\n\nfunction generateNumber(value: number): string {\n  return String(value);\n}\n\nfunction generateBool(value: boolean): string {\n  return value ? 'true' : 'false';\n}\n\nfunction genFunction(value: IPublicTypeJSFunction): string {\n  const globalVars = parseExpressionGetKeywords(value.value);\n\n  if (globalVars.includes('arguments')) {\n    return generateFunction(value, { isBindExpr: true });\n  }\n\n  return generateFunction(value, { isArrow: true });\n}\n\nfunction genJsSlot(value: IPublicTypeJSSlot, scope: IScope, options: CompositeValueGeneratorOptions = {}) {\n  if (options.nodeGenerator) {\n    return generateJsSlot(value, scope, options.nodeGenerator);\n  }\n  return '';\n}\n\nfunction generateUnknownType(\n  value: IPublicTypeCompositeValue,\n  scope: IScope,\n  options: CompositeValueGeneratorOptions = {},\n): string {\n  if (_.isUndefined(value)) {\n    return 'undefined';\n  }\n\n  if (_.isNull(value)) {\n    return 'null';\n  }\n\n  if (_.isArray(value)) {\n    if (options.handlers?.array) {\n      return executeFunctionStack(value, scope, options.handlers.array, generateArray, options);\n    }\n    return generateArray(value, scope, options);\n  }\n\n  // FIXME: 这个是临时方案\n  // 在遇到 type variable 私有类型时，转换为 JSExpression\n  if (isVariable(value)) {\n    const transValue: IPublicTypeJSExpression = {\n      type: 'JSExpression',\n      value: value.variable,\n    };\n\n    if (options.handlers?.expression) {\n      const expression = executeFunctionStack(\n        transValue,\n        scope,\n        options.handlers.expression,\n        generateExpression,\n        options,\n      );\n      return expression || 'undefined';\n    }\n    return generateExpression(transValue, scope);\n  }\n\n  if (isJSExpression(value)) {\n    if (options.handlers?.expression) {\n      return executeFunctionStack(\n        value,\n        scope,\n        options.handlers.expression,\n        generateExpression,\n        options,\n      );\n    }\n    return generateExpression(value, scope);\n  }\n\n  if (isJSFunction(value) || isJSExpressionFn(value)) {\n    if (options.handlers?.function) {\n      return executeFunctionStack(value, scope, options.handlers.function, genFunction, options);\n    }\n    return genFunction(value);\n  }\n\n  if (isJSSlot(value)) {\n    if (options.handlers?.slot) {\n      return executeFunctionStack(value, scope, options.handlers.slot, genJsSlot, options);\n    }\n    return genJsSlot(value, scope, options);\n  }\n\n  if (isDataSource(value)) {\n    return generateUnknownType(\n      {\n        type: 'JSExpression',\n        value: `this.dataSourceMap[${JSON.stringify(value.id)}]`,\n      },\n      scope,\n      options,\n    );\n  }\n\n  if (_.isObject(value)) {\n    if (options.handlers?.object) {\n      return executeFunctionStack(value, scope, options.handlers.object, generateObject, options);\n    }\n    return generateObject(value as IPublicTypeCompositeObject, scope, options);\n  }\n\n  if (_.isString(value)) {\n    if (options.handlers?.string) {\n      return executeFunctionStack(value, scope, options.handlers.string, generateString, options);\n    }\n    return generateString(value);\n  }\n\n  if (_.isNumber(value)) {\n    if (options.handlers?.number) {\n      return executeFunctionStack(value, scope, options.handlers.number, generateNumber, options);\n    }\n    return generateNumber(value);\n  }\n\n  if (_.isBoolean(value)) {\n    if (options.handlers?.boolean) {\n      return executeFunctionStack(value, scope, options.handlers.boolean, generateBool, options);\n    }\n    return generateBool(value);\n  }\n\n  throw new CodeGeneratorError('Meet unknown composite value type');\n}\n\n// 这一层曾经是对产出做最外层包装的，但其实包装逻辑不应该属于这一层\n// 这一层先不去掉，做冗余，方便后续重构\nexport function generateCompositeType(\n  value: IPublicTypeCompositeValue,\n  scope: IScope,\n  options: CompositeValueGeneratorOptions = {},\n): string {\n  const result = generateUnknownType(value, scope, options);\n  return result;\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/dataSource.ts",
    "content": "import changeCase from 'change-case';\nimport type { IProjectInfo } from '../types/intermediate';\n\nexport interface DataSourceDependenciesConfig {\n\n  /** 数据源引擎的版本 */\n  engineVersion?: string;\n\n  /** 数据源引擎的包名 */\n  enginePackage?: string;\n\n  /** 数据源 handlers 的版本 */\n  handlersVersion?: {\n    [key: string]: string;\n  };\n\n  /** 数据源 handlers 的包名 */\n  handlersPackages?: {\n    [key: string]: string;\n  };\n}\n\nexport function buildDataSourceDependencies(\n  ir: IProjectInfo,\n  cfg: DataSourceDependenciesConfig = {},\n): Record<string, string> {\n  return {\n    // 数据源引擎的依赖包\n    [cfg.enginePackage || '@alilc/lowcode-datasource-engine']: cfg.engineVersion || '^1.0.0',\n\n    // 各种数据源的 handlers 的依赖包\n    ...(ir.dataSourcesTypes || []).reduce(\n      (acc, dsType) => ({\n        ...acc,\n        [getDataSourceHandlerPackageName(dsType)]: cfg.handlersVersion?.[dsType] || '^1.0.0',\n      }),\n      {},\n    ),\n  };\n\n  function getDataSourceHandlerPackageName(dsType: string) {\n    return (\n      cfg.handlersPackages?.[dsType] ||\n      `@alilc/lowcode-datasource-${changeCase.kebab(dsType)}-handler`\n    );\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/debug.ts",
    "content": "import createDebug from 'debug';\n\nexport const debug = createDebug('code-generator');\n"
  },
  {
    "path": "modules/code-generator/src/utils/encodeJsxAttrString.ts",
    "content": "import _ from 'lodash';\n// import { encode } from 'html-entities';\n\nconst SPECIAL_CHARS = '\\n\\r\\'\"<>&';\nconst SPECIAL_CHARS_REG = new RegExp(\n  `[${SPECIAL_CHARS.split('')\n    .map((c) => `\\\\x${_.padStart(c.charCodeAt(0).toString(16), 2, '0')}`)\n    .join('')}]`,\n  'g',\n);\n\nexport function encodeJsxStringNode(str: string): string {\n  return str.replace(SPECIAL_CHARS_REG, (c) => `&#${c.charCodeAt(0)};`);\n}\n\n// export function encodeJsxStringNode(str: string): string {\n//   return encode(str);\n// }\n"
  },
  {
    "path": "modules/code-generator/src/utils/errors.ts",
    "content": "/**\n * 获取错误信息\n */\nexport function getErrorMessage(error: unknown): string | null {\n  if (!error) {\n    return null;\n  }\n\n  if (error instanceof Error) {\n    return error.message;\n  }\n\n  if (typeof error === 'string') {\n    return error;\n  }\n\n  if (typeof error === 'object' && error !== null) {\n    return (\n      getErrorMessage((error as { message: string }).message) ||\n      getErrorMessage((error as { errorMessage: string }).errorMessage) ||\n      getErrorMessage((error as { detail: string }).detail)\n    );\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/expressionParser.ts",
    "content": "import * as parser from '@babel/parser';\nimport generate from '@babel/generator';\nimport traverse, { NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\nimport { isIdentifier, Node } from '@babel/types';\n\nimport { OrderedSet } from './OrderedSet';\nimport { IScope } from '../types';\n\nexport class ParseError extends Error {\n  readonly expr: string | t.Expression;\n\n  readonly detail: unknown;\n\n  constructor(expr: string | t.Expression, detail: unknown) {\n    super(`Failed to parse expression \"${typeof expr === 'string' ? expr : generate(expr)}\"`);\n    this.expr = expr;\n    this.detail = detail;\n    Object.setPrototypeOf(this, new.target.prototype);\n  }\n}\n\nconst MAYBE_EXPRESSIONS: {\n  [k in Node['type']]?: {\n    // fields: Array<keyof (Node & { type: k })>\n    fields: string[] | ((node: Node) => string[]);\n  };\n} = {\n  ArrayExpression: { fields: ['elements'] },\n  AssignmentExpression: { fields: ['left', 'right'] },\n  BinaryExpression: { fields: ['left', 'right'] },\n  CallExpression: { fields: ['arguments', 'callee'] },\n  ConditionalExpression: { fields: ['test', 'consequent', 'alternate'] },\n  DoWhileStatement: { fields: ['test'] },\n  ExpressionStatement: { fields: ['expression'] },\n  ForInStatement: { fields: ['right'] },\n  ForStatement: { fields: ['init', 'test', 'update'] },\n  IfStatement: { fields: ['test'] },\n  LogicalExpression: { fields: ['left', 'right'] },\n  MemberExpression: {\n    fields: (node) => {\n      return node.type === 'MemberExpression' && node.computed\n        ? ['object', 'property']\n        : ['object'];\n    },\n  },\n  NewExpression: { fields: ['callee', 'arguments'] },\n  ObjectMethod: {\n    fields: (node) => {\n      return node.type === 'ObjectMethod' && node.computed ? ['key'] : [];\n    },\n  },\n  ObjectProperty: {\n    fields: (node) => {\n      return node.type === 'ObjectProperty' && node.computed ? ['key', 'value'] : ['value'];\n    },\n  },\n  ReturnStatement: { fields: ['argument'] },\n  SequenceExpression: { fields: ['expressions'] },\n  ParenthesizedExpression: { fields: ['expression'] },\n  SwitchCase: { fields: ['test'] },\n  SwitchStatement: { fields: ['discriminant'] },\n  ThrowStatement: { fields: ['argument'] },\n  UnaryExpression: { fields: ['argument'] },\n  UpdateExpression: { fields: ['argument'] },\n  VariableDeclarator: { fields: ['init'] },\n  WhileStatement: { fields: ['test'] },\n  WithStatement: { fields: ['object'] },\n  AssignmentPattern: { fields: ['right'] },\n  ArrowFunctionExpression: { fields: ['body'] },\n  ClassExpression: { fields: ['superClass'] },\n  ClassDeclaration: { fields: ['superClass'] },\n  ExportDefaultDeclaration: { fields: ['declaration'] },\n  ForOfStatement: { fields: ['right'] },\n  ClassMethod: {\n    fields: (node) => {\n      return node.type === 'ClassMethod' && node.computed ? ['key'] : [];\n    },\n  },\n  SpreadElement: { fields: ['argument'] },\n  TaggedTemplateExpression: { fields: ['tag'] },\n  TemplateLiteral: { fields: ['expressions'] },\n  YieldExpression: { fields: ['argument'] },\n  AwaitExpression: { fields: ['argument'] },\n  OptionalMemberExpression: {\n    fields: (node) => {\n      return node.type === 'OptionalMemberExpression' && node.computed\n        ? ['object', 'property']\n        : ['object'];\n    },\n  },\n  OptionalCallExpression: { fields: ['callee', 'arguments'] },\n  JSXSpreadAttribute: { fields: ['argument'] },\n  BindExpression: { fields: ['object', 'callee'] },\n  ClassProperty: {\n    fields: (node) => {\n      return node.type === 'ClassProperty' && node.computed ? ['key', 'value'] : ['value'];\n    },\n  },\n  PipelineTopicExpression: { fields: ['expression'] },\n  PipelineBareFunction: { fields: ['callee'] },\n  ClassPrivateProperty: { fields: ['value'] },\n  Decorator: { fields: ['expression'] },\n  TupleExpression: { fields: ['elements'] },\n  TSDeclareMethod: {\n    fields: (node) => {\n      return node.type === 'TSDeclareMethod' && node.computed ? ['key'] : [];\n    },\n  },\n  TSPropertySignature: {\n    fields: (node) => {\n      return node.type === 'TSPropertySignature' && node.computed\n        ? ['key', 'initializer']\n        : ['initializer'];\n    },\n  },\n\n  TSMethodSignature: {\n    fields: (node) => {\n      return node.type === 'TSMethodSignature' && node.computed ? ['key'] : [];\n    },\n  },\n  TSAsExpression: { fields: ['expression'] },\n  TSTypeAssertion: { fields: ['expression'] },\n  TSEnumDeclaration: { fields: ['initializer'] },\n  TSEnumMember: { fields: ['initializer'] },\n  TSNonNullExpression: { fields: ['expression'] },\n  TSExportAssignment: { fields: ['expression'] },\n};\n\nexport interface ParseExpressionGetGlobalVariablesOptions {\n  filter?: (varName: string) => boolean;\n}\n\nconst CROSS_THIS_SCOPE_TYPE_NODE: {\n  [k in Node['type']]?: boolean;\n} = {\n  ArrowFunctionExpression: false, // 箭头函数不跨越 this 的 scope\n  FunctionExpression: true,\n  FunctionDeclaration: true,\n  // FunctionTypeAnnotation: false, // 这是 TS 定义\n  // FunctionTypeParam: false, // 这是 TS 定义\n  ClassDeclaration: true,\n  ClassExpression: true,\n  ClassBody: true,\n  ClassImplements: true,\n  ClassMethod: true,\n  ClassPrivateMethod: true,\n  ClassProperty: true,\n  ClassPrivateProperty: true,\n  DeclareClass: true,\n};\n\nconst JS_KEYWORDS = ['arguments', 'this', 'super'];\n\nexport function parseExpressionGetKeywords(expr: string | null | undefined): string[] {\n  if (!expr) {\n    return [];\n  }\n\n  try {\n    const keywordVars = new OrderedSet<string>();\n\n    const ast = parser.parse(`!(${expr});`, {\n      plugins: [\n        'jsx',\n      ],\n    });\n\n    const addIdentifierIfNeeded = (x: Node | null | undefined) => {\n      if (typeof x === 'object' && isIdentifier(x) && JS_KEYWORDS.includes(x.name)) {\n        keywordVars.add(x.name);\n      }\n    };\n\n    traverse(ast, {\n      enter(path) {\n        const { node } = path;\n        const expressionFields = MAYBE_EXPRESSIONS[node.type]?.fields;\n        if (expressionFields) {\n          (typeof expressionFields === 'function'\n            ? expressionFields(node)\n            : expressionFields\n          ).forEach((fieldName) => {\n            const fieldValue = node[fieldName as keyof typeof node];\n            if (typeof fieldValue === 'object') {\n              if (Array.isArray(fieldValue)) {\n                fieldValue.forEach((item: any) => {\n                  addIdentifierIfNeeded(item);\n                });\n              } else {\n                addIdentifierIfNeeded(fieldValue as any);\n              }\n            }\n          });\n        }\n      },\n    });\n\n    return keywordVars.toArray().filter(Boolean);\n  } catch (e) {\n    throw new ParseError(expr, e);\n  }\n}\n\nexport function parseExpressionGetGlobalVariables(\n  expr: string | null | undefined,\n  { filter = () => true }: ParseExpressionGetGlobalVariablesOptions = {},\n): string[] {\n  if (!expr) {\n    return [];\n  }\n\n  try {\n    const undeclaredVars = new OrderedSet<string>();\n\n    const ast = parser.parse(`!(${expr});`);\n\n    const addUndeclaredIdentifierIfNeeded = (\n      x: Node | null | undefined,\n      path: NodePath<Node>,\n    ) => {\n      if (typeof x === 'object' && isIdentifier(x) && !path.scope.hasBinding(x.name)) {\n        undeclaredVars.add(x.name);\n      }\n    };\n\n    traverse(ast, {\n      enter(path) {\n        const { node } = path;\n        const expressionFields = MAYBE_EXPRESSIONS[node.type]?.fields;\n        if (expressionFields) {\n          (typeof expressionFields === 'function'\n            ? expressionFields(node)\n            : expressionFields\n          ).forEach((fieldName) => {\n            const fieldValue = node[fieldName as keyof typeof node];\n            if (typeof fieldValue === 'object') {\n              if (Array.isArray(fieldValue)) {\n                fieldValue.forEach((item: any) => {\n                  addUndeclaredIdentifierIfNeeded(item, path);\n                });\n              } else {\n                addUndeclaredIdentifierIfNeeded(fieldValue as any, path);\n              }\n            }\n          });\n        }\n      },\n    });\n\n    return undeclaredVars.toArray().filter(filter);\n  } catch (e) {\n    throw new ParseError(expr, e);\n  }\n}\n\nexport function parseExpressionConvertThis2Context(\n  expr: string | t.Expression,\n  contextName = '__$$context',\n  localVariables: string[] = [],\n): string {\n  if (!expr) {\n    return expr;\n  }\n\n  try {\n    const exprAst = typeof expr === 'string' ? parser.parseExpression(expr) : expr;\n    const exprWrapAst = t.expressionStatement(exprAst);\n    const fileAst = t.file(t.program([exprWrapAst]));\n\n    const localVariablesSet = new Set(localVariables);\n\n    let thisScopeLevel = CROSS_THIS_SCOPE_TYPE_NODE[exprAst.type] ? -1 : 0;\n    traverse(fileAst, {\n      enter(path) {\n        if (CROSS_THIS_SCOPE_TYPE_NODE[path.node.type]) {\n          thisScopeLevel++;\n        }\n      },\n      exit(path) {\n        if (CROSS_THIS_SCOPE_TYPE_NODE[path.node.type]) {\n          thisScopeLevel--;\n        }\n      },\n      MemberExpression(path) {\n        if (!path.isMemberExpression()) {\n          return;\n        }\n\n        const obj = path.get('object');\n        if (!obj.isThisExpression()) {\n          return;\n        }\n\n        // 处理局部变量\n        if (!path.node.computed) {\n          const prop = path.get('property');\n          if (prop.isIdentifier() && localVariablesSet.has(prop.node.name)) {\n            path.replaceWith(t.identifier(prop.node.name));\n            return;\n          }\n        }\n\n        // 替换 this (只在顶层替换)\n        if (thisScopeLevel <= 0) {\n          obj.replaceWith(t.identifier(contextName));\n        }\n      },\n      ThisExpression(path) {\n        if (!path.isThisExpression()) {\n          return;\n        }\n\n        // MemberExpression 中的 this.xxx 已经处理过了\n        if (path.parent.type === 'MemberExpression') {\n          return;\n        }\n\n        if (thisScopeLevel <= 0) {\n          path.replaceWith(t.identifier(contextName));\n        }\n      },\n    });\n\n    const { code } = generate(exprWrapAst.expression, { sourceMaps: false });\n    return code;\n  } catch (e) {\n    throw new ParseError(expr, e);\n  }\n}\n\nexport function parseExpression(expr: string) {\n  try {\n    return parser.parseExpression(expr);\n  } catch (e) {\n    throw new ParseError(expr, e);\n  }\n}\n\nexport function transformExpressionLocalRef(expr: string, scope: IScope) {\n  if (!expr) {\n    return expr;\n  }\n\n  if (!scope) {\n    throw new Error('transform expression without scope');\n  }\n\n  try {\n    const exprAst = typeof expr === 'string' ? parser.parseExpression(expr) : expr;\n    const exprWrapAst = t.expressionStatement(exprAst);\n    const fileAst = t.file(t.program([exprWrapAst]));\n\n    traverse(fileAst, {\n      MemberExpression(path) {\n        if (!path.isMemberExpression()) {\n          return;\n        }\n\n        const obj = path.get('object');\n        if (!obj.isThisExpression()) {\n          return;\n        }\n\n        // 查看是否存在引用 local 值\n        const prop = path.get('property');\n        let memberName = '';\n        if (!path.node.computed && prop.isIdentifier()) {\n          memberName = prop.node.name;\n        } else if (path.node.computed && prop.isStringLiteral()) {\n          memberName = prop.node.value;\n        }\n        if (memberName && scope.bindings && scope.bindings.hasBinding(memberName)) {\n          path.replaceWith(t.identifier(memberName));\n        }\n      },\n    });\n\n    const { code } = generate(exprWrapAst.expression, { sourceMaps: false });\n    return code;\n  } catch (e) {\n    throw new ParseError(expr, e);\n    // throw e;\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/format.ts",
    "content": "import prettier from 'prettier';\nimport parserBabel from 'prettier/parser-babel';\n\nexport function format(content: string, options = {}) {\n  return prettier.format(content, {\n    parser: 'babel',\n    plugins: [parserBabel],\n    singleQuote: true,\n    jsxSingleQuote: false,\n    ...options,\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/index.ts",
    "content": "// 本文件是要导出到外面的，注意只导出比较稳定的东西\nimport * as common from './common';\nimport * as compositeType from './compositeType';\nimport * as jsExpression from './jsExpression';\nimport * as jsSlot from './jsSlot';\nimport * as nodeToJSX from './nodeToJSX';\nimport * as resultHelper from './resultHelper';\nimport * as templateHelper from './templateHelper';\nimport * as validate from './validate';\nimport * as schema from './schema';\nimport * as version from './version';\nimport * as scope from './Scope';\nimport * as expressionParser from './expressionParser';\nimport * as dataSource from './dataSource';\nimport * as pathHelper from './pathHelper';\n\nexport {\n  common,\n  compositeType,\n  jsExpression,\n  jsSlot,\n  nodeToJSX,\n  resultHelper,\n  templateHelper,\n  validate,\n  schema,\n  version,\n  scope,\n  expressionParser,\n  dataSource,\n  pathHelper,\n};\n"
  },
  {
    "path": "modules/code-generator/src/utils/jsExpression.ts",
    "content": "import * as parser from '@babel/parser';\nimport generate from '@babel/generator';\nimport traverse from '@babel/traverse';\nimport * as t from '@babel/types';\nimport { IPublicTypeJSExpression, IPublicTypeJSFunction, isJSExpression, isJSFunction } from '@alilc/lowcode-types';\nimport { CodeGeneratorError, IScope } from '../types';\nimport { transformExpressionLocalRef, ParseError } from './expressionParser';\nimport { isJSExpressionFn } from './common';\n\nfunction parseFunction(content: string): t.FunctionExpression | null {\n  try {\n    const ast = parser.parse(`(${content});`, {\n      plugins: [\n        'jsx',\n      ],\n    });\n\n    let resultNode: t.FunctionExpression | null = null;\n    traverse(ast, {\n      FunctionExpression(path) {\n        resultNode = path.node;\n        path.stop();\n      },\n    });\n    return resultNode;\n  } catch (e) {\n    throw new ParseError(content, e);\n  }\n}\n\nfunction transformFuncExpr2MethodMember(methodName: string, content: string): string {\n  const funcNode = parseFunction(content);\n  if (funcNode) {\n    const targetNode = t.classMethod(\n      'method',\n      (methodName && t.identifier(methodName)) || funcNode.id || t.identifier('notDefineName'),\n      funcNode.params,\n      funcNode.body,\n      undefined,\n      undefined,\n      undefined,\n      funcNode.async || undefined,\n    );\n\n    const { code: resultCode } = generate(targetNode, { sourceMaps: false });\n    return resultCode;\n  }\n\n  throw new Error('Can not find Function Statement');\n}\n\nfunction getArrowFunction(content: string) {\n  const funcNode = parseFunction(content);\n  if (funcNode) {\n    const targetNode = t.arrowFunctionExpression(\n      funcNode.params,\n      funcNode.body,\n      funcNode.async || undefined,\n    );\n\n    const { code: resultCode } = generate(targetNode, { sourceMaps: false });\n    return resultCode;\n  }\n\n  throw new Error('Can not find Function Statement');\n}\n\nfunction getBodyStatements(content: string) {\n  const funcNode = parseFunction(content);\n  if (funcNode) {\n    const statements: t.Statement[] = funcNode.body.body;\n\n    const targetNode = t.program(statements, undefined, 'module', undefined);\n\n    const { code: resultCode } = generate(targetNode, { sourceMaps: false });\n    return resultCode;\n  }\n\n  throw new Error('Can not find Function Statement');\n}\n\n/**\n * 是否是广义上的 JSFunction\n * @param value\n * @returns\n */\nexport function isBroadJSFunction(value: unknown): boolean {\n  return isJSExpressionFn(value) || isJSFunction(value);\n}\n\nexport function generateExpression(value: any, scope: IScope): string {\n  if (isJSExpression(value)) {\n    const exprVal = (value as IPublicTypeJSExpression).value.trim();\n    if (!exprVal) {\n      return 'null';\n    }\n\n    const afterProcessWithLocals = transformExpressionLocalRef(exprVal, scope);\n    return afterProcessWithLocals;\n  }\n\n  throw new CodeGeneratorError('Not a JSExpression');\n}\n\nfunction getFunctionSource(cfg: IPublicTypeJSFunction): string {\n  return cfg.source || cfg.value || cfg.compiled;\n}\n\nexport function generateFunction(\n  value: any,\n  config: {\n    name?: string;\n    isMember?: boolean;\n    isBlock?: boolean;\n    isArrow?: boolean;\n    isBindExpr?: boolean;\n  } = {\n    name: undefined,\n    isMember: false,\n    isBlock: false,\n    isArrow: false,\n    isBindExpr: false,\n  },\n) {\n  if (isBroadJSFunction(value)) {\n    const functionCfg = value as IPublicTypeJSFunction;\n    const functionSource = getFunctionSource(functionCfg);\n    if (config.isMember) {\n      return transformFuncExpr2MethodMember(config.name || '', functionSource);\n    }\n    if (config.isBlock) {\n      return getBodyStatements(functionSource);\n    }\n    if (config.isArrow) {\n      return getArrowFunction(functionSource);\n    }\n    if (config.isBindExpr) {\n      return `(${functionSource}).bind(this)`;\n    }\n    return functionSource;\n  }\n\n  if (isJSExpression(value)) {\n    return value.value;\n  }\n\n  throw new CodeGeneratorError('Not a JSFunction or JSExpression');\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/jsSlot.ts",
    "content": "import { IPublicTypeJSSlot, isJSSlot, IPublicTypeNodeData } from '@alilc/lowcode-types';\nimport { CodeGeneratorError, NodeGenerator, IScope } from '../types';\nimport { unwrapJsExprQuoteInJsx } from './jsxHelpers';\n\nfunction generateSingleLineComment(commentText: string): string {\n  return `/* ${commentText.split('\\n').join(' ').replace(/\\*\\//g, '*-/')}*/`;\n}\n\nexport function generateJsSlot(slot: any, scope: IScope, generator: NodeGenerator<string>): string {\n  if (isJSSlot(slot)) {\n    const { title, params, value } = slot as IPublicTypeJSSlot;\n\n    // slot 也是分有参数和无参数的\n    // - 有参数的 slot 就是类似一个 render 函数，需要创建子作用域\n    // - 无参数的 slot 就是类似一个 JSX 节点，不需要创建子作用域\n    const slotScope = params ? scope.createSubScope(params || []) : scope;\n    const contentExpr = !value\n      ? 'null'\n      : generateNodeDataOrArrayForJsSlot(value, generator, slotScope);\n    if (params) {\n      return [\n        title && generateSingleLineComment(title),\n        '(',\n        (params || []).join(', '),\n        ') => ((__$$context) => (',\n        contentExpr,\n        '))(',\n        `  __$$createChildContext(__$$context, { ${(params || []).join(', ')} }`,\n        '))',\n      ]\n        .filter(Boolean)\n        .join('');\n    }\n\n    return contentExpr || '[]';\n  }\n\n  throw new CodeGeneratorError('Not a JSSlot');\n}\n\nfunction generateNodeDataOrArrayForJsSlot(\n  value: IPublicTypeNodeData | IPublicTypeNodeData[],\n  generator: NodeGenerator<string>,\n  scope: IScope,\n) {\n  if (Array.isArray(value)) {\n    if (value.length === 0) {\n      return '[]';\n    }\n\n    if (value.length === 1) {\n      return unwrapJsExprQuoteInJsx(generator(value, scope)) || 'null';\n    }\n\n    return `[\\n${\n      value\n        .map((v) => {\n          if (typeof v === 'string') {\n            return JSON.stringify(v);\n          }\n\n          return unwrapJsExprQuoteInJsx(generator(v, scope)) || 'null';\n        })\n        .join(',\\n') || 'null'\n    }\\n]`;\n  }\n\n  return unwrapJsExprQuoteInJsx(generator(value, scope)) || 'null';\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/jsxHelpers.ts",
    "content": "/**\n * 去掉 JS 表达式的 \"{...}\" 的封装, 如:\n *  {<xxx />} => <xxx />\n */\nexport function unwrapJsExprQuoteInJsx(jsxExpr: string): string {\n  if (jsxExpr.length >= 2 && jsxExpr[0] === '{' && jsxExpr[jsxExpr.length - 1] === '}') {\n    return jsxExpr.slice(1, jsxExpr.length - 1);\n  }\n\n  return jsxExpr;\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/nodeToJSX.ts",
    "content": "import _ from 'lodash';\nimport { pipe } from 'fp-ts/function';\nimport { IPublicTypeNodeSchema, isNodeSchema, IPublicTypeNodeDataType, IPublicTypeCompositeValue } from '@alilc/lowcode-types';\n\nimport {\n  IScope,\n  CodeGeneratorError,\n  PIECE_TYPE,\n  CodePiece,\n  NodeGenerator,\n  NodeGeneratorConfig,\n  NodePlugin,\n  AttrData,\n} from '../types';\n\nimport { generateCompositeType } from './compositeType';\nimport { getStaticExprValue } from './common';\nimport { executeFunctionStack } from './aopHelper';\nimport { encodeJsxStringNode } from './encodeJsxAttrString';\nimport { unwrapJsExprQuoteInJsx } from './jsxHelpers';\nimport { transformThis2Context } from '../core/jsx/handlers/transformThis2Context';\nimport { isValidIdentifier } from './validate';\n\nfunction mergeNodeGeneratorConfig(\n  cfg1: NodeGeneratorConfig,\n  cfg2: NodeGeneratorConfig = {},\n): NodeGeneratorConfig {\n  const resCfg: NodeGeneratorConfig = {};\n  if (cfg1.handlers || cfg2.handlers) {\n    resCfg.handlers = {\n      ...(cfg1.handlers || {}),\n      ...(cfg2.handlers || {}),\n    };\n  }\n\n  if (cfg1.tagMapping || cfg2.tagMapping) {\n    resCfg.tagMapping = cfg2.tagMapping || cfg1.tagMapping;\n  }\n\n  if (cfg1.attrPlugins || cfg2.attrPlugins) {\n    resCfg.attrPlugins = [];\n    resCfg.attrPlugins.push(...(cfg2.attrPlugins || []));\n    resCfg.attrPlugins.push(...(cfg1.attrPlugins || []));\n  }\n\n  if (cfg1.nodePlugins || cfg2.nodePlugins) {\n    resCfg.nodePlugins = [];\n    resCfg.nodePlugins.push(...(cfg2.nodePlugins || []));\n    resCfg.nodePlugins.push(...(cfg1.nodePlugins || []));\n  }\n\n  return resCfg;\n}\n\nexport function isPureString(v: string) {\n  // FIXME: 目前的方式不够严谨\n  return (v[0] === \"'\" && v[v.length - 1] === \"'\") || (v[0] === '\"' && v[v.length - 1] === '\"');\n}\n\nfunction generateAttrValue(\n  attrData: { attrName: string; attrValue: IPublicTypeCompositeValue },\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n): CodePiece[] {\n  const valueStr = generateCompositeType(attrData.attrValue, scope, {\n    handlers: config?.handlers,\n    nodeGenerator: config?.self,\n  });\n  return [\n    {\n      type: PIECE_TYPE.ATTR,\n      name: attrData.attrName,\n      value: valueStr,\n    },\n  ];\n}\n\nfunction generateAttr(\n  attrName: string,\n  attrValue: IPublicTypeCompositeValue,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n): CodePiece[] {\n  let pieces: CodePiece[];\n  if (config?.attrPlugins) {\n    pieces = executeFunctionStack<AttrData, CodePiece[], NodeGeneratorConfig>(\n      { attrName, attrValue },\n      scope,\n      config.attrPlugins,\n      generateAttrValue,\n      config,\n    );\n  } else {\n    pieces = generateAttrValue({ attrName, attrValue }, scope, config);\n  }\n\n  pieces = pieces.map((p) => {\n    // FIXME: 在经过 generateCompositeType 处理过之后，其实已经无法通过传入值的类型判断传出值是否为纯字面值字符串了（可能包裹了加工函数之类的）\n    //        因此这个处理最好的方式是对传出值做语法分析，判断以哪种模版产出 Attr 值\n    let newValue: string;\n    if (p.value && isPureString(p.value)) {\n      // 似乎多次一举，目前的诉求是处理多种引号类型字符串的 case，正确处理转义\n      const content = getStaticExprValue<string>(p.value);\n      newValue = JSON.stringify(encodeJsxStringNode(content));\n    } else {\n      newValue = `{${p.value}}`;\n    }\n\n    return {\n      value: `${p.name}=${newValue}`,\n      type: PIECE_TYPE.ATTR,\n    };\n  });\n\n  return pieces;\n}\n\nfunction generateAttrs(\n  nodeItem: IPublicTypeNodeSchema,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n): CodePiece[] {\n  const { props } = nodeItem;\n\n  let pieces: CodePiece[] = [];\n\n  if (props) {\n    if (!Array.isArray(props)) {\n      Object.keys(props).forEach((propName: string) => {\n        if (isValidIdentifier(propName)) {\n          pieces = pieces.concat(generateAttr(propName, props[propName] as IPublicTypeCompositeValue, scope, config));\n        }\n      });\n    } else {\n      props.forEach((prop) => {\n        if (prop.name && isValidIdentifier(prop.name) && !prop.spread) {\n          pieces = pieces.concat(generateAttr(prop.name, prop.value, scope, config));\n        }\n\n        // TODO: 处理 spread 场景（<Xxx {...(something)}/>)\n        // 这种在 schema 里面怎么描述\n      });\n    }\n  }\n\n  return pieces;\n}\n\nfunction generateBasicNode(\n  nodeItem: IPublicTypeNodeSchema,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n): CodePiece[] {\n  const pieces: CodePiece[] = [];\n  const tagName = (config?.tagMapping || _.identity)(nodeItem.componentName);\n\n  pieces.push({\n    value: tagName || '', // FIXME: type detection error\n    type: PIECE_TYPE.TAG,\n  });\n\n  return pieces;\n}\n\nfunction generateSimpleNode(\n  nodeItem: IPublicTypeNodeSchema,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n): CodePiece[] {\n  const basicParts = generateBasicNode(nodeItem, scope, config) || [];\n  const attrParts = generateAttrs(nodeItem, scope, config) || [];\n  const childrenParts: CodePiece[] = [];\n  if (nodeItem.children && config?.self) {\n    const childrenStr = config.self(nodeItem.children, scope);\n\n    childrenParts.push({\n      type: PIECE_TYPE.CHILDREN,\n      value: childrenStr,\n    });\n  }\n\n  return [...basicParts, ...attrParts, ...childrenParts];\n}\n\nfunction linkPieces(pieces: CodePiece[]): string {\n  const tagsPieces = pieces.filter((p) => p.type === PIECE_TYPE.TAG);\n  if (tagsPieces.length !== 1) {\n    throw new CodeGeneratorError('Only one tag definition required', tagsPieces);\n  }\n  const tagName = tagsPieces[0].value;\n\n  const beforeParts = pieces\n    .filter((p) => p.type === PIECE_TYPE.BEFORE)\n    .map((p) => p.value)\n    .join('');\n\n  const afterParts = pieces\n    .filter((p) => p.type === PIECE_TYPE.AFTER)\n    .map((p) => p.value)\n    .join('');\n\n  const childrenParts = pieces\n    .filter((p) => p.type === PIECE_TYPE.CHILDREN)\n    .map((p) => p.value)\n    .join('');\n\n  let attrsParts = pieces\n    .filter((p) => p.type === PIECE_TYPE.ATTR)\n    .map((p) => p.value)\n    .join(' ');\n\n  attrsParts = attrsParts ? ` ${attrsParts}` : '';\n\n  if (childrenParts) {\n    return `${beforeParts}<${tagName}${attrsParts}>${childrenParts}</${tagName}>${afterParts}`;\n  }\n\n  return `${beforeParts}<${tagName}${attrsParts} />${afterParts}`;\n}\n\nfunction generateNodeSchema(\n  nodeItem: IPublicTypeNodeSchema,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n): string {\n  const pieces: CodePiece[] = [];\n  if (config?.nodePlugins) {\n    const res = executeFunctionStack<IPublicTypeNodeSchema, CodePiece[], NodeGeneratorConfig>(\n      nodeItem,\n      scope,\n      config.nodePlugins,\n      generateSimpleNode,\n      config,\n    );\n    pieces.push(...res);\n  } else {\n    pieces.push(...generateSimpleNode(nodeItem, scope, config));\n  }\n\n  return linkPieces(pieces);\n}\n\n// TODO: 生成文档\n// 为包裹的代码片段生成子上下文，集成父级上下文，并传入子级上下文新增内容。（如果存在多级上下文怎么处理？）\n// 创建新的上下文，并从作用域中取对应同名变量塞到作用域里面？\n// export function createSubContext() {}\n\n/**\n * JSX 生成逻辑插件。在 React 代码模式下生成 loop 相关的逻辑代码\n * @type NodePlugin Extended\n *\n * @export\n * @param {IPublicTypeNodeSchema} nodeItem 当前 UI 节点\n * @returns {CodePiece[]} 实现功能的相关代码片段\n */\nexport function generateReactLoopCtrl(\n  nodeItem: IPublicTypeNodeSchema,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n  next?: NodePlugin,\n): CodePiece[] {\n  if (nodeItem.loop) {\n    const tolerateEvalErrors = config?.tolerateEvalErrors ?? true;\n\n    const loopItemName = nodeItem.loopArgs?.[0] || 'item';\n    const loopIndexName = nodeItem.loopArgs?.[1] || 'index';\n\n    // 新建作用域\n    const subScope = scope.createSubScope([loopItemName, loopIndexName]);\n    const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : [];\n\n    // 生成循环变量表达式\n    const loopDataExpr = pipe(\n      nodeItem.loop,\n      // 将 JSExpression 转换为 JS 表达式代码:\n      (expr) => generateCompositeType(expr, scope, {\n          handlers: config?.handlers,\n          tolerateEvalErrors: false, // 这个内部不需要包 try catch, 下面会统一加的\n        }),\n      // 将 this.xxx 转换为 __$$context.xxx:\n      (expr) => transformThis2Context(expr, scope, { ignoreRootScope: true }),\n      // 如果要容忍错误，则包一层 try catch (基于助手函数 __$$evalArray)\n      (expr) => (tolerateEvalErrors ? `__$$evalArray(() => (${expr}))` : expr),\n    );\n\n    pieces.unshift({\n      value: `(${loopDataExpr}).map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`,\n      type: PIECE_TYPE.BEFORE,\n    });\n\n    pieces.push({\n      value: `))(__$$createChildContext(__$$context, { ${loopItemName}, ${loopIndexName} })))`,\n      type: PIECE_TYPE.AFTER,\n    });\n\n    return pieces;\n  }\n\n  return next ? next(nodeItem, scope, config) : [];\n}\n\n/**\n * JSX 生成逻辑插件。在 React 代码模式下生成 condition 相关的逻辑代码\n * @type NodePlugin\n *\n * @export\n * @param {IPublicTypeNodeSchema} nodeItem 当前 UI 节点\n * @returns {CodePiece[]} 实现功能的相关代码片段\n */\nexport function generateConditionReactCtrl(\n  nodeItem: IPublicTypeNodeSchema,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n  next?: NodePlugin,\n): CodePiece[] {\n  const pieces: CodePiece[] = next ? next(nodeItem, scope, config) : [];\n\n  if (nodeItem.condition != null && nodeItem.condition !== true) {\n    const value = generateCompositeType(nodeItem.condition, scope, {\n      handlers: config?.handlers,\n    });\n\n    pieces.unshift({\n      value: `!!(${value}) && (`,\n      type: PIECE_TYPE.BEFORE,\n    });\n\n    pieces.push({\n      value: ')',\n      type: PIECE_TYPE.AFTER,\n    });\n  }\n\n  return pieces;\n}\n\n/**\n * JSX 生成逻辑插件。在 React 代码模式下，如果 Node 生成结果是一个表达式，则对其进行 { Expression } 包装\n * @type NodePlugin\n *\n * @export\n * @param {IPublicTypeNodeSchema} nodeItem 当前 UI 节点\n * @returns {CodePiece[]} 实现功能的相关代码片段\n */\nexport function generateReactExprInJS(\n  nodeItem: IPublicTypeNodeSchema,\n  scope: IScope,\n  config?: NodeGeneratorConfig,\n  next?: NodePlugin,\n): CodePiece[] {\n  const pieces: CodePiece[] = next ? next(nodeItem, scope, config) : [];\n\n  if ((nodeItem.condition != null && nodeItem.condition !== true) || nodeItem.loop != null) {\n    pieces.unshift({\n      value: '{',\n      type: PIECE_TYPE.BEFORE,\n    });\n\n    pieces.push({\n      value: '}',\n      type: PIECE_TYPE.AFTER,\n    });\n  }\n\n  return pieces;\n}\n\nconst handleChildren = (v: string[]) => v.join('');\n\nexport function createNodeGenerator(cfg: NodeGeneratorConfig = {}): NodeGenerator<string> {\n  const generateNode = (nodeItem: IPublicTypeNodeDataType, scope: IScope): string => {\n    if (_.isArray(nodeItem)) {\n      const resList = nodeItem.map((n) => generateNode(n, scope));\n      return handleChildren(resList);\n    }\n\n    if (isNodeSchema(nodeItem)) {\n      return generateNodeSchema(nodeItem, scope, {\n        ...cfg,\n        self: generateNode,\n      });\n    }\n\n    const valueStr = generateCompositeType(nodeItem, scope, {\n      handlers: cfg.handlers,\n      nodeGenerator: generateNode,\n    });\n\n    if (isPureString(valueStr)) {\n      return encodeJsxStringNode(getStaticExprValue<string>(valueStr));\n    }\n\n    return `{${valueStr}}`;\n  };\n\n  return (nodeItem: IPublicTypeNodeDataType, scope: IScope) => unwrapJsExprQuoteInJsx(generateNode(nodeItem, scope));\n}\n\nconst defaultReactGeneratorConfig: NodeGeneratorConfig = {\n  nodePlugins: [generateReactExprInJS, generateReactLoopCtrl, generateConditionReactCtrl],\n};\n\nexport function createReactNodeGenerator(cfg?: NodeGeneratorConfig): NodeGenerator<string> {\n  const newCfg = mergeNodeGeneratorConfig(defaultReactGeneratorConfig, cfg);\n\n  return createNodeGenerator(newCfg);\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/pathHelper.ts",
    "content": "import { IContextData } from '../types';\n\nfunction relativePath(from: string[], to: string[]): string[] {\n  const length = Math.min(from.length, to.length);\n  let samePartsLength = length;\n  for (let i = 0; i < length; i++) {\n    if (from[i] !== to[i]) {\n      samePartsLength = i;\n      break;\n    }\n  }\n  if (samePartsLength === 0) {\n    return to;\n  }\n  let outputParts = [];\n  for (let i = samePartsLength; i < from.length; i++) {\n    outputParts.push('..');\n  }\n  outputParts = [...outputParts, ...to.slice(samePartsLength)];\n  if (outputParts[0] !== '..') {\n    outputParts.unshift('.');\n  }\n  return outputParts;\n}\n\nexport function getSlotRelativePath(options: {\n  contextData: IContextData;\n  from: string;\n  to: string;\n}) {\n  const { contextData, from, to } = options;\n  const isSingleComponent = contextData?.extraContextData?.projectRemark?.isSingleComponent;\n  const template = contextData?.extraContextData?.template;\n  let toPath = template.slots[to].path;\n  toPath = [...toPath, template.slots[to].fileName!];\n  let fromPath = template.slots[from].path;\n  if (!isSingleComponent && ['components', 'pages'].indexOf(from) !== -1) {\n    fromPath = [...fromPath, 'pageName'];\n  }\n  return relativePath(fromPath, toPath).join('/');\n}"
  },
  {
    "path": "modules/code-generator/src/utils/resultHelper.ts",
    "content": "import { ResultFile, ResultDir } from '@alilc/lowcode-types';\nimport nm from 'nanomatch';\n\nimport { CodeGeneratorError } from '../types/error';\nimport { FlattenFile } from '../types/file';\n\nexport function createResultFile(name: string, ext = 'jsx', content = ''): ResultFile {\n  return {\n    name,\n    ext,\n    content,\n  };\n}\n\nexport function createResultDir(name: string): ResultDir {\n  return {\n    name,\n    dirs: [],\n    files: [],\n  };\n}\n\nexport function addDirectory(target: ResultDir, dir: ResultDir): void {\n  if (target.dirs.findIndex((d) => d.name === dir.name) < 0) {\n    target.dirs.push(dir);\n  } else {\n    throw new CodeGeneratorError(\n      `Adding same directory to one directory: ${dir.name} -> ${target.name}`,\n    );\n  }\n}\n\nexport function addFile(target: ResultDir, file: ResultFile): void {\n  if (target.files.findIndex((f) => f.name === file.name && f.ext === file.ext) < 0) {\n    target.files.push(file);\n  } else {\n    throw new CodeGeneratorError(\n      `Adding same file to one directory: ${file.name} -> ${target.name}`,\n    );\n  }\n}\n\nexport function flattenResult(dir: ResultDir, cwd = ''): FlattenFile[] {\n  if (!dir.files.length && !dir.dirs.length) {\n    return [];\n  }\n\n  return [\n    ...dir.files.map(\n      (file): FlattenFile => ({\n        pathName: joinPath(cwd, `${file.name}${file.ext ? `.${file.ext}` : ''}`),\n        content: file.content,\n      }),\n    ),\n  ].concat(...dir.dirs.map((subDir) => flattenResult(subDir, joinPath(cwd, subDir.name))));\n}\n\nexport type GlobOptions = {\n  /** 是否查找 \".xxx\" 文件, 默认: 否 */\n  dot?: boolean;\n};\n\n/**\n * 查找文件\n * @param result 出码结果\n * @param fileGlobExpr 文件名匹配表达式\n * @param resultDirPath 出码结果的路径（默认是 '.'）\n * @returns 匹配的第一个文件或 null （找不到）\n */\nexport function findFile(\n  result: ResultDir,\n  fileGlobExpr: string,\n  options: GlobOptions = {},\n  resultDirPath = getResultNameOrDefault(result, ''),\n): ResultFile | null {\n  const maxDepth = !/\\/|\\*\\*/.test(fileGlobExpr) ? 1 : undefined; // 如果 glob 表达式里面压根不会匹配子目录，则深度限制为 1\n  const files = scanFiles(result, resultDirPath, maxDepth);\n\n  for (let [filePath, file] of files) {\n    if (nm.isMatch(filePath, fileGlobExpr, options)) {\n      return file;\n    }\n  }\n\n  return null;\n}\n\n/**\n * 使用 glob 语法查找多个文件\n * @param result 出码结果\n * @param fileGlobExpr 文件名匹配表达式\n * @param resultDirPath 出码结果的路径（默认是 '.'）\n * @returns 找到的文件列表的迭代器 [ [文件路径, 文件信息], ... ]\n */\nexport function* globFiles(\n  result: ResultDir,\n  fileGlobExpr: string,\n  options: GlobOptions = {},\n  resultDirPath = getResultNameOrDefault(result, ''),\n): IterableIterator<[string, ResultFile]> {\n  const files = scanFiles(result, resultDirPath);\n\n  for (let [filePath, file] of files) {\n    if (nm.isMatch(filePath, fileGlobExpr, options)) {\n      yield [filePath, file];\n    }\n  }\n}\n\n/**\n * 遍历所有的文件\n */\nexport function* scanFiles(\n  result: ResultDir,\n  resultDirPath = getResultNameOrDefault(result, ''),\n  maxDepth = 10000,\n): IterableIterator<[string, ResultFile]> {\n  for (let file of result.files) {\n    const fileName = getFileNameWithExt(file);\n    yield [joinPath(resultDirPath, fileName), file];\n  }\n\n  for (let subDir of result.dirs) {\n    yield* scanFiles(subDir, joinPath(resultDirPath, subDir.name), maxDepth - 1);\n  }\n}\n\nexport function getFileNameWithExt(file: ResultFile) {\n  return `${file.name}${file.ext ? `.${file.ext}` : ''}`;\n}\n\nfunction getResultNameOrDefault(result: ResultDir, defaultDir = '/') {\n  return result.name && result.name !== '.' ? result.name : defaultDir;\n}\n\nfunction joinPath(...pathParts: string[]): string {\n  return pathParts\n    .filter((x) => x !== '' && x !== '.')\n    .join('/')\n    .replace(/\\\\+/g, '/')\n    .replace(/\\/+/g, '/');\n}\n\nexport function* scanDirs(\n  result: ResultDir,\n  resultDirPath = getResultNameOrDefault(result, ''),\n  maxDepth = 10000,\n): IterableIterator<[string, ResultDir]> {\n  yield [resultDirPath, result];\n\n  for (let subDir of result.dirs) {\n    yield* scanDirs(subDir, joinPath(resultDirPath, subDir.name), maxDepth - 1);\n  }\n}\n\nexport function* globDirs(\n  result: ResultDir,\n  dirGlobExpr: string,\n  options: GlobOptions = {},\n  resultDirPath = getResultNameOrDefault(result, ''),\n): IterableIterator<[string, ResultDir]> {\n  const dirs = scanDirs(result, resultDirPath);\n\n  for (let [dirPath, dir] of dirs) {\n    if (nm.isMatch(dirPath, dirGlobExpr, options)) {\n      yield [dirPath, dir];\n    }\n  }\n}\n\nexport function findDir(\n  result: ResultDir,\n  dirGlobExpr: string,\n  options: GlobOptions = {},\n  resultDirPath = getResultNameOrDefault(result, ''),\n): ResultDir | null {\n  const dirs = scanDirs(result, resultDirPath);\n\n  for (let [dirPath, dir] of dirs) {\n    if (nm.isMatch(dirPath, dirGlobExpr, options)) {\n      return dir;\n    }\n  }\n\n  return null;\n}\n\n/**\n * 从结果中移除一些文件\n * @param result 出码结果目录\n * @param filePathGlobExpr 要移除的文件路径（glob 表达式）\n * @param globOptions glob 参数\n * @returns 移除了多少文件\n */\nexport function removeFilesFromResult(\n  result: ResultDir,\n  filePathGlobExpr: string,\n  globOptions: GlobOptions = {},\n): number {\n  let removedCount = 0;\n  const [dirPath, fileName] = splitPath(filePathGlobExpr);\n\n  const dirs = dirPath ? globDirs(result, dirPath) : [['', result] as const];\n  for (let [, dir] of dirs) {\n    const files = globFiles(dir, fileName, globOptions, '.');\n    for (let [, file] of files) {\n      dir.files.splice(dir.files.indexOf(file), 1);\n      removedCount += 1;\n    }\n  }\n\n  return removedCount;\n}\n\n/**\n * 从结果中移除一些目录\n * @param result 出码结果目录\n * @param dirPathGlobExpr 要移除的目录路径（glob 表达式）\n * @param globOptions glob 参数\n * @returns 移除了多少文件\n */\nexport function removeDirsFromResult(\n  result: ResultDir,\n  dirPathGlobExpr: string,\n  globOptions: GlobOptions = {},\n): number {\n  let removedCount = 0;\n  const [dirPath, fileName] = splitPath(dirPathGlobExpr);\n\n  const dirs = dirPath ? globDirs(result, dirPath) : [['', result] as const];\n  for (let [, dir] of dirs) {\n    const foundDirs = globDirs(dir, fileName, globOptions, '.');\n    for (let [, foundDir] of foundDirs) {\n      dir.dirs.splice(dir.dirs.indexOf(foundDir), 1);\n      removedCount += 1;\n    }\n  }\n\n  return removedCount;\n}\n\n/**\n * 将文件路径拆分为目录路径和文件名\n * @param filePath\n * @returns [fileDirPath, fileName]\n */\nfunction splitPath(filePath: string) {\n  const parts = filePath.split('/');\n  const fileName = parts.pop() || '';\n  return [joinPath(...parts), fileName];\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/schema.ts",
    "content": "import * as _ from 'lodash';\nimport {\n  IPublicTypeJSExpression,\n  IPublicTypeNodeData,\n  IPublicTypeNodeSchema,\n  isJSExpression,\n  isJSSlot,\n  isDOMText,\n  IPublicTypeContainerSchema,\n  IPublicTypeNpmInfo,\n  IPublicTypeCompositeValue,\n  isNodeSchema,\n  isJSFunction,\n} from '@alilc/lowcode-types';\nimport { CodeGeneratorError } from '../types/error';\nimport { isJSExpressionFn } from './common';\n\nexport function isContainerSchema(x: any): x is IPublicTypeContainerSchema {\n  return (\n    typeof x === 'object' &&\n    x &&\n    typeof x.componentName === 'string' &&\n    typeof x.fileName === 'string'\n  );\n}\n\nexport function isNpmInfo(x: any): x is IPublicTypeNpmInfo {\n  return typeof x === 'object' && x && typeof x.package === 'string';\n}\n\nconst noop = () => undefined;\n\nconst handleChildrenDefaultOptions = {\n  rerun: false,\n};\n\nconst DEFAULT_MAX_DEPTH = 100000;\n\n/**\n * 遍历并处理所有的子节点\n * @param children\n * @param handlers\n * @param options\n * @returns\n */\nexport function handleSubNodes<T>(\n  children: IPublicTypeNodeSchema['children'],\n  handlers: {\n    string?: (i: string) => T;\n    expression?: (i: IPublicTypeJSExpression) => T;\n    node?: (i: IPublicTypeNodeSchema) => T;\n  },\n  options?: {\n    rerun?: boolean;\n    maxDepth?: number; // 防止出现死循环无穷递归\n  },\n): T[] {\n  const opt = {\n    ...handleChildrenDefaultOptions,\n    ...(options || {}),\n  };\n  const maxDepth = opt.maxDepth ?? DEFAULT_MAX_DEPTH;\n  if (maxDepth <= 0) {\n    throw new Error('handleSubNodes maxDepth reached');\n  }\n\n  if (Array.isArray(children)) {\n    const list: IPublicTypeNodeData[] = children as IPublicTypeNodeData[];\n    return list\n      .map((child) => handleSubNodes(child, handlers, { ...opt, maxDepth: maxDepth - 1 }))\n      .reduce((p, c) => p.concat(c), []);\n  }\n\n  let result: T | undefined;\n  const childrenRes: T[] = [];\n  if (children === null || children === undefined) {\n    return [];\n  } else if (isDOMText(children)) {\n    const handler = handlers.string || noop;\n    result = handler(children);\n  } else if (isJSExpression(children)) {\n    const handler = handlers.expression || noop;\n    result = handler(children);\n  } else if (isJSSlot(children)) {\n    return handleSubNodes(children.value, handlers, { ...opt, maxDepth: maxDepth - 1 });\n  } else if (isNodeSchema(children)) {\n    const handler = handlers.node || noop;\n    const child = children as IPublicTypeNodeSchema;\n    result = handler(child);\n\n    if (child.children) {\n      const childRes = handleSubNodes(child.children, handlers, opt);\n      childrenRes.push(...childRes);\n    }\n\n    if (child.props) {\n      if (Array.isArray(child.props)) {\n        child.props.forEach(({ value }) => {\n          const childRes = handleCompositeValueInProps(value);\n          childrenRes.push(...childRes);\n        });\n      } else {\n        Object.values(child.props).forEach((value) => {\n          const childRes = handleCompositeValueInProps(value as IPublicTypeCompositeValue);\n          childrenRes.push(...childRes);\n        });\n      }\n    }\n  } else {\n    throw new CodeGeneratorError('handleSubNodes got invalid NodeData', children);\n  }\n\n  if (result !== undefined) {\n    childrenRes.unshift(result);\n  }\n\n  return childrenRes;\n\n  function handleCompositeValueInProps(value: IPublicTypeCompositeValue): T[] {\n    if (isJSSlot(value)) {\n      return handleSubNodes(value.value, handlers, { ...opt, maxDepth: maxDepth - 1 });\n    }\n\n    // CompositeArray\n    if (Array.isArray(value)) {\n      return _.flatMap(value, (v) => handleCompositeValueInProps(v));\n    }\n\n    // IPublicTypeCompositeObject\n    if (\n      !isJSExpression(value) &&\n      !isJSExpressionFn(value) &&\n      !isJSFunction(value) &&\n      typeof value === 'object' &&\n      value !== null\n    ) {\n      return _.flatMap(Object.values(value), (v) => handleCompositeValueInProps(v));\n    }\n\n    return [];\n  }\n}\n\nexport function isValidContainerType(schema: IPublicTypeNodeSchema) {\n  return [\n    'Page',\n    'Component',\n    'Block',\n  ].includes(schema.componentName);\n}\n\nexport const enum ContainerType {\n  Page = 'Page',\n  Component = 'Component',\n  Block = 'Block',\n}"
  },
  {
    "path": "modules/code-generator/src/utils/templateHelper.ts",
    "content": "import { ResultDir, ResultFile } from '@alilc/lowcode-types';\nimport { createResultDir, addDirectory, addFile } from './resultHelper';\n\ntype FuncFileGenerator = () => [string[], ResultFile];\n\nexport function insertFile(root: ResultDir, path: string[], file: ResultFile) {\n  let current: ResultDir = root;\n  path.forEach((pathNode) => {\n    const dir = current.dirs.find((d) => d.name === pathNode);\n    if (dir) {\n      current = dir;\n    } else {\n      const newDir = createResultDir(pathNode);\n      addDirectory(current, newDir);\n      current = newDir;\n    }\n  });\n\n  addFile(current, file);\n}\n\nexport function runFileGenerator(root: ResultDir, fun: FuncFileGenerator) {\n  try {\n    const result = fun();\n    const [path, file] = result;\n    insertFile(root, path, file);\n  } catch (error) {\n    throw new Error(`Error: ${typeof fun}`);\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/src/utils/theme.ts",
    "content": "/**\n * 获取主题信息\n * @param theme theme 形如 @alife/theme-97 或者 @alife/theme-97@^1.0.0\n */\n\nexport interface ThemeInfo {\n  name: string;\n  version?: string;\n}\n\nexport function getThemeInfo(theme: string): ThemeInfo {\n  const sepIdx = theme.indexOf('@', 1);\n  if (sepIdx === -1) {\n    return { name: theme };\n  }\n  return {\n    name: theme.slice(0, sepIdx),\n    version: theme.slice(sepIdx + 1),\n  };\n}"
  },
  {
    "path": "modules/code-generator/src/utils/validate.ts",
    "content": "export const isValidIdentifier = (name: string) => {\n  return /^[_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*$/.test(name);\n};\n\nexport const isValidComponentName = (name: string) => {\n  return /^[_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF.]*$/.test(name);\n};\n\nexport const ensureValidClassName = (name: string) => {\n  if (!isValidIdentifier(name)) {\n    return `$${name.replace(/[^_$a-zA-Z0-9]/g, '')}`;\n  }\n  return name;\n};\n"
  },
  {
    "path": "modules/code-generator/src/utils/version.ts",
    "content": "import semver from 'semver';\n\nexport function calcCompatibleVersion(v1: string | undefined | null, v2: string | undefined | null): string {\n  if (!v1 && !v2) {\n    return '*';\n  }\n\n  if (!v1 || v1 === '*') {\n    return v2 || '*';\n  }\n\n  if (!v2 || v2 === '*') {\n    return v1;\n  }\n\n  if (v1 === v2) {\n    return v1;\n  }\n\n  if (!semver.intersects(v1, v2, { loose: true })) {\n    throw new Error(`no compatible versions for \"${v1}\" and \"${v2}\"`);\n  }\n\n  if (semver.subset(v1, v2, { loose: true })) {\n    return v1;\n  }\n\n  return v2;\n}\n"
  },
  {
    "path": "modules/code-generator/standalone/index.js",
    "content": "/* eslint-disable @typescript-eslint/no-require-imports */\nif (process.env.NODE_ENV !== 'development') {\n  module.exports = require('../dist/standalone.min');\n} else {\n  module.exports = require('../dist/standalone');\n}\n"
  },
  {
    "path": "modules/code-generator/standalone/package.json",
    "content": "{\n  \"internal\": true,\n  \"main\": \"./index.js\",\n  \"types\": \"../types/standalone.d.ts\"\n}\n"
  },
  {
    "path": "modules/code-generator/standalone-loader/index.js",
    "content": "/* eslint-disable @typescript-eslint/no-require-imports */\nmodule.exports = require('../dist/standalone-loader');\n"
  },
  {
    "path": "modules/code-generator/standalone-loader/package.json",
    "content": "{\n  \"internal\": true,\n  \"main\": \"../dist/standalone-loader.js\",\n  \"module\": \"../dist/standalone-loader.esm.js\",\n  \"types\": \"../types/standalone-loader.d.ts\"\n}\n"
  },
  {
    "path": "modules/code-generator/standalone-worker/index.js",
    "content": "/* eslint-disable @typescript-eslint/no-require-imports */\nif (process.env.NODE_ENV !== 'development') {\n  module.exports = require('../dist/standalone-worker.min');\n} else {\n  module.exports = require('../dist/standalone-worker');\n}\n"
  },
  {
    "path": "modules/code-generator/standalone-worker/package.json",
    "content": "{\n  \"internal\": true,\n  \"main\": \"./index.js\",\n  \"types\": \"../lib/standalone-worker.d.ts\"\n}\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/.eslintignore.template",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/.eslintrc.js.template",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/.gitignore.template",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/static-files/rax/.prettierignore.template",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/.prettierrc.js.template",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/.stylelintignore.template",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/.stylelintrc.js.template",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/README.md.template",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/jsconfig.json.template",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/static-files/rax/tsconfig.json.template",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}"
  },
  {
    "path": "modules/code-generator/tests/bugfix/.gitignore",
    "content": "*.generated\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/i18n-with-params.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"react-greetings\",\n      \"version\": \"1.0.0\",\n      \"componentName\": \"Greetings\",\n      \"exportName\": \"Greetings\",\n      \"destructuring\": true\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_ocl137q7oc1\",\n      \"fileName\": \"test\",\n      \"props\": { \"style\": {} },\n      \"lifeCycles\": {},\n      \"dataSource\": { \"list\": [] },\n      \"state\": {\n        \"name\": \"lowcode world\"\n      },\n      \"methods\": {},\n      \"children\": [\n        {\n          \"componentName\": \"Greetings\",\n          \"id\": \"node_ocl137q7oc4\",\n          \"props\": {\n            \"content\": {\n              \"type\": \"i18n\",\n              \"key\": \"greetings.hello\",\n              \"params\": {\n                \"name\": {\n                  \"type\": \"JSExpression\",\n                  \"value\": \"this.state.name\"\n                }\n              }\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"i18n\": {\n    \"zh-CN\": {\n      \"greetings.hello\": \"${name}, 你好！\"\n    },\n    \"en-US\": {\n      \"greetings.hello\": \"Hello, ${name}!\"\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/i18n-with-params.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\nconst inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\nconst outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n\njest.setTimeout(60 * 60 * 1000);\n\ndescribe(testCaseBaseName, () => {\n  test('default import', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {});\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain(\n      `\n        <Greetings\n          content={this._i18nText({\n            key: 'greetings.hello',\n            params: { name: this.state.name },\n          })}\n        />\n      `.trim(),\n    );\n  });\n});\n\nfunction exportProject(\n  importPath: string,\n  outputPath: string,\n  mergeSchema?: Partial<IPublicTypeProjectSchema>,\n) {\n  const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });\n  const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };\n  const builder = CodeGenerator.solutions.icejs({ tolerateEvalErrors: false });\n\n  return builder.generateProject(schema).then(async (result) => {\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n\nfunction readOutputTextFile(outputFilePath: string): string {\n  return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-import-wrong-naming.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"example-package\",\n      \"version\": \"1.2.3\",\n      \"exportName\": \"Bar\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": false,\n      \"subName\": \"\",\n      \"componentName\": \"Foo\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_ocl137q7oc1\",\n      \"fileName\": \"test\",\n      \"props\": { \"style\": {} },\n      \"lifeCycles\": {},\n      \"dataSource\": { \"list\": [] },\n      \"state\": {},\n      \"methods\": {},\n      \"children\": [\n        {\n          \"componentName\": \"Foo\",\n          \"id\": \"node_ocl137q7oc4\",\n          \"props\": {}\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-import-wrong-naming.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\nconst inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\nconst outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n\njest.setTimeout(60 * 60 * 1000);\n\ndescribe(testCaseBaseName, () => {\n  test('default import', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Bar',\n          main: 'lib/index.js',\n          destructuring: false,\n          subName: '',\n          componentName: 'Foo',\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain('import Foo from \\'example-package/lib/index.js\\';');\n  });\n\n  test('named import with no alias', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Foo',\n          main: 'lib/index.js',\n          destructuring: true,\n          subName: '',\n          componentName: 'Foo',\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain(\n      'import { Foo } from \\'example-package/lib/index.js\\';',\n    );\n  });\n\n  test('named import with alias', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Bar',\n          main: 'lib/index.js',\n          destructuring: true,\n          subName: '',\n          componentName: 'Foo',\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain(\n      'import { Bar as Foo } from \\'example-package/lib/index.js\\';',\n    );\n  });\n\n  test('default import with same name', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Foo',\n          main: 'lib/index.js',\n          destructuring: false,\n          subName: '',\n          componentName: 'Foo',\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain('import Foo from \\'example-package/lib/index.js\\';');\n  });\n\n  test('default import with sub name and export name', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Bar',\n          main: 'lib/index.js',\n          destructuring: false,\n          subName: 'Baz',\n          componentName: 'Foo',\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain('import Bar from \\'example-package/lib/index.js\\';');\n\n    expect(generatedPageFileContent).toContain('const Foo = Bar.Baz;');\n  });\n\n  test('default import with sub name without export name', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          main: 'lib/index.js',\n          destructuring: false,\n          exportName: '',\n          subName: 'Baz',\n          componentName: 'Foo',\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain(\n      'import __$examplePackage_default from \\'example-package/lib/index.js\\';',\n    );\n\n    expect(generatedPageFileContent).toContain('const Foo = __$examplePackage_default.Baz;');\n  });\n\n  test('named import with sub name', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Bar',\n          main: 'lib/index.js',\n          destructuring: true,\n          subName: 'Baz',\n          componentName: 'Foo',\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain(\n      'import { Bar } from \\'example-package/lib/index.js\\';',\n    );\n\n    expect(generatedPageFileContent).toContain('const Foo = Bar.Baz;');\n  });\n\n  test('default imports with different componentName', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {\n      componentsMap: [\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Bar',\n          destructuring: false,\n          componentName: 'Foo',\n        },\n        {\n          package: 'example-package',\n          version: '1.2.3',\n          exportName: 'Bar',\n          destructuring: false,\n          componentName: 'Baz',\n        },\n      ],\n      componentsTree: [\n        {\n          componentName: 'Page',\n          fileName: 'test',\n          dataSource: { list: [] },\n          children: [{ componentName: 'Foo' }, { componentName: 'Baz' }],\n        },\n      ],\n    });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).toContain('import Foo from \\'example-package\\';');\n    expect(generatedPageFileContent).toContain('import Baz from \\'example-package\\';');\n\n    expect(generatedPageFileContent).not.toContain('const Foo =');\n    expect(generatedPageFileContent).not.toContain('const Baz =');\n  });\n});\n\nfunction exportProject(\n  importPath: string,\n  outputPath: string,\n  mergeSchema?: Partial<IPublicTypeProjectSchema>,\n) {\n  const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });\n  const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };\n  const builder = CodeGenerator.solutions.icejs();\n\n  return builder.generateProject(schema).then(async (result) => {\n    // displayResultInConsole(result);\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n\nfunction readOutputTextFile(outputFilePath: string): string {\n  return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-js-function1.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Page\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Slot\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Text\",\n      \"componentName\": \"Typography.Text\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Button\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Button\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Modal\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Modal\"\n    },\n    {\n      \"destructuring\": true,\n      \"exportName\": \"AliAutoSearchSelect\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.69\",\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoSearchSelectDefault\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Item\",\n      \"componentName\": \"Form.Item\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Col\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Col\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Input\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Input\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Row\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Row\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Select\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Select\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Form\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextP\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Col\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextCol\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Row\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextRow\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"RowColContainer\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextRowColContainer\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"BlockCell\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlockCell\"\n    },\n    {\n      \"destructuring\": true,\n      \"exportName\": \"AliAutoSearchTable\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.69\",\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoSearchTableDefault\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlock\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"componentName\": \"NextPage\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"style\": {\n          \"height\": \"100%\"\n        }\n      },\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff;\\n}\",\n      \"lifeCycles\": {\n        \"constructor\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.__jp__init();\\n    this.initUrl();\\n  }\"\n        },\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    // this.initUserHeaders();\\n    this.statusDict = {\\n      0: {\\n        type: 'danger',\\n        text: '失败',\\n      },\\n      1: {\\n        type: 'success',\\n        text: '成功',\\n      },\\n      2: {\\n        type: 'default',\\n        text: '构建中',\\n      },\\n      3: {\\n        type: 'warning',\\n        text: '构建超时',\\n      },\\n    };\\n    this.statusOptions = Object.keys(this.statusDict).map(k => ({\\n      label: this.statusDict[k].text,\\n      value: k,\\n    }));\\n\\n    this.searchParams = {};\\n  }\"\n        },\n        \"componentDidUpdate\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(prevProps, prevState, snapshot) {}\"\n        },\n        \"componentWillUnmount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {}\"\n        }\n      },\n      \"methods\": {\n        \"__jp__init\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initRouter\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initDataSource\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initEnv\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initConfig\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initUtils\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initUziModel\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__registerModel\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__finishedFn\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"initUrl\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"initUserHeaders\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"fetchBuilds\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"userHandler\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"channelHandler\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(res) {\\n    const data = res.data.info.map(item => {\\n      const { id, channelId } = item;\\n      return {\\n        label: channelId,\\n        value: id,\\n      };\\n    });\\n    return data;\\n  }\"\n        },\n        \"renderStatus\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(status) {\\n    return this.statusDict[status]?.text || '暂无';\\n  }\"\n        },\n        \"getStatusColor\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(status) {\\n    return this.statusDict[status]?.type || 'default';\\n  }\"\n        },\n        \"getLinkText\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(record) {\\n    const { status } = record || {};\\n    if (status === 0) {\\n      return '查看错误信息';\\n    } else if (status === 1) {\\n      return '去下载';\\n    }\\n    return '查看详情';\\n  }\"\n        },\n        \"renderTime\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(time) {\\n    return time\\n      ? this.$utils.moment(time).format('YYYY-MM-DD HH:mm')\\n      : '暂无';\\n  }\"\n        },\n        \"onPageChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(pageIndex, pageSize) {\\n    this.setSearchParams({\\n      page: pageIndex,\\n      page_size: pageSize,\\n    });\\n    this.fetchBuilds();\\n  }\"\n        },\n        \"renderUser\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(creator) {\\n    return creator ? creator.user_name : '暂无';\\n  }\"\n        },\n        \"setSearchParams\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(params) {\\n    this.searchParams = {\\n      ...this.searchParams,\\n      ...params,\\n    };\\n  }\"\n        },\n        \"onFinish\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(values) {\\n    const formValues = Object.keys(values).reduce((pre, key) => {\\n      const value = values[key];\\n      if (value === undefined || value === null) {\\n        return pre;\\n      }\\n      return {\\n        ...pre,\\n        [key]: value,\\n      };\\n    }, {});\\n    this.setSearchParams(formValues);\\n    this.fetchBuilds();\\n  }\"\n        },\n        \"linkHandler\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(_, record) {\\n    console.log('debug record', record);\\n    if (record && record.result_url) {\\n      window.open(record.result_url);\\n      return;\\n    }\\n    if (record && record.error_info) {\\n      this.setState({\\n        errorVisible: true,\\n        errorInfo: record.error_info,\\n      });\\n      return;\\n    }\\n    if (record && record.status === 0) {\\n      this.$utils.message.error('暂无错误信息！');\\n      return;\\n    }\\n    this.$utils.message.info('暂无详情信息！');\\n  }\"\n        },\n        \"toNewPage\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.$router.push('/android/component_package/add');\\n  }\"\n        },\n        \"showErrorModal\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      errorVisible: true,\\n    });\\n  }\"\n        },\n        \"hideErrorModal\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      errorVisible: false,\\n    });\\n  }\"\n        }\n      },\n      \"hidden\": false,\n      \"title\": \"\",\n      \"isLocked\": false,\n      \"condition\": true,\n      \"conditionGroup\": \"\",\n      \"state\": {\n        \"page\": 1,\n        \"pageSize\": 10,\n        \"total\": 0,\n        \"builds\": [],\n        \"errorVisible\": false,\n        \"errorInfo\": \"\"\n      },\n      \"children\": [\n        {\n          \"componentName\": \"Modal\",\n          \"id\": \"node_ockxhcliuqd\",\n          \"props\": {\n            \"title\": \"错误信息\",\n            \"okText\": \"确认\",\n            \"cancelText\": \"取消\",\n            \"visible\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"this.state.errorVisible\",\n              \"mock\": true\n            },\n            \"closable\": true,\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"value\": [\n                {\n                  \"componentName\": \"Button\",\n                  \"id\": \"node_ockxhcliuqf\",\n                  \"props\": {\n                    \"type\": \"primary\",\n                    \"children\": \"确定\",\n                    \"__events\": {\n                      \"eventDataList\": [\n                        {\n                          \"type\": \"componentEvent\",\n                          \"name\": \"onClick\",\n                          \"relatedEventName\": \"hideErrorModal\"\n                        }\n                      ],\n                      \"eventList\": [\n                        {\n                          \"name\": \"onClick\",\n                          \"template\": \"onClick(event,${extParams}){\\n// 点击按钮时的回调\\nconsole.log('onClick', event);}\",\n                          \"disabled\": true\n                        }\n                      ]\n                    },\n                    \"onClick\": {\n                      \"type\": \"JSFunction\",\n                      \"value\": \"function(){this.hideErrorModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                    }\n                  },\n                  \"hidden\": false,\n                  \"title\": \"\",\n                  \"isLocked\": false,\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"loopArgs\": [\"\", \"\"]\n                }\n              ]\n            },\n            \"width\": \"720px\",\n            \"__events\": {\n              \"eventDataList\": [\n                {\n                  \"type\": \"componentEvent\",\n                  \"name\": \"onCancel\",\n                  \"relatedEventName\": \"hideErrorModal\"\n                }\n              ],\n              \"eventList\": [\n                {\n                  \"name\": \"afterClose\",\n                  \"templete\": \"onCancel(${extParams}){\\n// 完全关闭后的回调\\nconsole.log('afterClose');}\",\n                  \"disabled\": false\n                },\n                {\n                  \"name\": \"onCancel\",\n                  \"template\": \"onCancel(${extParams}){\\n// 点击遮罩层或右上角叉或取消按钮的回调\\nconsole.log('onCancel');}\",\n                  \"disabled\": true\n                },\n                {\n                  \"name\": \"onOk\",\n                  \"template\": \"onOk(${extParams}){\\n// 点击确定回调\\nconsole.log('onOk');}\",\n                  \"disabled\": false\n                }\n              ]\n            },\n            \"onCancel\": {\n              \"type\": \"JSFunction\",\n              \"value\": \"function(){this.hideErrorModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n            }\n          },\n          \"hidden\": true,\n          \"title\": \"\",\n          \"isLocked\": false,\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"loopArgs\": [\"\", \"\"],\n          \"children\": [\n            {\n              \"componentName\": \"Typography.Text\",\n              \"id\": \"node_ockxhcliuqg\",\n              \"props\": {\n                \"children\": {\n                  \"type\": \"JSExpression\",\n                  \"value\": \"this.state.errorInfo\",\n                  \"mock\": \"text\"\n                }\n              },\n              \"hidden\": false,\n              \"title\": \"\",\n              \"isLocked\": false,\n              \"condition\": true,\n              \"conditionGroup\": \"\",\n              \"loopArgs\": [\"\", \"\"]\n            }\n          ]\n        },\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ocko19zplh1\",\n          \"props\": {\n            \"columns\": 12,\n            \"headerDivider\": true,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": \"\",\n            \"headerProps\": {\n              \"background\": \"surface\"\n            },\n            \"footer\": \"\",\n            \"minHeight\": \"100vh\",\n            \"presetNav\": true,\n            \"presetAside\": true\n          },\n          \"title\": \"页面\",\n          \"hidden\": false,\n          \"isLocked\": false,\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockwq51blv16\",\n              \"props\": {\n                \"placeholderStyle\": {\n                  \"height\": \"100%\"\n                },\n                \"noPadding\": false,\n                \"noBorder\": false,\n                \"title\": \"\",\n                \"rowGap\": 20,\n                \"colGap\": 20,\n                \"background\": \"surface\",\n                \"layoutmode\": \"O\",\n                \"strict\": true,\n                \"colSpan\": 12,\n                \"rowSpan\": 1,\n                \"mode\": \"transparent\",\n                \"childTotalColumns\": 12\n              },\n              \"title\": \"区域\",\n              \"hidden\": false,\n              \"isLocked\": false,\n              \"condition\": true,\n              \"conditionGroup\": \"\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockxfuqtmx2\",\n                  \"props\": {\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1,\n                    \"mode\": \"procard\",\n                    \"isAutoContainer\": true,\n                    \"title\": \"\",\n                    \"childNum\": 2,\n                    \"childMode\": \"initial\"\n                  },\n                  \"hidden\": false,\n                  \"title\": \"\",\n                  \"isLocked\": false,\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextRowColContainer\",\n                      \"id\": \"node_ockxfuqtmx3\",\n                      \"props\": {\n                        \"rowGap\": 20,\n                        \"colGap\": 20,\n                        \"strict\": true\n                      },\n                      \"title\": \"行列容器\",\n                      \"hidden\": false,\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"NextRow\",\n                          \"id\": \"node_ockxfuqtmx4\",\n                          \"props\": {\n                            \"strict\": true\n                          },\n                          \"title\": \"行\",\n                          \"hidden\": false,\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"children\": [\n                            {\n                              \"componentName\": \"NextCol\",\n                              \"id\": \"node_ockxfuqtmx5\",\n                              \"props\": {\n                                \"colSpan\": 1,\n                                \"strict\": true\n                              },\n                              \"title\": \"列\",\n                              \"hidden\": false,\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"NextP\",\n                                  \"id\": \"node_ockxfuqxgd7c\",\n                                  \"props\": {\n                                    \"wrap\": false,\n                                    \"type\": \"body2\",\n                                    \"verAlign\": \"middle\",\n                                    \"textSpacing\": true,\n                                    \"align\": \"left\",\n                                    \"full\": true,\n                                    \"flex\": true\n                                  },\n                                  \"title\": \"段落\",\n                                  \"hidden\": false,\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Form\",\n                                      \"id\": \"node_ockxfuqxgd7d\",\n                                      \"props\": {\n                                        \"labelCol\": {\n                                          \"span\": 6\n                                        },\n                                        \"wrapperCol\": {\n                                          \"span\": 18\n                                        },\n                                        \"onFinish\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        },\n                                        \"name\": \"basic\",\n                                        \"__events\": {\n                                          \"eventDataList\": [\n                                            {\n                                              \"type\": \"componentEvent\",\n                                              \"name\": \"onFinish\",\n                                              \"relatedEventName\": \"onFinish\"\n                                            }\n                                          ],\n                                          \"eventList\": [\n                                            {\n                                              \"name\": \"onFinish\",\n                                              \"template\": \"onFinish(values,${extParams}){\\n// 提交表单且数据验证成功后回调事件\\nconsole.log('onFinish',values);}\",\n                                              \"disabled\": true\n                                            },\n                                            {\n                                              \"name\": \"onFinishFailed\",\n                                              \"template\": \"onFinishFailed({values,errorFields,outOfDate},${extParams}){\\n// 提交表单且数据验证失败后回调事件\\nconsole.log('onFinishFailed',values, errorFields, outOfDate);}\",\n                                              \"disabled\": false\n                                            },\n                                            {\n                                              \"name\": \"onFieldsChange\",\n                                              \"template\": \"onFieldsChange(changedFields,allFields,${extParams}){\\n// 字段更新时触发回调事件\\nconsole.log('onFieldsChange',changedFields,allFields);}\",\n                                              \"disabled\": false\n                                            },\n                                            {\n                                              \"name\": \"onValuesChange\",\n                                              \"template\": \"onValuesChange(changedValues,allValues,${extParams}){\\n// 字段值更新时触发回调事件\\nconsole.log('onValuesChange',changedValues,allValues);}\",\n                                              \"disabled\": false\n                                            }\n                                          ]\n                                        }\n                                      },\n                                      \"hidden\": false,\n                                      \"title\": \"\",\n                                      \"isLocked\": false,\n                                      \"condition\": true,\n                                      \"conditionGroup\": \"\",\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Row\",\n                                          \"id\": \"node_ockxfuqxgd82\",\n                                          \"props\": {},\n                                          \"hidden\": false,\n                                          \"title\": \"\",\n                                          \"isLocked\": false,\n                                          \"condition\": true,\n                                          \"conditionGroup\": \"\",\n                                          \"children\": [\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxfuqxgd83\",\n                                              \"props\": {\n                                                \"span\": 8\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxfuqtmx7e\",\n                                                  \"props\": {\n                                                    \"label\": \"渠道号\",\n                                                    \"name\": \"channel_id\"\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"AliAutoSearchSelectDefault\",\n                                                      \"id\": \"node_ockxfurh9p1\",\n                                                      \"props\": {\n                                                        \"type\": \"custom\",\n                                                        \"style\": {\n                                                          \"width\": \"100%\"\n                                                        },\n                                                        \"placeholder\": \"请搜索选择渠道号\",\n                                                        \"config\": {\n                                                          \"url\": {\n                                                            \"type\": \"JSExpression\",\n                                                            \"value\": \"this.channelUrl\"\n                                                          },\n                                                          \"searchKey\": \"search_param\",\n                                                          \"dataHandler\": {\n                                                            \"type\": \"JSFunction\",\n                                                            \"value\": \"function(){ return this.channelHandler.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                                          },\n                                                          \"method\": \"GET\"\n                                                        },\n                                                        \"init\": true\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\"\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            },\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxfuqxgd84\",\n                                              \"props\": {\n                                                \"span\": 8\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxfuqtmx7f\",\n                                                  \"props\": {\n                                                    \"label\": \"构建号\",\n                                                    \"name\": \"buildId\"\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"Input\",\n                                                      \"id\": \"node_ockxfuqxgd7\",\n                                                      \"props\": {\n                                                        \"placeholder\": \"请输入\"\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\",\n                                                      \"loopArgs\": [\"\", \"\"]\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            },\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxfuqxgd85\",\n                                              \"props\": {\n                                                \"span\": 8\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxfuqtmx7g\",\n                                                  \"props\": {\n                                                    \"label\": \"构建人\",\n                                                    \"name\": \"user_id\"\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"AliAutoSearchSelectDefault\",\n                                                      \"id\": \"node_ockxfuqxgdd\",\n                                                      \"props\": {\n                                                        \"type\": \"custom\",\n                                                        \"style\": {\n                                                          \"width\": \"100%\"\n                                                        },\n                                                        \"placeholder\": \"请搜索选择构建人\",\n                                                        \"config\": {\n                                                          \"url\": {\n                                                            \"type\": \"JSExpression\",\n                                                            \"value\": \"this.userUrl\"\n                                                          },\n                                                          \"searchKey\": \"q\",\n                                                          \"method\": \"GET\",\n                                                          \"dataHandler\": {\n                                                            \"type\": \"JSFunction\",\n                                                            \"value\": \"function(){ return this.userHandler.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                                          }\n                                                        }\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\"\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            }\n                                          ]\n                                        },\n                                        {\n                                          \"componentName\": \"Row\",\n                                          \"id\": \"node_ockxfuqxgd8o\",\n                                          \"props\": {\n                                            \"style\": {}\n                                          },\n                                          \"hidden\": false,\n                                          \"title\": \"\",\n                                          \"isLocked\": false,\n                                          \"condition\": true,\n                                          \"conditionGroup\": \"\",\n                                          \"children\": [\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxfuqxgd8p\",\n                                              \"props\": {\n                                                \"span\": 8\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxfuqtmx7h\",\n                                                  \"props\": {\n                                                    \"label\": \"构建状态\",\n                                                    \"name\": \"status\",\n                                                    \"style\": {\n                                                      \"marginBottom\": \"0\"\n                                                    }\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"Select\",\n                                                      \"id\": \"node_ockxfuqxgde\",\n                                                      \"props\": {\n                                                        \"style\": {},\n                                                        \"options\": {\n                                                          \"type\": \"JSExpression\",\n                                                          \"value\": \"this.statusOptions\"\n                                                        },\n                                                        \"allowClear\": true,\n                                                        \"placeholder\": \"请选择构建状态\"\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\"\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            },\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxfuqxgd8q\",\n                                              \"props\": {\n                                                \"span\": 16\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxfuqxgd7g\",\n                                                  \"props\": {\n                                                    \"wrapperCol\": {\n                                                      \"offset\": 6\n                                                    },\n                                                    \"style\": {\n                                                      \"textAlign\": \"right\",\n                                                      \"marginBottom\": \"0\"\n                                                    }\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"Button\",\n                                                      \"id\": \"node_ockxfuqxgd7h\",\n                                                      \"props\": {\n                                                        \"type\": \"primary\",\n                                                        \"children\": \"查看\",\n                                                        \"htmlType\": \"submit\"\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\"\n                                                    },\n                                                    {\n                                                      \"componentName\": \"Button\",\n                                                      \"id\": \"node_ockxfuqxgd7i\",\n                                                      \"props\": {\n                                                        \"style\": {\n                                                          \"marginLeft\": 20\n                                                        },\n                                                        \"children\": \"新增打包\",\n                                                        \"type\": \"link\",\n                                                        \"__events\": {\n                                                          \"eventDataList\": [\n                                                            {\n                                                              \"type\": \"componentEvent\",\n                                                              \"name\": \"onClick\",\n                                                              \"relatedEventName\": \"toNewPage\"\n                                                            }\n                                                          ],\n                                                          \"eventList\": [\n                                                            {\n                                                              \"name\": \"onClick\",\n                                                              \"template\": \"onClick(event,${extParams}){\\n// 点击按钮时的回调\\nconsole.log('onClick', event);}\",\n                                                              \"disabled\": true\n                                                            }\n                                                          ]\n                                                        },\n                                                        \"onClick\": {\n                                                          \"type\": \"JSFunction\",\n                                                          \"value\": \"function(){this.toNewPage.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                                        }\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\"\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            }\n                                          ]\n                                        }\n                                      ]\n                                    }\n                                  ]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                },\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockxfuqtmx7i\",\n                  \"props\": {\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1,\n                    \"mode\": \"procard\",\n                    \"isAutoContainer\": true,\n                    \"title\": \"\",\n                    \"childNum\": 2,\n                    \"childMode\": \"initial\"\n                  },\n                  \"hidden\": false,\n                  \"title\": \"\",\n                  \"isLocked\": false,\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextRowColContainer\",\n                      \"id\": \"node_ockxfuqtmx7j\",\n                      \"props\": {\n                        \"rowGap\": 20,\n                        \"colGap\": 20,\n                        \"strict\": true\n                      },\n                      \"title\": \"行列容器\",\n                      \"hidden\": false,\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"NextRow\",\n                          \"id\": \"node_ockxfuqtmx7k\",\n                          \"props\": {\n                            \"strict\": true\n                          },\n                          \"title\": \"行\",\n                          \"hidden\": false,\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"children\": [\n                            {\n                              \"componentName\": \"NextCol\",\n                              \"id\": \"node_ockxfuqtmx7l\",\n                              \"props\": {\n                                \"colSpan\": 1,\n                                \"strict\": true\n                              },\n                              \"title\": \"列\",\n                              \"hidden\": false,\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"NextP\",\n                                  \"id\": \"node_ockxg2pglu1t\",\n                                  \"props\": {\n                                    \"wrap\": false,\n                                    \"type\": \"body2\",\n                                    \"verAlign\": \"middle\",\n                                    \"textSpacing\": true,\n                                    \"align\": \"left\",\n                                    \"flex\": true\n                                  },\n                                  \"title\": \"段落\",\n                                  \"hidden\": false,\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"AliAutoSearchTableDefault\",\n                                      \"id\": \"node_ockxg2pglu1u\",\n                                      \"props\": {\n                                        \"rowKey\": \"key\",\n                                        \"dataSource\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.state.builds\"\n                                        },\n                                        \"columns\": [\n                                          {\n                                            \"title\": \"渠道号\",\n                                            \"dataIndex\": \"channelId\",\n                                            \"key\": \"name\"\n                                          },\n                                          {\n                                            \"title\": \"Job名称\",\n                                            \"dataIndex\": \"job_name\",\n                                            \"key\": \"age\"\n                                          },\n                                          {\n                                            \"title\": \"构建号\",\n                                            \"dataIndex\": \"buildId\",\n                                            \"key\": \"address\"\n                                          },\n                                          {\n                                            \"title\": \"版本号\",\n                                            \"dataIndex\": \"version\"\n                                          },\n                                          {\n                                            \"title\": \"组件\",\n                                            \"dataIndex\": \"components\"\n                                          },\n                                          {\n                                            \"title\": \"构建状态\",\n                                            \"dataIndex\": \"status\",\n                                            \"render\": {\n                                              \"type\": \"JSSlot\",\n                                              \"params\": [\"text\", \"record\", \"index\"],\n                                              \"value\": [\n                                                {\n                                                  \"componentName\": \"Typography.Text\",\n                                                  \"id\": \"node_ockxg2qmtb6\",\n                                                  \"props\": {\n                                                    \"children\": {\n                                                      \"type\": \"JSExpression\",\n                                                      \"value\": \"this.renderStatus(this.text)\",\n                                                      \"mock\": \"\"\n                                                    },\n                                                    \"type\": {\n                                                      \"type\": \"JSExpression\",\n                                                      \"value\": \"this.getStatusColor(this.text)\"\n                                                    }\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\"\n                                                }\n                                              ]\n                                            }\n                                          },\n                                          {\n                                            \"title\": \"构建时间\",\n                                            \"dataIndex\": \"create_time\",\n                                            \"render\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            }\n                                          },\n                                          {\n                                            \"title\": \"构建人\",\n                                            \"dataIndex\": \"creator\",\n                                            \"render\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){ return this.renderUser.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            }\n                                          },\n                                          {\n                                            \"title\": \"详情\",\n                                            \"dataIndex\": \"result_url\",\n                                            \"render\": {\n                                              \"type\": \"JSSlot\",\n                                              \"params\": [\"text\", \"record\", \"index\"],\n                                              \"value\": [\n                                                {\n                                                  \"componentName\": \"Button\",\n                                                  \"id\": \"node_ockxhavvl63\",\n                                                  \"props\": {\n                                                    \"type\": \"link\",\n                                                    \"children\": {\n                                                      \"type\": \"JSExpression\",\n                                                      \"value\": \"this.getLinkText(this.record)\",\n                                                      \"mock\": \"\"\n                                                    },\n                                                    \"__events\": {\n                                                      \"eventDataList\": [\n                                                        {\n                                                          \"type\": \"componentEvent\",\n                                                          \"name\": \"onClick\",\n                                                          \"relatedEventName\": \"linkHandler\",\n                                                          \"paramStr\": \"this.record\"\n                                                        }\n                                                      ],\n                                                      \"eventList\": [\n                                                        {\n                                                          \"name\": \"onClick\",\n                                                          \"template\": \"onClick(event,${extParams}){\\n// 点击按钮时的回调\\nconsole.log('onClick', event);}\",\n                                                          \"disabled\": true\n                                                        }\n                                                      ]\n                                                    },\n                                                    \"onClick\": {\n                                                      \"type\": \"JSFunction\",\n                                                      \"value\": \"function(){this.linkHandler.apply(this,Array.prototype.slice.call(arguments).concat([this.record])) }\"\n                                                    },\n                                                    \"style\": {\n                                                      \"paddingLeft\": \"0px\",\n                                                      \"paddingRight\": \"0px\"\n                                                    }\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\",\n                                                  \"loopArgs\": [\"\", \"\"]\n                                                }\n                                              ]\n                                            }\n                                          }\n                                        ],\n                                        \"actions\": [],\n                                        \"size\": \"small\",\n                                        \"pagination\": {\n                                          \"total\": {\n                                            \"type\": \"JSExpression\",\n                                            \"value\": \"this.state.total\"\n                                          },\n                                          \"defaultPageIndex\": {\n                                            \"type\": \"JSExpression\",\n                                            \"value\": \"this.state.page\"\n                                          },\n                                          \"defaultPageSize\": {\n                                            \"type\": \"JSExpression\",\n                                            \"value\": \"this.state.pageSize\"\n                                          },\n                                          \"onPageChange\": {\n                                            \"type\": \"JSFunction\",\n                                            \"value\": \"function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                          }\n                                        },\n                                        \"loading\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.state.LOADING_BUILD_LIST\"\n                                        }\n                                      },\n                                      \"hidden\": false,\n                                      \"title\": \"\",\n                                      \"isLocked\": false,\n                                      \"condition\": true,\n                                      \"conditionGroup\": \"\",\n                                      \"loopArgs\": [\"\", \"\"]\n                                    }\n                                  ]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                },\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockxhclely3\",\n                  \"props\": {\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1,\n                    \"mode\": \"procard\",\n                    \"isAutoContainer\": true,\n                    \"title\": \"\",\n                    \"childNum\": 2,\n                    \"childMode\": \"initial\",\n                    \"style\": {\n                      \"display\": \"none\"\n                    }\n                  },\n                  \"hidden\": false,\n                  \"title\": \"\",\n                  \"isLocked\": false,\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextRowColContainer\",\n                      \"id\": \"node_ockxhclely4\",\n                      \"props\": {\n                        \"rowGap\": 20,\n                        \"colGap\": 20,\n                        \"strict\": true\n                      },\n                      \"title\": \"行列容器\",\n                      \"hidden\": false,\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"NextRow\",\n                          \"id\": \"node_ockxhclely5\",\n                          \"props\": {\n                            \"strict\": true\n                          },\n                          \"title\": \"行\",\n                          \"hidden\": false,\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"children\": [\n                            {\n                              \"componentName\": \"NextCol\",\n                              \"id\": \"node_ockxhclely6\",\n                              \"props\": {\n                                \"colSpan\": 1,\n                                \"strict\": true\n                              },\n                              \"title\": \"列\",\n                              \"hidden\": false,\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"NextP\",\n                                  \"id\": \"node_ockxhclelya\",\n                                  \"props\": {\n                                    \"wrap\": false,\n                                    \"type\": \"body2\",\n                                    \"verAlign\": \"middle\",\n                                    \"textSpacing\": true,\n                                    \"align\": \"left\",\n                                    \"flex\": true\n                                  },\n                                  \"title\": \"段落\",\n                                  \"hidden\": false,\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Button\",\n                                      \"id\": \"node_ockxhclelyb\",\n                                      \"props\": {\n                                        \"type\": \"link\",\n                                        \"children\": \"链接按钮\"\n                                      },\n                                      \"hidden\": false,\n                                      \"title\": \"\",\n                                      \"isLocked\": false,\n                                      \"condition\": true,\n                                      \"conditionGroup\": \"\"\n                                    },\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ockxhclely14\",\n                                      \"props\": {\n                                        \"children\": \"text\"\n                                      },\n                                      \"hidden\": false,\n                                      \"title\": \"\",\n                                      \"isLocked\": false,\n                                      \"condition\": true,\n                                      \"conditionGroup\": \"\"\n                                    }\n                                  ]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-js-function1.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\n\ntest(testCaseBaseName, async () => {\n  const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\n  const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n  await exportProject(inputSchemaJsonFile, outputDir);\n\n  const generatedPageFileContent = fs.readFileSync(\n    path.join(outputDir, 'demo-project/src/pages/Test/index.jsx'),\n    'utf-8',\n  );\n  expect(generatedPageFileContent).toContain(`\n                                  onClick={function () {\n                                    this.linkHandler.apply(\n                                      this,\n                                      Array.prototype.slice\n                                        .call(arguments)\n                                        .concat([record])\n                                    );\n                                  }.bind(__$$context)}`);\n});\n\nfunction exportProject(inputPath: string, outputPath: string) {\n  const schemaJson = fs.readFileSync(inputPath, { encoding: 'utf8' });\n  const newSchema = schemaJson;\n  const builder = CodeGenerator.solutions.icejs();\n\n  return builder.generateProject(newSchema).then(async (result) => {\n    // displayResultInConsole(result);\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-missing-imports-1.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"destructuring\": true,\n      \"exportName\": \"AliAutoSearchSelect\",\n      \"main\": \"build/lowcode/index.js\",\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"^0.1.45\",\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoSearchSelectDefault\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Item\",\n      \"componentName\": \"Form.Item\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Col\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Col\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Select\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Select\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Button\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Button\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Row\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Row\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Form\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextP\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Col\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextCol\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Row\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextRow\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"RowColContainer\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextRowColContainer\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"BlockCell\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlockCell\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Text\",\n      \"componentName\": \"Typography.Text\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.17.0\",\n      \"exportName\": \"Tag\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Tag\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Slot\"\n    },\n    {\n      \"destructuring\": true,\n      \"exportName\": \"AliAutoSearchTable\",\n      \"main\": \"build/lowcode/index.js\",\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"^0.1.45\",\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoSearchTableDefault\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlock\"\n    },\n    {\n      \"package\": \"@alife/pro-layout\",\n      \"version\": \"^0.1.0\",\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"componentName\": \"NextPage\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Page\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"style\": {\n          \"height\": \"100%\"\n        }\n      },\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff;\\n}\",\n      \"lifeCycles\": {\n        \"constructor\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.__jp__init();\\n    this.initUrl();\\n    this.searchParams = {};\\n    this.channelTimer = null;\\n    this.currentChannel = null;\\n  }\"\n        },\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {}\"\n        },\n        \"componentWillUnmount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {}\"\n        }\n      },\n      \"methods\": {\n        \"__jp__init\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__initRouter\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__initDataSource\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__initEnv\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__initConfig\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__initUtils\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__initUziModel\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__registerModel\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"__jp__finishedFn\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"initUrl\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"channelHandler\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"fetchProjects\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"setSearchParams\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"onPageChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"renderName\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"renderPlatform\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(col) {\\n    return col.platform_name;\\n  }\"\n        },\n        \"renderTime\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(time) {\\n    if (time) {\\n      return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\\n    }\\n    return '暂无';\\n  }\"\n        },\n        \"onFinish\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"onSearchChannel\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(value) {\\n    this.fetchChannels(value);\\n  }\"\n        },\n        \"toNewAddPage\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"handlerModify\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"infoTip\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(msg) {\\n    this.$utils.message.info(msg);\\n  }\"\n        },\n        \"renderCreator\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        }\n      },\n      \"hidden\": false,\n      \"title\": \"\",\n      \"isLocked\": false,\n      \"condition\": true,\n      \"conditionGroup\": \"\",\n      \"state\": {\n        \"total\": 0,\n        \"projects\": [],\n        \"channelOpts\": [],\n        \"visible\": false\n      },\n      \"children\": [\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ocko19zplh1\",\n          \"props\": {\n            \"columns\": 12,\n            \"headerDivider\": true,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": \"\",\n            \"headerProps\": {\n              \"background\": \"surface\",\n              \"style\": {\n                \"padding\": \"\"\n              }\n            },\n            \"footer\": \"\",\n            \"minHeight\": \"100vh\",\n            \"contentProps\": {\n              \"noPadding\": false,\n              \"background\": \"transparent\"\n            },\n            \"presetNav\": true,\n            \"presetAside\": true\n          },\n          \"title\": \"页面\",\n          \"condition\": true,\n          \"hidden\": false,\n          \"isLocked\": false,\n          \"conditionGroup\": \"\",\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockwu5hu4r3\",\n              \"props\": {\n                \"placeholderStyle\": {\n                  \"height\": \"100%\"\n                },\n                \"noPadding\": false,\n                \"noBorder\": false,\n                \"title\": \"\",\n                \"rowGap\": 20,\n                \"colGap\": 20,\n                \"background\": \"surface\",\n                \"layoutmode\": \"O\",\n                \"strict\": true,\n                \"colSpan\": 12,\n                \"rowSpan\": 1,\n                \"mode\": \"transparent\",\n                \"childTotalColumns\": 12\n              },\n              \"title\": \"区域\",\n              \"hidden\": false,\n              \"isLocked\": false,\n              \"condition\": true,\n              \"conditionGroup\": \"\",\n              \"loopArgs\": [\"\", \"\"],\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockwu5hu4rj\",\n                  \"props\": {\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1,\n                    \"mode\": \"procard\",\n                    \"isAutoContainer\": true,\n                    \"title\": \"\",\n                    \"childNum\": 2,\n                    \"childMode\": \"initial\"\n                  },\n                  \"hidden\": false,\n                  \"title\": \"\",\n                  \"isLocked\": false,\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextRowColContainer\",\n                      \"id\": \"node_ockwu5hu4rk\",\n                      \"props\": {\n                        \"rowGap\": 20,\n                        \"colGap\": 20,\n                        \"strict\": true\n                      },\n                      \"title\": \"行列容器\",\n                      \"hidden\": false,\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"NextRow\",\n                          \"id\": \"node_ockwu5hu4rl\",\n                          \"props\": {\n                            \"strict\": true\n                          },\n                          \"title\": \"行\",\n                          \"hidden\": false,\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"children\": [\n                            {\n                              \"componentName\": \"NextCol\",\n                              \"id\": \"node_ockwu5hu4rm\",\n                              \"props\": {\n                                \"colSpan\": 1,\n                                \"strict\": true\n                              },\n                              \"title\": \"列\",\n                              \"hidden\": false,\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"],\n                              \"children\": [\n                                {\n                                  \"componentName\": \"NextP\",\n                                  \"id\": \"node_ockxie3rxc11g\",\n                                  \"props\": {\n                                    \"wrap\": false,\n                                    \"type\": \"body2\",\n                                    \"verAlign\": \"middle\",\n                                    \"textSpacing\": true,\n                                    \"align\": \"left\",\n                                    \"full\": true,\n                                    \"flex\": true\n                                  },\n                                  \"title\": \"段落\",\n                                  \"hidden\": false,\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Form\",\n                                      \"id\": \"node_ockxie3rxc11h\",\n                                      \"props\": {\n                                        \"labelCol\": {\n                                          \"span\": 6\n                                        },\n                                        \"wrapperCol\": {\n                                          \"span\": 18\n                                        },\n                                        \"onValuesChange\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"function() {\\n      const self = this;\\n      try {\\n        return (function onValuesChange(changedValues, allValues) {\\n  console.log('onValuesChange', changedValues, allValues);\\n}).apply(self, arguments);\\n      } catch(e) {\\n        console.log('call function which parsed by lowcode failed: ', e);\\n        return e.message;\\n      }\\n    }\"\n                                        },\n                                        \"onFinish\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"function() {\\n      const self = this;\\n      try {\\n        return (function onFinish(values) {\\n  console.log('onFinish', values);\\n}).apply(self, arguments);\\n      } catch(e) {\\n        console.log('call function which parsed by lowcode failed: ', e);\\n        return e.message;\\n      }\\n    }\"\n                                        },\n                                        \"onFinishFailed\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"function() {\\n      const self = this;\\n      try {\\n        return (function onFinishFailed({ values, errorFields, outOfDate }) {\\n  console.log('onFinishFailed', values, errorFields, outOfDate);\\n}).apply(self, arguments);\\n      } catch(e) {\\n        console.log('call function which parsed by lowcode failed: ', e);\\n        return e.message;\\n      }\\n    }\"\n                                        },\n                                        \"name\": \"basic\",\n                                        \"layout\": \"horizontal\"\n                                      },\n                                      \"hidden\": false,\n                                      \"title\": \"\",\n                                      \"isLocked\": false,\n                                      \"condition\": true,\n                                      \"conditionGroup\": \"\",\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Row\",\n                                          \"id\": \"node_ockxie3rxc11v\",\n                                          \"props\": {\n                                            \"align\": \"middle\",\n                                            \"gutter\": [0, 0],\n                                            \"h-gutter\": 0\n                                          },\n                                          \"hidden\": false,\n                                          \"title\": \"\",\n                                          \"isLocked\": false,\n                                          \"condition\": true,\n                                          \"conditionGroup\": \"\",\n                                          \"children\": [\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxie3rxc11w\",\n                                              \"props\": {\n                                                \"span\": 10\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxie3rxcq2\",\n                                                  \"props\": {\n                                                    \"label\": \"项目名称/渠道号\",\n                                                    \"labelAlign\": \"right\",\n                                                    \"colon\": true,\n                                                    \"name\": \"channel_id\",\n                                                    \"style\": {\n                                                      \"marginBottom\": \"0px\"\n                                                    }\n                                                  },\n                                                  \"condition\": true,\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"AliAutoSearchSelectDefault\",\n                                                      \"id\": \"node_ockxie4o9g2f\",\n                                                      \"props\": {\n                                                        \"type\": \"custom\",\n                                                        \"style\": {\n                                                          \"width\": \"100%\"\n                                                        },\n                                                        \"init\": true,\n                                                        \"placeholder\": \"请搜索选择项目名称/渠道号\",\n                                                        \"config\": {\n                                                          \"url\": {\n                                                            \"type\": \"JSExpression\",\n                                                            \"value\": \"this.channelUrl\"\n                                                          },\n                                                          \"searchKey\": \"search_param\",\n                                                          \"dataHandler\": {\n                                                            \"type\": \"JSFunction\",\n                                                            \"value\": \"function(){ return this.channelHandler.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                                          }\n                                                        },\n                                                        \"interval\": 300\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\"\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            },\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxie3rxc11x\",\n                                              \"props\": {\n                                                \"span\": 8\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxie3rxcpz\",\n                                                  \"props\": {\n                                                    \"label\": \"项目类型\",\n                                                    \"labelAlign\": \"right\",\n                                                    \"colon\": true,\n                                                    \"name\": \"project_type\",\n                                                    \"style\": {\n                                                      \"marginBottom\": \"0px\"\n                                                    }\n                                                  },\n                                                  \"condition\": true,\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"Select\",\n                                                      \"id\": \"node_ockxie3rxcq0\",\n                                                      \"props\": {\n                                                        \"style\": {},\n                                                        \"options\": [\n                                                          {\n                                                            \"label\": \"平台化项目\",\n                                                            \"value\": \"platform_adapter\"\n                                                          },\n                                                          {\n                                                            \"label\": \"纯适配项目\",\n                                                            \"value\": \"pure_adapter\"\n                                                          }\n                                                        ],\n                                                        \"defaultActiveFirstOption\": true,\n                                                        \"size\": \"middle\",\n                                                        \"bordered\": true,\n                                                        \"filterOption\": true,\n                                                        \"optionFilterProp\": \"value\",\n                                                        \"allowClear\": true,\n                                                        \"placeholder\": \"请选择项目类型\"\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\",\n                                                      \"loopArgs\": [\"\", \"\"]\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            },\n                                            {\n                                              \"componentName\": \"Col\",\n                                              \"id\": \"node_ockxie3rxc11y\",\n                                              \"props\": {\n                                                \"span\": 6,\n                                                \"style\": {\n                                                  \"textAlign\": \"right\"\n                                                }\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\",\n                                              \"children\": [\n                                                {\n                                                  \"componentName\": \"Form.Item\",\n                                                  \"id\": \"node_ockxie3rxcq5\",\n                                                  \"props\": {\n                                                    \"wrapperCol\": {\n                                                      \"offset\": 6\n                                                    },\n                                                    \"style\": {\n                                                      \"marginBottom\": \"0px\"\n                                                    }\n                                                  },\n                                                  \"hidden\": false,\n                                                  \"title\": \"\",\n                                                  \"isLocked\": false,\n                                                  \"condition\": true,\n                                                  \"conditionGroup\": \"\",\n                                                  \"children\": [\n                                                    {\n                                                      \"componentName\": \"Button\",\n                                                      \"id\": \"node_ockxie3rxcq6\",\n                                                      \"props\": {\n                                                        \"type\": \"primary\",\n                                                        \"children\": \"查询\",\n                                                        \"htmlType\": \"submit\",\n                                                        \"shape\": \"default\",\n                                                        \"size\": \"middle\",\n                                                        \"block\": false\n                                                      },\n                                                      \"condition\": true,\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"conditionGroup\": \"\"\n                                                    },\n                                                    {\n                                                      \"componentName\": \"Button\",\n                                                      \"id\": \"node_ockwu5hu4ri\",\n                                                      \"props\": {\n                                                        \"type\": \"link\",\n                                                        \"children\": \"新增项目\",\n                                                        \"htmlType\": \"button\",\n                                                        \"shape\": \"default\",\n                                                        \"size\": \"middle\",\n                                                        \"__events\": {\n                                                          \"eventDataList\": [\n                                                            {\n                                                              \"type\": \"componentEvent\",\n                                                              \"name\": \"onClick\",\n                                                              \"relatedEventName\": \"toNewAddPage\"\n                                                            }\n                                                          ],\n                                                          \"eventList\": [\n                                                            {\n                                                              \"name\": \"onClick\",\n                                                              \"templete\": \"onClick(${extParams}){\\n// 点击按钮时的回调\\nconsole.log('onClick');}\",\n                                                              \"disabled\": true\n                                                            }\n                                                          ]\n                                                        },\n                                                        \"onClick\": {\n                                                          \"type\": \"JSFunction\",\n                                                          \"value\": \"function(){this.toNewAddPage.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                                        },\n                                                        \"style\": {\n                                                          \"marginLeft\": \"16px\"\n                                                        }\n                                                      },\n                                                      \"hidden\": false,\n                                                      \"title\": \"\",\n                                                      \"isLocked\": false,\n                                                      \"condition\": true,\n                                                      \"conditionGroup\": \"\"\n                                                    }\n                                                  ]\n                                                }\n                                              ]\n                                            }\n                                          ]\n                                        }\n                                      ]\n                                    }\n                                  ]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                },\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockxie3rxc1\",\n                  \"props\": {\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1,\n                    \"mode\": \"procard\",\n                    \"isAutoContainer\": true,\n                    \"title\": \"\",\n                    \"childNum\": 2,\n                    \"childMode\": \"initial\"\n                  },\n                  \"hidden\": false,\n                  \"title\": \"\",\n                  \"isLocked\": false,\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextRowColContainer\",\n                      \"id\": \"node_ockxie3rxc2\",\n                      \"props\": {\n                        \"rowGap\": 20,\n                        \"colGap\": 20,\n                        \"strict\": true\n                      },\n                      \"title\": \"行列容器\",\n                      \"hidden\": false,\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"NextRow\",\n                          \"id\": \"node_ockxie3rxc3\",\n                          \"props\": {\n                            \"strict\": true\n                          },\n                          \"title\": \"行\",\n                          \"hidden\": false,\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"children\": [\n                            {\n                              \"componentName\": \"NextCol\",\n                              \"id\": \"node_ockxie3rxc4\",\n                              \"props\": {\n                                \"colSpan\": 1,\n                                \"strict\": true\n                              },\n                              \"title\": \"列\",\n                              \"hidden\": false,\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"AliAutoSearchTableDefault\",\n                                  \"id\": \"node_ockxie3rxc5\",\n                                  \"props\": {\n                                    \"rowKey\": \"key\",\n                                    \"dataSource\": {\n                                      \"type\": \"JSExpression\",\n                                      \"value\": \"this.state.projects\"\n                                    },\n                                    \"columns\": [\n                                      {\n                                        \"title\": \"项目名称\",\n                                        \"dataIndex\": \"project_name\",\n                                        \"key\": \"name\"\n                                      },\n                                      {\n                                        \"title\": \"代码名称\",\n                                        \"dataIndex\": \"coding_name\",\n                                        \"key\": \"address\"\n                                      },\n                                      {\n                                        \"title\": \"项目类型\",\n                                        \"dataIndex\": \"project_type\",\n                                        \"render\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){ return this.renderName.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        }\n                                      },\n                                      {\n                                        \"title\": \"渠道号\",\n                                        \"dataIndex\": \"channelId\",\n                                        \"render\": {\n                                          \"type\": \"JSSlot\",\n                                          \"params\": [\"text\", \"record\", \"index\"],\n                                          \"value\": [\n                                            {\n                                              \"componentName\": \"Typography.Text\",\n                                              \"id\": \"node_ockxijxx0a3\",\n                                              \"props\": {\n                                                \"children\": \"text\"\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\"\n                                            },\n                                            {\n                                              \"componentName\": \"Tag\",\n                                              \"id\": \"node_ockxijxwe42\",\n                                              \"props\": {\n                                                \"color\": \"magenta\",\n                                                \"children\": {\n                                                  \"type\": \"JSExpression\",\n                                                  \"value\": \"this.text\",\n                                                  \"mock\": \"tag\"\n                                                }\n                                              },\n                                              \"hidden\": false,\n                                              \"title\": \"\",\n                                              \"isLocked\": false,\n                                              \"condition\": true,\n                                              \"conditionGroup\": \"\"\n                                            }\n                                          ]\n                                        }\n                                      },\n                                      {\n                                        \"title\": \"更新时间\",\n                                        \"dataIndex\": \"update_time\",\n                                        \"render\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        },\n                                        \"width\": 160\n                                      },\n                                      {\n                                        \"title\": \"操作人\",\n                                        \"dataIndex\": \"creator\",\n                                        \"width\": 90,\n                                        \"render\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){ return this.renderCreator.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        }\n                                      }\n                                    ],\n                                    \"actions\": [\n                                      {\n                                        \"text\": \"修改\",\n                                        \"needConfirm\": false,\n                                        \"handler\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){ return this.handlerModify.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        }\n                                      }\n                                    ],\n                                    \"isPagination\": true,\n                                    \"pagination\": {\n                                      \"defaultPageIndex\": 1,\n                                      \"defaultPageSize\": 10,\n                                      \"total\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.state.total\"\n                                      },\n                                      \"onPageChange\": {\n                                        \"type\": \"JSFunction\",\n                                        \"value\": \"function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                      }\n                                    },\n                                    \"size\": \"small\",\n                                    \"loading\": {\n                                      \"type\": \"JSExpression\",\n                                      \"value\": \"this.state.LOADING_PROJECTS\"\n                                    }\n                                  },\n                                  \"condition\": true,\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-missing-imports-1.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\n\ntest(testCaseBaseName, async () => {\n  const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\n  const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n  await exportProject(inputSchemaJsonFile, outputDir);\n\n  const generatedPageFileContent = fs.readFileSync(\n    path.join(outputDir, 'demo-project/src/pages/Test/index.jsx'),\n    'utf-8',\n  );\n  expect(generatedPageFileContent).toContain(`import {\n  Form,\n  Row,\n  Col,\n  Select,\n  Button,\n  Typography,\n  Tag,\n} from '@alilc/antd-lowcode-materials/dist/antd-lowcode.esm.js';`);\n});\n\nfunction exportProject(inputPath: string, outputPath: string) {\n  const schemaJson = fs.readFileSync(inputPath, { encoding: 'utf8' });\n  const newSchema = schemaJson;\n  const builder = CodeGenerator.solutions.icejs();\n\n  return builder.generateProject(newSchema).then(async (result) => {\n    // displayResultInConsole(result);\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-package-json-dependencies.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"@alilc/lowcode-materials\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Page\",\n      \"destructuring\": true,\n      \"componentName\": \"Page\"\n    },\n    {\n      \"package\": \"@alilc/lowcode-materials\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Typography\",\n      \"destructuring\": true,\n      \"subName\": \"Text\",\n      \"componentName\": \"Text\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {},\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": [\n          {\n            \"id\": \"test\",\n            \"type\": \"fetch\",\n            \"options\": {\n              \"uri\": \"https://xxx.com/api/xxx\"\n            }\n          }\n        ]\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff;\\n}\",\n      \"lifeCycles\": {},\n\n      \"hidden\": false,\n      \"title\": \"\",\n      \"isLocked\": false,\n      \"condition\": true,\n      \"conditionGroup\": \"\",\n      \"state\": {},\n      \"children\": [\n        {\n          \"componentName\": \"Text\",\n          \"props\": {\n            \"text\": \"hello world\"\n          }\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-package-json-dependencies.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\n\ntest(testCaseBaseName, async () => {\n  const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\n  const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n  await exportProject(inputSchemaJsonFile, outputDir);\n\n  const generatedPackageJsonText = fs.readFileSync(\n    path.join(outputDir, 'demo-project/package.json'),\n    'utf-8',\n  );\n  const generatedPackageJson = JSON.parse(generatedPackageJsonText);\n  expect(generatedPackageJson.dependencies).toBeTruthy();\n\n  // 里面有的数据源则应该生成对应的 dependencies\n  expect(generatedPackageJson.dependencies).toMatchObject({\n    '@alilc/lowcode-datasource-engine': '^1.0.0',\n    '@alilc/lowcode-datasource-fetch-handler': '^1.0.0',\n  });\n\n  // 里面没有的，则不应该生成对应的 dependencies\n  expect(generatedPackageJson.dependencies).not.toMatchObject({\n    '@alilc/lowcode-datasource-url-params-handler': '^1.0.0',\n    '@alilc/lowcode-datasource-mtop-handler': '^1.0.0',\n    '@alilc/lowcode-datasource-mopen-handler': '^1.0.0',\n  });\n});\n\nfunction exportProject(inputPath: string, outputPath: string) {\n  const schemaJson = fs.readFileSync(inputPath, { encoding: 'utf8' });\n  const newSchema = schemaJson;\n  const builder = CodeGenerator.solutions.icejs();\n\n  return builder.generateProject(newSchema).then(async (result) => {\n    // displayResultInConsole(result);\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-page-map1.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Page\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.18.0\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Text\",\n      \"componentName\": \"Text\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {},\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff;\\n}\",\n      \"lifeCycles\": {},\n\n      \"hidden\": false,\n      \"title\": \"\",\n      \"isLocked\": false,\n      \"condition\": true,\n      \"conditionGroup\": \"\",\n      \"state\": {},\n      \"children\": [\n        {\n          \"componentName\": \"Text\",\n          \"props\": {\n            \"text\": \"hello world\"\n          }\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/icejs-page-map1.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\n\ntest(testCaseBaseName, async () => {\n  const inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\n  const outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n  await exportProject(inputSchemaJsonFile, outputDir);\n\n  const generatedPageFileContent = fs.readFileSync(\n    path.join(outputDir, 'demo-project/src/pages/Test/index.jsx'),\n    'utf-8',\n  );\n  expect(generatedPageFileContent).toContain(`<div`);\n  expect(generatedPageFileContent).toContain(`</div>`);\n  expect(generatedPageFileContent).not.toContain(`import Page from \"undefined\";`);\n});\n\nfunction exportProject(inputPath: string, outputPath: string) {\n  const schemaJson = fs.readFileSync(inputPath, { encoding: 'utf8' });\n  const newSchema = schemaJson;\n  const builder = CodeGenerator.solutions.icejs();\n\n  return builder.generateProject(newSchema).then(async (result) => {\n    // displayResultInConsole(result);\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/page-element1.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Page\",\n      \"main\": \"\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"Page\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Image\",\n      \"main\": \"\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"Image\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Container\",\n      \"main\": \"\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"Container\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Slot\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Text\",\n      \"main\": \"\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"Text\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Link\",\n      \"main\": \"\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"Link\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Share\",\n      \"main\": \"\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"Share\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"DruidList\",\n      \"main\": \"\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"DruidList\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outerView\",\n        \"style\": {\n          \"height\": \"100%\"\n        },\n        \"isTransparentTitle\": true,\n        \"spmA\": \"a691\",\n        \"spmB\": \"b34649\",\n        \"spmBizType\": \"BAOXIAN\"\n      },\n      \"fileName\": \"/\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"lifeCycles\": {\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.utils.rpc('com.alipay.inslifeweb.channel.pilotpension.render', {\\n        showType: 4,\\n      })\\n      .then((result) => {\\n        this.setState({\\n          policyCount: result.policyCount,\\n          hasAuthorized: result.hasAuthorized\\n        });\\n      });\\n  }\"\n        }\n      },\n      \"hidden\": false,\n      \"title\": \"\",\n      \"isLocked\": false,\n      \"condition\": true,\n      \"conditionGroup\": \"\",\n      \"_insiopConfig\": {\n        \"sceneCode\": \"PILOT_PENSION_LANDING_PAGE\"\n      },\n      \"css\": \"body {\\n  background: #f5f5f9;\\n}\",\n      \"methods\": {\n        \"handleAuth\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      hasAuthorized: true,\\n    });\\n    \\n    this.utils.rpc('com.alipay.inslifeweb.agreement.index.authorize', {\\n      bizScene: 'PILOT_ENDOWMENT_CHANNEL_POLICY_AGREEMENT',\\n      agreementScene: '20',\\n    });\\n\\n    Tracert.click('c88773.d183217');\\n  }\"\n        }\n      },\n      \"state\": {\n        \"policyCount\": 0,\n        \"hasAuthorized\": false\n      },\n      \"children\": [\n        {\n          \"componentName\": \"DruidList\",\n          \"id\": \"node_ockwcyxpypb\",\n          \"props\": {\n            \"slotList\": [\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwnbkrje1e\",\n                      \"props\": {\n                        \"style\": {\n                          \"marginBottom\": \"16px\"\n                        },\n                        \"spmC\": \"c88756\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"loopArgs\": [\"\", \"\"],\n                      \"children\": [\n                        {\n                          \"componentName\": \"Image\",\n                          \"id\": \"node_ockwd01xqzc\",\n                          \"props\": {\n                            \"src\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.module.imgList[0].imgUrl\",\n                              \"mock\": \"https://img.alicdn.com/imgextra/i3/O1CN01eqyMv71N2XZXffFkv_!!6000000001512-2-tps-750-642.png\"\n                            },\n                            \"width\": \"100%\",\n                            \"style\": {\n                              \"display\": \"block\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"]\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"图片区块\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_PICTURE\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwdmjns334\",\n                      \"props\": {\n                        \"style\": {\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"marginTop\": \"0px\",\n                          \"borderRadius\": \"16px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginBottom\": \"16px\",\n                          \"paddingLeft\": \"20px\",\n                          \"paddingTop\": \"20px\",\n                          \"paddingRight\": \"20px\",\n                          \"paddingBottom\": \"20px\"\n                        },\n                        \"spmC\": \"c88773\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"已授权状态\",\n                      \"isLocked\": false,\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.state.policyCount > 0 && this.state.hasAuthorized\",\n                        \"mock\": true\n                      },\n                      \"conditionGroup\": \"\",\n                      \"loopArgs\": [\"\", \"\"],\n                      \"children\": [\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwkbudw48\",\n                          \"props\": {\n                            \"style\": {\n                              \"backgroundColor\": \"#fff\",\n                              \"marginRight\": \"0px\",\n                              \"display\": \"flex\",\n                              \"flexDirection\": \"row\",\n                              \"justifyContent\": \"space-between\",\n                              \"alignItems\": \"center\",\n                              \"borderBottomStyle\": \"solid\",\n                              \"borderBottomWidth\": \"0px\",\n                              \"borderBottomColor\": \"#9b9b9b\",\n                              \"marginBottom\": \"0px\",\n                              \"marginLeft\": \"0px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"condition\": true,\n                          \"children\": [\n                            {\n                              \"componentName\": \"Container\",\n                              \"id\": \"node_ockwkbudw49\",\n                              \"props\": {},\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"],\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Text\",\n                                  \"id\": \"node_ockwkbudw4a\",\n                                  \"props\": {\n                                    \"context\": \"我的保单\",\n                                    \"style\": {\n                                      \"marginRight\": \"16px\",\n                                      \"fontSize\": \"30px\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                },\n                                {\n                                  \"componentName\": \"Text\",\n                                  \"id\": \"node_ockwkbudw4b\",\n                                  \"props\": {\n                                    \"context\": \"专属商业养老保险\",\n                                    \"style\": {\n                                      \"color\": \"#999999\",\n                                      \"fontSize\": \"24px\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                }\n                              ]\n                            },\n                            {\n                              \"componentName\": \"Link\",\n                              \"id\": \"node_ockx02i8r07\",\n                              \"props\": {\n                                \"link\": \"./pilot-pension_policy-list.html\",\n                                \"spmD\": \"c88773.d183218\"\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Container\",\n                                  \"id\": \"node_ockwkbudw4s\",\n                                  \"props\": {\n                                    \"style\": {\n                                      \"boxSizing\": \"border-box\",\n                                      \"display\": \"flex\",\n                                      \"position\": \"relative\",\n                                      \"alignItems\": \"center\",\n                                      \"flexDirection\": \"row\",\n                                      \"marginLeft\": \"24px\",\n                                      \"borderWidth\": \"1px\",\n                                      \"borderStyle\": \"solid\",\n                                      \"borderRadius\": \"8px\",\n                                      \"borderColor\": \"#1677ff\",\n                                      \"paddingRight\": \"24px\",\n                                      \"paddingLeft\": \"24px\",\n                                      \"height\": \"58px\",\n                                      \"lineHeight\": \"30px\",\n                                      \"whiteSpace\": \"nowrap\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"],\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Text\",\n                                      \"id\": \"node_ockwkbudw4t\",\n                                      \"props\": {\n                                        \"context\": \"点击查看\",\n                                        \"style\": {\n                                          \"color\": \"#1677ff\",\n                                          \"fontSize\": \"24px\"\n                                        }\n                                      },\n                                      \"hidden\": false,\n                                      \"title\": \"\",\n                                      \"isLocked\": false,\n                                      \"condition\": true,\n                                      \"conditionGroup\": \"\"\n                                    }\n                                  ]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    },\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwptkenn17\",\n                      \"props\": {\n                        \"style\": {\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"marginTop\": \"0px\",\n                          \"borderRadius\": \"16px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginBottom\": \"16px\",\n                          \"paddingLeft\": \"20px\",\n                          \"paddingTop\": \"20px\",\n                          \"paddingRight\": \"20px\",\n                          \"paddingBottom\": \"20px\"\n                        },\n                        \"spmC\": \"c88773\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"未授权状态\",\n                      \"isLocked\": false,\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.state.policyCount > 0 && !this.state.hasAuthorized\",\n                        \"mock\": true\n                      },\n                      \"conditionGroup\": \"\",\n                      \"loopArgs\": [\"\", \"\"],\n                      \"children\": [\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwptkenn19\",\n                          \"props\": {\n                            \"style\": {\n                              \"marginBottom\": \"0px\",\n                              \"borderStyle\": \"none\",\n                              \"display\": \"flex\",\n                              \"alignItems\": \"center\",\n                              \"paddingBottom\": \"16px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"children\": [\n                            {\n                              \"componentName\": \"Text\",\n                              \"id\": \"node_ockwptkenn1a\",\n                              \"props\": {\n                                \"context\": \"我的保单\",\n                                \"style\": {\n                                  \"marginRight\": \"16px\",\n                                  \"fontSize\": \"30px\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"]\n                            },\n                            {\n                              \"componentName\": \"Text\",\n                              \"id\": \"node_ockwptkenn1b\",\n                              \"props\": {\n                                \"context\": \"专属商业养老保险\",\n                                \"style\": {\n                                  \"color\": \"#999999\",\n                                  \"fontSize\": \"24px\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"]\n                            }\n                          ]\n                        },\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwvvdp9p7\",\n                          \"props\": {\n                            \"style\": {\n                              \"paddingTop\": \"16px\",\n                              \"borderTopWidth\": \"1px\",\n                              \"borderTopColor\": \"#eeeeee\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"children\": [\n                            {\n                              \"componentName\": \"Text\",\n                              \"id\": \"node_ockwptkenn1c\",\n                              \"props\": {\n                                \"context\": \"同意在蚂蚁保查看、管理专属商业养老保险保单\",\n                                \"style\": {\n                                  \"height\": \"37px\",\n                                  \"lineHeight\": \"37px\",\n                                  \"color\": \"#999\",\n                                  \"fontSize\": \"26px\",\n                                  \"fontWeight\": \"400\",\n                                  \"marginLeft\": \"0px\",\n                                  \"display\": \"block\",\n                                  \"borderTopWidth\": \"1px\",\n                                  \"borderTopStyle\": \"solid\",\n                                  \"borderTopColor\": \"#eeeeee\",\n                                  \"paddingTop\": \"0px\",\n                                  \"borderStyle\": \"none\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"]\n                            }\n                          ]\n                        },\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwptkenn1d\",\n                          \"props\": {\n                            \"style\": {\n                              \"display\": \"block\",\n                              \"flexDirection\": \"row\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"children\": [\n                            {\n                              \"componentName\": \"Container\",\n                              \"id\": \"node_ockwptkenn1e\",\n                              \"props\": {\n                                \"style\": {\n                                  \"boxSizing\": \"border-box\",\n                                  \"display\": \"inline-block\",\n                                  \"position\": \"relative\",\n                                  \"alignItems\": \"center\",\n                                  \"flexDirection\": \"row\",\n                                  \"marginTop\": \"16px\",\n                                  \"marginLeft\": \"0px\",\n                                  \"borderWidth\": \"1px\",\n                                  \"borderStyle\": \"solid\",\n                                  \"borderRadius\": \"8px\",\n                                  \"borderColor\": \"#1677ff\",\n                                  \"paddingRight\": \"24px\",\n                                  \"paddingLeft\": \"24px\",\n                                  \"whiteSpace\": \"nowrap\",\n                                  \"paddingTop\": \"0px\",\n                                  \"paddingBottom\": \"0px\",\n                                  \"height\": \"58px\",\n                                  \"lineHeight\": \"58px\"\n                                },\n                                \"__events\": {\n                                  \"eventDataList\": [\n                                    {\n                                      \"type\": \"componentEvent\",\n                                      \"name\": \"onClick\",\n                                      \"relatedEventName\": \"handleAuth\"\n                                    }\n                                  ],\n                                  \"eventList\": [\n                                    {\n                                      \"name\": \"onClick\",\n                                      \"disabled\": true\n                                    }\n                                  ]\n                                },\n                                \"onClick\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){this.handleAuth.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Text\",\n                                  \"id\": \"node_ockwptkenn1f\",\n                                  \"props\": {\n                                    \"context\": \"同意并查看\",\n                                    \"style\": {\n                                      \"color\": \"#1677ff\",\n                                      \"fontSize\": \"24px\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\"\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"我的保单\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_MYPOLICY\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwdbwgg7o\",\n                      \"props\": {\n                        \"style\": {\n                          \"paddingTop\": \"20px\",\n                          \"paddingLeft\": \"20px\",\n                          \"paddingRight\": \"20px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"paddingBottom\": \"20px\",\n                          \"borderRadius\": \"16px\",\n                          \"marginBottom\": \"16px\"\n                        },\n                        \"spmC\": \"c88758\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwdb9utbc\",\n                          \"props\": {\n                            \"style\": {\n                              \"paddingBottom\": \"24px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"loop\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"this.module.productImg\"\n                          },\n                          \"children\": [\n                            {\n                              \"componentName\": \"Link\",\n                              \"id\": \"node_ockx03llkjw\",\n                              \"props\": {\n                                \"link\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"this.item.link\"\n                                },\n                                \"spmD\": \"c88758.d183221\"\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Image\",\n                                  \"id\": \"node_ockwdb9utbd\",\n                                  \"props\": {\n                                    \"src\": {\n                                      \"type\": \"JSExpression\",\n                                      \"value\": \"this.item.imgSrc\",\n                                      \"mock\": \"https://img.alicdn.com/imgextra/i1/O1CN01c35RIk1e3Ji8oUPXQ_!!6000000003815-2-tps-654-376.png\"\n                                    },\n                                    \"width\": \"100%\",\n                                    \"style\": {\n                                      \"display\": \"block\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                }\n                              ]\n                            }\n                          ]\n                        },\n                        {\n                          \"componentName\": \"Text\",\n                          \"id\": \"node_ockwnbkrje1l\",\n                          \"props\": {\n                            \"context\": \"更多指定保司产品将逐渐开放，敬请期待\",\n                            \"style\": {\n                              \"color\": \"#999999\",\n                              \"fontSize\": \"26px\",\n                              \"textAlign\": \"center\",\n                              \"display\": \"block\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\"\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"产品列表\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_ARTICLE_LIST\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockx4gcrxg1c\",\n                      \"props\": {\n                        \"style\": {\n                          \"paddingTop\": \"0px\",\n                          \"paddingLeft\": \"0px\",\n                          \"paddingRight\": \"0px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"paddingBottom\": \"0px\",\n                          \"borderRadius\": \"16px\",\n                          \"marginBottom\": \"16px\"\n                        },\n                        \"spmC\": \"c88757\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"Image\",\n                          \"id\": \"node_ockx4h25ygq\",\n                          \"props\": {\n                            \"src\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.module.header\",\n                              \"mock\": \"https://gw.alicdn.com/imgextra/i2/O1CN01nQxtcb1ail4yyw2kZ_!!6000000003364-2-tps-702-78.png\"\n                            },\n                            \"width\": \"100%\"\n                          },\n                          \"hidden\": false,\n                          \"title\": \"标题\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\"\n                        },\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockx4gcrxg1d\",\n                          \"props\": {\n                            \"style\": {\n                              \"paddingBottom\": \"24px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"文章列表循环\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"loop\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"this.module.productIntroduce\"\n                          },\n                          \"children\": [\n                            {\n                              \"componentName\": \"Link\",\n                              \"id\": \"node_ockx4gcrxg1e\",\n                              \"props\": {\n                                \"link\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"this.item.link\"\n                                },\n                                \"spmD\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"'c88757.d183219_' + this.index\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"],\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Image\",\n                                  \"id\": \"node_ockx4gcrxg1f\",\n                                  \"props\": {\n                                    \"src\": \"https://img.alicdn.com/imgextra/i4/O1CN015NY1E21XIhhWNXs3J_!!6000000002901-2-tps-700-230.png\",\n                                    \"width\": \"100%\",\n                                    \"style\": {\n                                      \"display\": \"block\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"文章列表\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_PRODUCT_LIST\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Share\",\n                      \"id\": \"node_ockx0429phm\",\n                      \"props\": {\n                        \"bizType\": \"ztokenV0_PaWxRUaO\",\n                        \"title\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.module.share.shareTitle\",\n                          \"mock\": \"我是分享标题\"\n                        },\n                        \"desc\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.module.share.shareDesc\",\n                          \"mock\": \"我是分享描述\"\n                        },\n                        \"iconUrl\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.module.share.iconUrl\",\n                          \"mock\": \"我是分享图标链接\"\n                        }\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\"\n                    }\n                  ],\n                  \"title\": \"分享设置\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_SHARE\"\n              }\n            ],\n            \"moduleList\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"this.state._insiopData.modules || []\"\n            }\n          },\n          \"hidden\": false,\n          \"title\": \"德鲁伊容器\",\n          \"isLocked\": false,\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"loopArgs\": [\"\", \"\"]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/page-element1.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\ntest('page-element1', async () => {\n  const inputSchemaJsonFile = path.join(__dirname, 'page-element1.schema.json');\n  const outputDir = path.join(__dirname, 'page-element1.generated');\n  await exportProject(inputSchemaJsonFile, outputDir);\n\n  const generatedPageFileContent = fs.readFileSync(\n    path.join(outputDir, 'demo-project/src/pages/$/index.jsx'),\n    'utf-8',\n  );\n  expect(generatedPageFileContent).toContain('<Page');\n});\n\nfunction exportProject(inputPath: string, outputPath: string) {\n  const schemaJson = fs.readFileSync(inputPath, { encoding: 'utf8' });\n  const newSchema = schemaJson;\n  const builder = CodeGenerator.createProjectBuilder({\n    template: CodeGenerator.solutionParts.icejs.template,\n    plugins: {\n      components: [\n        CodeGenerator.plugins.react.reactCommonDeps(),\n        CodeGenerator.plugins.common.esmodule({\n          fileType: 'jsx',\n        }),\n        CodeGenerator.plugins.react.containerClass(),\n        CodeGenerator.plugins.react.containerInitState(),\n        CodeGenerator.plugins.react.containerLifeCycle(),\n        CodeGenerator.plugins.react.containerMethod(),\n        CodeGenerator.plugins.react.jsx(),\n        CodeGenerator.plugins.style.css(),\n      ],\n      pages: [\n        CodeGenerator.plugins.react.reactCommonDeps(),\n        CodeGenerator.plugins.common.esmodule({\n          fileType: 'jsx',\n        }),\n        CodeGenerator.plugins.react.containerClass(),\n        CodeGenerator.plugins.react.containerInitState(),\n        CodeGenerator.plugins.react.containerLifeCycle(),\n        CodeGenerator.plugins.react.containerMethod(),\n        CodeGenerator.plugins.react.jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Block: 'div',\n          },\n        }),\n        CodeGenerator.plugins.style.css(),\n      ],\n      router: [\n        CodeGenerator.plugins.common.esmodule(),\n        CodeGenerator.solutionParts.icejs.plugins.router(),\n      ],\n      entry: [CodeGenerator.solutionParts.icejs.plugins.entry()],\n      constants: [CodeGenerator.plugins.project.constants()],\n      utils: [CodeGenerator.plugins.common.esmodule(), CodeGenerator.plugins.project.utils()],\n      i18n: [CodeGenerator.plugins.project.i18n()],\n      globalStyle: [CodeGenerator.solutionParts.icejs.plugins.globalStyle()],\n      htmlEntry: [CodeGenerator.solutionParts.icejs.plugins.entryHtml()],\n      packageJSON: [CodeGenerator.solutionParts.icejs.plugins.packageJSON()],\n    },\n    postProcessors: [CodeGenerator.postprocessor.prettier()],\n  });\n\n  return builder.generateProject(newSchema).then(async (result) => {\n    // displayResultInConsole(result);\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/page-element2.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Page\",\n      \"destructuring\": false,\n      \"main\": \"/es/components/page\",\n      \"subName\": \"\",\n      \"componentName\": \"Page\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Image\",\n      \"main\": \"/es/components/image\",\n      \"destructuring\": false,\n      \"subName\": \"\",\n      \"componentName\": \"Image\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Container\",\n      \"main\": \"/es/components/container\",\n      \"destructuring\": false,\n      \"subName\": \"\",\n      \"componentName\": \"Container\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Slot\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Text\",\n      \"main\": \"/es/components/text\",\n      \"destructuring\": false,\n      \"subName\": \"\",\n      \"componentName\": \"Text\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Link\",\n      \"main\": \"/es/components/link\",\n      \"destructuring\": false,\n      \"subName\": \"\",\n      \"componentName\": \"Link\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"Share\",\n      \"main\": \"/es/components/share\",\n      \"destructuring\": false,\n      \"subName\": \"\",\n      \"componentName\": \"Share\"\n    },\n    {\n      \"package\": \"@alipay/insragdoll-common-components\",\n      \"version\": \"1.0.x\",\n      \"exportName\": \"DruidList\",\n      \"main\": \"/es/components/druid-list\",\n      \"destructuring\": false,\n      \"subName\": \"\",\n      \"componentName\": \"DruidList\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outerView\",\n        \"style\": {\n          \"height\": \"100%\"\n        },\n        \"isTransparentTitle\": true,\n        \"spmA\": \"a691\",\n        \"spmB\": \"b34649\",\n        \"spmBizType\": \"BAOXIAN\"\n      },\n      \"fileName\": \"/\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"lifeCycles\": {\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.utils.rpc('com.alipay.inslifeweb.channel.pilotpension.render', {\\n        showType: 4,\\n      })\\n      .then((result) => {\\n        this.setState({\\n          policyCount: result.policyCount,\\n          hasAuthorized: result.hasAuthorized\\n        });\\n      });\\n  }\"\n        }\n      },\n      \"hidden\": false,\n      \"title\": \"\",\n      \"isLocked\": false,\n      \"condition\": true,\n      \"conditionGroup\": \"\",\n      \"_insiopConfig\": {\n        \"sceneCode\": \"PILOT_PENSION_LANDING_PAGE\"\n      },\n      \"css\": \"body {\\n  background: #f5f5f9;\\n}\",\n      \"methods\": {\n        \"handleAuth\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      hasAuthorized: true,\\n    });\\n    \\n    this.utils.rpc('com.alipay.inslifeweb.agreement.index.authorize', {\\n      bizScene: 'PILOT_ENDOWMENT_CHANNEL_POLICY_AGREEMENT',\\n      agreementScene: '20',\\n    });\\n\\n    Tracert.click('c88773.d183217');\\n  }\"\n        }\n      },\n      \"state\": {\n        \"policyCount\": 0,\n        \"hasAuthorized\": false\n      },\n      \"children\": [\n        {\n          \"componentName\": \"DruidList\",\n          \"id\": \"node_ockwcyxpypb\",\n          \"props\": {\n            \"slotList\": [\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwnbkrje1e\",\n                      \"props\": {\n                        \"style\": {\n                          \"marginBottom\": \"16px\"\n                        },\n                        \"spmC\": \"c88756\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"loopArgs\": [\"\", \"\"],\n                      \"children\": [\n                        {\n                          \"componentName\": \"Image\",\n                          \"id\": \"node_ockwd01xqzc\",\n                          \"props\": {\n                            \"src\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.module.imgList[0].imgUrl\",\n                              \"mock\": \"https://img.alicdn.com/imgextra/i3/O1CN01eqyMv71N2XZXffFkv_!!6000000001512-2-tps-750-642.png\"\n                            },\n                            \"width\": \"100%\",\n                            \"style\": {\n                              \"display\": \"block\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"]\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"图片区块\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_PICTURE\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwdmjns334\",\n                      \"props\": {\n                        \"style\": {\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"marginTop\": \"0px\",\n                          \"borderRadius\": \"16px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginBottom\": \"16px\",\n                          \"paddingLeft\": \"20px\",\n                          \"paddingTop\": \"20px\",\n                          \"paddingRight\": \"20px\",\n                          \"paddingBottom\": \"20px\"\n                        },\n                        \"spmC\": \"c88773\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"已授权状态\",\n                      \"isLocked\": false,\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.state.policyCount > 0 && this.state.hasAuthorized\",\n                        \"mock\": true\n                      },\n                      \"conditionGroup\": \"\",\n                      \"loopArgs\": [\"\", \"\"],\n                      \"children\": [\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwkbudw48\",\n                          \"props\": {\n                            \"style\": {\n                              \"backgroundColor\": \"#fff\",\n                              \"marginRight\": \"0px\",\n                              \"display\": \"flex\",\n                              \"flexDirection\": \"row\",\n                              \"justifyContent\": \"space-between\",\n                              \"alignItems\": \"center\",\n                              \"borderBottomStyle\": \"solid\",\n                              \"borderBottomWidth\": \"0px\",\n                              \"borderBottomColor\": \"#9b9b9b\",\n                              \"marginBottom\": \"0px\",\n                              \"marginLeft\": \"0px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"condition\": true,\n                          \"children\": [\n                            {\n                              \"componentName\": \"Container\",\n                              \"id\": \"node_ockwkbudw49\",\n                              \"props\": {},\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"],\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Text\",\n                                  \"id\": \"node_ockwkbudw4a\",\n                                  \"props\": {\n                                    \"context\": \"我的保单\",\n                                    \"style\": {\n                                      \"marginRight\": \"16px\",\n                                      \"fontSize\": \"30px\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                },\n                                {\n                                  \"componentName\": \"Text\",\n                                  \"id\": \"node_ockwkbudw4b\",\n                                  \"props\": {\n                                    \"context\": \"专属商业养老保险\",\n                                    \"style\": {\n                                      \"color\": \"#999999\",\n                                      \"fontSize\": \"24px\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                }\n                              ]\n                            },\n                            {\n                              \"componentName\": \"Link\",\n                              \"id\": \"node_ockx02i8r07\",\n                              \"props\": {\n                                \"link\": \"./pilot-pension_policy-list.html\",\n                                \"spmD\": \"c88773.d183218\"\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Container\",\n                                  \"id\": \"node_ockwkbudw4s\",\n                                  \"props\": {\n                                    \"style\": {\n                                      \"boxSizing\": \"border-box\",\n                                      \"display\": \"flex\",\n                                      \"position\": \"relative\",\n                                      \"alignItems\": \"center\",\n                                      \"flexDirection\": \"row\",\n                                      \"marginLeft\": \"24px\",\n                                      \"borderWidth\": \"1px\",\n                                      \"borderStyle\": \"solid\",\n                                      \"borderRadius\": \"8px\",\n                                      \"borderColor\": \"#1677ff\",\n                                      \"paddingRight\": \"24px\",\n                                      \"paddingLeft\": \"24px\",\n                                      \"height\": \"58px\",\n                                      \"lineHeight\": \"30px\",\n                                      \"whiteSpace\": \"nowrap\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"],\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Text\",\n                                      \"id\": \"node_ockwkbudw4t\",\n                                      \"props\": {\n                                        \"context\": \"点击查看\",\n                                        \"style\": {\n                                          \"color\": \"#1677ff\",\n                                          \"fontSize\": \"24px\"\n                                        }\n                                      },\n                                      \"hidden\": false,\n                                      \"title\": \"\",\n                                      \"isLocked\": false,\n                                      \"condition\": true,\n                                      \"conditionGroup\": \"\"\n                                    }\n                                  ]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    },\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwptkenn17\",\n                      \"props\": {\n                        \"style\": {\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"marginTop\": \"0px\",\n                          \"borderRadius\": \"16px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginBottom\": \"16px\",\n                          \"paddingLeft\": \"20px\",\n                          \"paddingTop\": \"20px\",\n                          \"paddingRight\": \"20px\",\n                          \"paddingBottom\": \"20px\"\n                        },\n                        \"spmC\": \"c88773\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"未授权状态\",\n                      \"isLocked\": false,\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.state.policyCount > 0 && !this.state.hasAuthorized\",\n                        \"mock\": true\n                      },\n                      \"conditionGroup\": \"\",\n                      \"loopArgs\": [\"\", \"\"],\n                      \"children\": [\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwptkenn19\",\n                          \"props\": {\n                            \"style\": {\n                              \"marginBottom\": \"0px\",\n                              \"borderStyle\": \"none\",\n                              \"display\": \"flex\",\n                              \"alignItems\": \"center\",\n                              \"paddingBottom\": \"16px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"children\": [\n                            {\n                              \"componentName\": \"Text\",\n                              \"id\": \"node_ockwptkenn1a\",\n                              \"props\": {\n                                \"context\": \"我的保单\",\n                                \"style\": {\n                                  \"marginRight\": \"16px\",\n                                  \"fontSize\": \"30px\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"]\n                            },\n                            {\n                              \"componentName\": \"Text\",\n                              \"id\": \"node_ockwptkenn1b\",\n                              \"props\": {\n                                \"context\": \"专属商业养老保险\",\n                                \"style\": {\n                                  \"color\": \"#999999\",\n                                  \"fontSize\": \"24px\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"]\n                            }\n                          ]\n                        },\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwvvdp9p7\",\n                          \"props\": {\n                            \"style\": {\n                              \"paddingTop\": \"16px\",\n                              \"borderTopWidth\": \"1px\",\n                              \"borderTopColor\": \"#eeeeee\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"children\": [\n                            {\n                              \"componentName\": \"Text\",\n                              \"id\": \"node_ockwptkenn1c\",\n                              \"props\": {\n                                \"context\": \"同意在蚂蚁保查看、管理专属商业养老保险保单\",\n                                \"style\": {\n                                  \"height\": \"37px\",\n                                  \"lineHeight\": \"37px\",\n                                  \"color\": \"#999\",\n                                  \"fontSize\": \"26px\",\n                                  \"fontWeight\": \"400\",\n                                  \"marginLeft\": \"0px\",\n                                  \"display\": \"block\",\n                                  \"borderTopWidth\": \"1px\",\n                                  \"borderTopStyle\": \"solid\",\n                                  \"borderTopColor\": \"#eeeeee\",\n                                  \"paddingTop\": \"0px\",\n                                  \"borderStyle\": \"none\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"]\n                            }\n                          ]\n                        },\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwptkenn1d\",\n                          \"props\": {\n                            \"style\": {\n                              \"display\": \"block\",\n                              \"flexDirection\": \"row\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"children\": [\n                            {\n                              \"componentName\": \"Container\",\n                              \"id\": \"node_ockwptkenn1e\",\n                              \"props\": {\n                                \"style\": {\n                                  \"boxSizing\": \"border-box\",\n                                  \"display\": \"inline-block\",\n                                  \"position\": \"relative\",\n                                  \"alignItems\": \"center\",\n                                  \"flexDirection\": \"row\",\n                                  \"marginTop\": \"16px\",\n                                  \"marginLeft\": \"0px\",\n                                  \"borderWidth\": \"1px\",\n                                  \"borderStyle\": \"solid\",\n                                  \"borderRadius\": \"8px\",\n                                  \"borderColor\": \"#1677ff\",\n                                  \"paddingRight\": \"24px\",\n                                  \"paddingLeft\": \"24px\",\n                                  \"whiteSpace\": \"nowrap\",\n                                  \"paddingTop\": \"0px\",\n                                  \"paddingBottom\": \"0px\",\n                                  \"height\": \"58px\",\n                                  \"lineHeight\": \"58px\"\n                                },\n                                \"__events\": {\n                                  \"eventDataList\": [\n                                    {\n                                      \"type\": \"componentEvent\",\n                                      \"name\": \"onClick\",\n                                      \"relatedEventName\": \"handleAuth\"\n                                    }\n                                  ],\n                                  \"eventList\": [\n                                    {\n                                      \"name\": \"onClick\",\n                                      \"disabled\": true\n                                    }\n                                  ]\n                                },\n                                \"onClick\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){this.handleAuth.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Text\",\n                                  \"id\": \"node_ockwptkenn1f\",\n                                  \"props\": {\n                                    \"context\": \"同意并查看\",\n                                    \"style\": {\n                                      \"color\": \"#1677ff\",\n                                      \"fontSize\": \"24px\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\"\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"我的保单\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_MYPOLICY\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockwdbwgg7o\",\n                      \"props\": {\n                        \"style\": {\n                          \"paddingTop\": \"20px\",\n                          \"paddingLeft\": \"20px\",\n                          \"paddingRight\": \"20px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"paddingBottom\": \"20px\",\n                          \"borderRadius\": \"16px\",\n                          \"marginBottom\": \"16px\"\n                        },\n                        \"spmC\": \"c88758\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockwdb9utbc\",\n                          \"props\": {\n                            \"style\": {\n                              \"paddingBottom\": \"24px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"loop\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"this.module.productImg\"\n                          },\n                          \"children\": [\n                            {\n                              \"componentName\": \"Link\",\n                              \"id\": \"node_ockx03llkjw\",\n                              \"props\": {\n                                \"link\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"this.item.link\"\n                                },\n                                \"spmD\": \"c88758.d183221\"\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Image\",\n                                  \"id\": \"node_ockwdb9utbd\",\n                                  \"props\": {\n                                    \"src\": {\n                                      \"type\": \"JSExpression\",\n                                      \"value\": \"this.item.imgSrc\",\n                                      \"mock\": \"https://img.alicdn.com/imgextra/i1/O1CN01c35RIk1e3Ji8oUPXQ_!!6000000003815-2-tps-654-376.png\"\n                                    },\n                                    \"width\": \"100%\",\n                                    \"style\": {\n                                      \"display\": \"block\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                }\n                              ]\n                            }\n                          ]\n                        },\n                        {\n                          \"componentName\": \"Text\",\n                          \"id\": \"node_ockwnbkrje1l\",\n                          \"props\": {\n                            \"context\": \"更多指定保司产品将逐渐开放，敬请期待\",\n                            \"style\": {\n                              \"color\": \"#999999\",\n                              \"fontSize\": \"26px\",\n                              \"textAlign\": \"center\",\n                              \"display\": \"block\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\"\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"产品列表\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_ARTICLE_LIST\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Container\",\n                      \"id\": \"node_ockx4gcrxg1c\",\n                      \"props\": {\n                        \"style\": {\n                          \"paddingTop\": \"0px\",\n                          \"paddingLeft\": \"0px\",\n                          \"paddingRight\": \"0px\",\n                          \"backgroundColor\": \"#ffffff\",\n                          \"marginLeft\": \"24px\",\n                          \"marginRight\": \"24px\",\n                          \"paddingBottom\": \"0px\",\n                          \"borderRadius\": \"16px\",\n                          \"marginBottom\": \"16px\"\n                        },\n                        \"spmC\": \"c88757\"\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"Image\",\n                          \"id\": \"node_ockx4h25ygq\",\n                          \"props\": {\n                            \"src\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.module.header\",\n                              \"mock\": \"https://gw.alicdn.com/imgextra/i2/O1CN01nQxtcb1ail4yyw2kZ_!!6000000003364-2-tps-702-78.png\"\n                            },\n                            \"width\": \"100%\"\n                          },\n                          \"hidden\": false,\n                          \"title\": \"标题\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\"\n                        },\n                        {\n                          \"componentName\": \"Container\",\n                          \"id\": \"node_ockx4gcrxg1d\",\n                          \"props\": {\n                            \"style\": {\n                              \"paddingBottom\": \"24px\"\n                            }\n                          },\n                          \"hidden\": false,\n                          \"title\": \"文章列表循环\",\n                          \"isLocked\": false,\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"loopArgs\": [\"\", \"\"],\n                          \"loop\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"this.module.productIntroduce\"\n                          },\n                          \"children\": [\n                            {\n                              \"componentName\": \"Link\",\n                              \"id\": \"node_ockx4gcrxg1e\",\n                              \"props\": {\n                                \"link\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"this.item.link\"\n                                },\n                                \"spmD\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"'c88757.d183219_' + this.index\"\n                                }\n                              },\n                              \"hidden\": false,\n                              \"title\": \"\",\n                              \"isLocked\": false,\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"loopArgs\": [\"\", \"\"],\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Image\",\n                                  \"id\": \"node_ockx4gcrxg1f\",\n                                  \"props\": {\n                                    \"src\": \"https://img.alicdn.com/imgextra/i4/O1CN015NY1E21XIhhWNXs3J_!!6000000002901-2-tps-700-230.png\",\n                                    \"width\": \"100%\",\n                                    \"style\": {\n                                      \"display\": \"block\"\n                                    }\n                                  },\n                                  \"hidden\": false,\n                                  \"title\": \"\",\n                                  \"isLocked\": false,\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"loopArgs\": [\"\", \"\"]\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ],\n                  \"title\": \"文章列表\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_PRODUCT_LIST\"\n              },\n              {\n                \"childRender\": {\n                  \"type\": \"JSSlot\",\n                  \"params\": [\"module\"],\n                  \"value\": [\n                    {\n                      \"componentName\": \"Share\",\n                      \"id\": \"node_ockx0429phm\",\n                      \"props\": {\n                        \"bizType\": \"ztokenV0_PaWxRUaO\",\n                        \"title\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.module.share.shareTitle\",\n                          \"mock\": \"我是分享标题\"\n                        },\n                        \"desc\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.module.share.shareDesc\",\n                          \"mock\": \"我是分享描述\"\n                        },\n                        \"iconUrl\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.module.share.iconUrl\",\n                          \"mock\": \"我是分享图标链接\"\n                        }\n                      },\n                      \"hidden\": false,\n                      \"title\": \"\",\n                      \"isLocked\": false,\n                      \"condition\": true,\n                      \"conditionGroup\": \"\"\n                    }\n                  ],\n                  \"title\": \"分享设置\"\n                },\n                \"templateCode\": \"PILOT_PENSION_LANDING_PAGE_SHARE\"\n              }\n            ],\n            \"moduleList\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"this.state._insiopData.modules || []\"\n            }\n          },\n          \"hidden\": false,\n          \"title\": \"德鲁伊容器\",\n          \"isLocked\": false,\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"loopArgs\": [\"\", \"\"]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/page-element2.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\n\ntest('page-element2', async () => {\n  const inputSchemaJsonFile = path.join(__dirname, 'page-element2.schema.json');\n  const outputDir = path.join(__dirname, 'page-element2.generated');\n  await exportProject(inputSchemaJsonFile, outputDir);\n\n  const generatedPageFileContent = fs.readFileSync(\n    path.join(outputDir, 'demo-project/src/pages/$/index.jsx'),\n    'utf-8',\n  );\n  expect(generatedPageFileContent).toContain('<Page');\n});\n\nfunction exportProject(inputPath: string, outputPath: string) {\n  const schemaJson = fs.readFileSync(inputPath, { encoding: 'utf8' });\n  const newSchema = schemaJson;\n  const builder = CodeGenerator.createProjectBuilder({\n    template: CodeGenerator.solutionParts.icejs.template,\n    plugins: {\n      components: [\n        CodeGenerator.plugins.react.reactCommonDeps(),\n        CodeGenerator.plugins.common.esmodule({\n          fileType: 'jsx',\n        }),\n        CodeGenerator.plugins.react.containerClass(),\n        CodeGenerator.plugins.react.containerInitState(),\n        CodeGenerator.plugins.react.containerLifeCycle(),\n        CodeGenerator.plugins.react.containerMethod(),\n        CodeGenerator.plugins.react.jsx(),\n        CodeGenerator.plugins.style.css(),\n      ],\n      pages: [\n        CodeGenerator.plugins.react.reactCommonDeps(),\n        CodeGenerator.plugins.common.esmodule({\n          fileType: 'jsx',\n        }),\n        CodeGenerator.plugins.react.containerClass(),\n        CodeGenerator.plugins.react.containerInitState(),\n        CodeGenerator.plugins.react.containerLifeCycle(),\n        CodeGenerator.plugins.react.containerMethod(),\n        CodeGenerator.plugins.react.jsx({\n          nodeTypeMapping: {\n            Div: 'div',\n            Component: 'div',\n            Block: 'div',\n          },\n        }),\n        CodeGenerator.plugins.style.css(),\n      ],\n      router: [\n        CodeGenerator.plugins.common.esmodule(),\n        CodeGenerator.solutionParts.icejs.plugins.router(),\n      ],\n      entry: [CodeGenerator.solutionParts.icejs.plugins.entry()],\n      constants: [CodeGenerator.plugins.project.constants()],\n      utils: [CodeGenerator.plugins.common.esmodule(), CodeGenerator.plugins.project.utils()],\n      i18n: [CodeGenerator.plugins.project.i18n()],\n      globalStyle: [CodeGenerator.solutionParts.icejs.plugins.globalStyle()],\n      htmlEntry: [CodeGenerator.solutionParts.icejs.plugins.entryHtml()],\n      packageJSON: [CodeGenerator.solutionParts.icejs.plugins.packageJSON()],\n    },\n    postProcessors: [CodeGenerator.postprocessor.prettier()],\n  });\n\n  return builder.generateProject(newSchema).then(async (result) => {\n    // displayResultInConsole(result);\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/strict-mode-context-1.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Text\",\n      \"componentName\": \"Typography.Text\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Select\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Select\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Space\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Space\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Button\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Button\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"InputNumber\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"InputNumber\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Item\",\n      \"componentName\": \"Form.Item\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Input\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"TextArea\",\n      \"componentName\": \"Input.TextArea\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Form\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Modal\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Modal\"\n    },\n    {\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.16\",\n      \"exportName\": \"AliAutoSearchTable\",\n      \"main\": \"build/lowcode/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoSearchTableDefault\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode\",\n      \"version\": \"0.5.4\",\n      \"exportName\": \"Card\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Card\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextP\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"Cell\",\n      \"componentName\": \"NextBlockCell\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlock\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Slot\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextPage\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Page\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"style\": {\n          \"height\": \"100%\"\n        }\n      },\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}\",\n      \"lifeCycles\": {\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"componentWillUnmount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"componentDidUpdate\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        }\n      },\n      \"methods\": {\n        \"onChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"getActions\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"onCreateOrder\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"onCancelModal\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        },\n        \"onConfirmCreateOrder\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /* ... */ }\"\n        }\n      },\n      \"state\": {\n        \"name\": \"nongzhou\",\n        \"gateways\": [],\n        \"selectedGateway\": null,\n        \"records\": [],\n        \"modalVisible\": false\n      },\n      \"children\": [\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ocknqx3esma\",\n          \"props\": {\n            \"columns\": 12,\n            \"headerDivider\": true,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"header\"\n            },\n            \"headerProps\": {\n              \"background\": \"surface\"\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"footer\"\n            },\n            \"minHeight\": \"100vh\",\n            \"style\": {\n              \"cursor\": \"pointer\"\n            }\n          },\n          \"title\": \"页面\",\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ocknqx3esmb\",\n              \"props\": {\n                \"prefix\": \"next-\",\n                \"placeholderStyle\": {\n                  \"height\": \"100%\"\n                },\n                \"noPadding\": false,\n                \"noBorder\": false,\n                \"background\": \"surface\",\n                \"layoutmode\": \"O\",\n                \"colSpan\": 12,\n                \"rowSpan\": 1,\n                \"childTotalColumns\": 12\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ocknqx3esmc\",\n                  \"props\": {\n                    \"title\": \"\",\n                    \"prefix\": \"next-\",\n                    \"placeholderStyle\": {\n                      \"height\": \"100%\"\n                    },\n                    \"layoutmode\": \"O\",\n                    \"childTotalColumns\": 12,\n                    \"isAutoContainer\": true,\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ocknqx3esm1j\",\n                      \"props\": {\n                        \"wrap\": false,\n                        \"type\": \"body2\",\n                        \"verAlign\": \"middle\",\n                        \"textSpacing\": true,\n                        \"align\": \"left\",\n                        \"full\": true,\n                        \"flex\": true\n                      },\n                      \"title\": \"段落\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"Card\",\n                          \"id\": \"node_ocknqx3esm1k\",\n                          \"props\": {\n                            \"title\": \"\"\n                          },\n                          \"children\": [\n                            {\n                              \"componentName\": \"Space\",\n                              \"id\": \"node_ocknqx3esm1n\",\n                              \"props\": {\n                                \"size\": 0,\n                                \"align\": \"center\",\n                                \"direction\": \"horizontal\"\n                              },\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Typography.Text\",\n                                  \"id\": \"node_ocknqx3esm1l\",\n                                  \"props\": {\n                                    \"children\": \"所在网关：\"\n                                  }\n                                },\n                                {\n                                  \"componentName\": \"Select\",\n                                  \"id\": \"node_ocknqx3esm1m\",\n                                  \"props\": {\n                                    \"style\": {\n                                      \"marginTop\": \"16px\",\n                                      \"marginRight\": \"16px\",\n                                      \"marginBottom\": \"16px\",\n                                      \"marginLeft\": \"16px\",\n                                      \"width\": \"400px\",\n                                      \"display\": \"inline-block\"\n                                    },\n                                    \"options\": {\n                                      \"type\": \"JSExpression\",\n                                      \"value\": \"this.state.gateways\"\n                                    },\n                                    \"mode\": \"single\",\n                                    \"defaultValue\": [\"auto-edd-uniproxy\"],\n                                    \"labelInValue\": true,\n                                    \"showSearch\": true,\n                                    \"allowClear\": false,\n                                    \"placeholder\": \"请选取网关\",\n                                    \"showArrow\": true,\n                                    \"loading\": false,\n                                    \"tokenSeparators\": [],\n                                    \"__events\": {\n                                      \"eventDataList\": [\n                                        {\n                                          \"type\": \"componentEvent\",\n                                          \"name\": \"onChange\",\n                                          \"relatedEventName\": \"onChange\"\n                                        }\n                                      ],\n                                      \"eventList\": [\n                                        {\n                                          \"name\": \"onBlur\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onChange\",\n                                          \"disabled\": true\n                                        },\n                                        {\n                                          \"name\": \"onDeselect\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onFocus\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onInputKeyDown\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onMouseEnter\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onMouseLeave\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onPopupScroll\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onSearch\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onSelect\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onDropdownVisibleChange\",\n                                          \"disabled\": false\n                                        }\n                                      ]\n                                    },\n                                    \"onChange\": {\n                                      \"type\": \"JSFunction\",\n                                      \"value\": \"function(){this.onChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                    }\n                                  }\n                                }\n                              ]\n                            },\n                            {\n                              \"componentName\": \"Button\",\n                              \"id\": \"node_ockntwgdsn7\",\n                              \"props\": {\n                                \"type\": \"primary\",\n                                \"children\": \"创建发布单\",\n                                \"style\": {\n                                  \"display\": \"block\",\n                                  \"marginTop\": \"20px\",\n                                  \"marginBottom\": \"20px\"\n                                },\n                                \"__events\": {\n                                  \"eventDataList\": [\n                                    {\n                                      \"type\": \"componentEvent\",\n                                      \"name\": \"onClick\",\n                                      \"relatedEventName\": \"onCreateOrder\"\n                                    }\n                                  ],\n                                  \"eventList\": [\n                                    {\n                                      \"name\": \"onClick\",\n                                      \"disabled\": true\n                                    }\n                                  ]\n                                },\n                                \"onClick\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){this.onCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                }\n                              }\n                            },\n                            {\n                              \"componentName\": \"Modal\",\n                              \"id\": \"node_ockntx4eo9p\",\n                              \"props\": {\n                                \"title\": \"创建发布单\",\n                                \"visible\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"this.state.modalVisible\"\n                                },\n                                \"footer\": \"\",\n                                \"__events\": {\n                                  \"eventDataList\": [\n                                    {\n                                      \"type\": \"componentEvent\",\n                                      \"name\": \"onCancel\",\n                                      \"relatedEventName\": \"onCancelModal\"\n                                    }\n                                  ],\n                                  \"eventList\": [\n                                    {\n                                      \"name\": \"onCancel\",\n                                      \"disabled\": true\n                                    },\n                                    {\n                                      \"name\": \"onOk\",\n                                      \"disabled\": false\n                                    }\n                                  ]\n                                },\n                                \"onCancel\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                },\n                                \"zIndex\": 2000\n                              },\n                              \"hidden\": true,\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Form\",\n                                  \"id\": \"node_ockntx4eo9s\",\n                                  \"props\": {\n                                    \"labelCol\": {\n                                      \"span\": 6\n                                    },\n                                    \"wrapperCol\": {\n                                      \"span\": 14\n                                    },\n                                    \"onFinish\": {\n                                      \"type\": \"JSFunction\",\n                                      \"value\": \"function(){this.onConfirmCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                    },\n                                    \"name\": \"basic\",\n                                    \"__events\": {\n                                      \"eventDataList\": [\n                                        {\n                                          \"type\": \"componentEvent\",\n                                          \"name\": \"onFinish\",\n                                          \"relatedEventName\": \"onConfirmCreateOrder\"\n                                        }\n                                      ],\n                                      \"eventList\": [\n                                        {\n                                          \"name\": \"onFinish\",\n                                          \"disabled\": true\n                                        },\n                                        {\n                                          \"name\": \"onFinishFailed\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onFieldsChange\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onValuesChange\",\n                                          \"disabled\": false\n                                        }\n                                      ]\n                                    }\n                                  },\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ockntx4eo91k\",\n                                      \"props\": {\n                                        \"label\": \"发布批次\"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"InputNumber\",\n                                          \"id\": \"node_ockntx4eo91l\",\n                                          \"props\": {\n                                            \"value\": 3,\n                                            \"min\": 1\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ockntx4eo91r\",\n                                      \"props\": {\n                                        \"label\": \"批次间隔时间\"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"InputNumber\",\n                                          \"id\": \"node_ockntx4eo91s\",\n                                          \"props\": {\n                                            \"value\": 3\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ockntx4eo91y\",\n                                      \"props\": {\n                                        \"label\": \"备注 \"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Input.TextArea\",\n                                          \"id\": \"node_ockntx4eo91z\",\n                                          \"props\": {\n                                            \"rows\": 3,\n                                            \"placeholder\": \"请输入\"\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ockntx4eo9v\",\n                                      \"props\": {\n                                        \"wrapperCol\": {\n                                          \"offset\": 6\n                                        },\n                                        \"style\": {\n                                          \"flexDirection\": \"row\",\n                                          \"alignItems\": \"flex-end\",\n                                          \"justifyContent\": \"center\",\n                                          \"display\": \"flex\"\n                                        },\n                                        \"labelAlign\": \"right\"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Button\",\n                                          \"id\": \"node_ockntx4eo9w\",\n                                          \"props\": {\n                                            \"type\": \"primary\",\n                                            \"children\": \"提交\",\n                                            \"htmlType\": \"submit\"\n                                          }\n                                        },\n                                        {\n                                          \"componentName\": \"Button\",\n                                          \"id\": \"node_ockntx4eo9x\",\n                                          \"props\": {\n                                            \"style\": {\n                                              \"marginLeft\": 20\n                                            },\n                                            \"children\": \"取消\",\n                                            \"__events\": {\n                                              \"eventDataList\": [\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onClick\",\n                                                  \"relatedEventName\": \"onCancelModal\"\n                                                }\n                                              ],\n                                              \"eventList\": [\n                                                {\n                                                  \"name\": \"onClick\",\n                                                  \"disabled\": true\n                                                }\n                                              ]\n                                            },\n                                            \"onClick\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            }\n                                          }\n                                        }\n                                      ]\n                                    }\n                                  ]\n                                }\n                              ]\n                            },\n                            {\n                              \"componentName\": \"AliAutoSearchTableDefault\",\n                              \"id\": \"node_ocknqx3esm1q\",\n                              \"props\": {\n                                \"rowKey\": \"key\",\n                                \"dataSource\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"this.state.records\"\n                                },\n                                \"columns\": [\n                                  {\n                                    \"title\": \"发布名称\",\n                                    \"dataIndex\": \"order_name\",\n                                    \"key\": \"name\"\n                                  },\n                                  {\n                                    \"title\": \"类型\",\n                                    \"dataIndex\": \"order_type_desc\",\n                                    \"key\": \"age\"\n                                  },\n                                  {\n                                    \"title\": \"发布状态\",\n                                    \"dataIndex\": \"order_status_desc\",\n                                    \"key\": \"address\"\n                                  },\n                                  {\n                                    \"title\": \"发布人\",\n                                    \"dataIndex\": \"creator_name\"\n                                  },\n                                  {\n                                    \"title\": \"当前批次/总批次\",\n                                    \"dataIndex\": \"cur_batch_no\"\n                                  },\n                                  {\n                                    \"title\": \"发布机器/总机器\",\n                                    \"dataIndex\": \"pubblish_ip_finish_num\"\n                                  },\n                                  {\n                                    \"title\": \"发布时间\",\n                                    \"dataIndex\": \"publish_id\"\n                                  }\n                                ],\n                                \"actions\": {\n                                  \"type\": \"JSExpression\",\n                                  \"value\": \"this.actions || []\"\n                                },\n                                \"getActions\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){ return this.getActions.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                }\n                              }\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/strict-mode-context-1.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\nimport { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\nconst inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\nconst outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n\njest.setTimeout(60 * 60 * 1000);\n\ndescribe(testCaseBaseName, () => {\n  test('methods will be set to context in constructor', async () => {\n    await exportProject(inputSchemaJsonFile, outputDir, {}, { inStrictMode: true });\n\n    const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n    expect(generatedPageFileContent).not.toContain('_context = this;');\n    expect(generatedPageFileContent).toContain('_context = this._createContext();');\n    expect(generatedPageFileContent).toContain(\n      `\n    this._context.onChange = this.onChange;\n    this._context.getActions = this.getActions;\n    this._context.onCreateOrder = this.onCreateOrder;\n    this._context.onCancelModal = this.onCancelModal;\n    this._context.onConfirmCreateOrder = this.onConfirmCreateOrder;\n      `.trim(),\n    );\n  });\n});\n\nfunction exportProject(\n  importPath: string,\n  outputPath: string,\n  mergeSchema?: Partial<IPublicTypeProjectSchema>,\n  options?: IceJsProjectBuilderOptions,\n) {\n  const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });\n  const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };\n  const builder = CodeGenerator.solutions.icejs(options);\n\n  return builder.generateProject(schema).then(async (result) => {\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n\nfunction readOutputTextFile(outputFilePath: string): string {\n  return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/tolerate-eval-errors-1-loop.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"react-greetings\",\n      \"version\": \"1.0.0\",\n      \"componentName\": \"Greetings\",\n      \"exportName\": \"Greetings\",\n      \"destructuring\": true\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_ocl137q7oc1\",\n      \"fileName\": \"test\",\n      \"props\": { \"style\": {} },\n      \"lifeCycles\": {},\n      \"dataSource\": { \"list\": [] },\n      \"state\": {\n        \"name\": \"lowcode world\",\n        \"users\": null\n      },\n      \"methods\": {},\n      \"children\": [\n        {\n          \"componentName\": \"Greetings\",\n          \"id\": \"node_ocl137q7oc4\",\n          \"loop\": {\n            \"type\": \"JSExpression\",\n            \"value\": \"this.state.users\"\n          },\n          \"loopArgs\": [\"item\", \"\"],\n          \"props\": {\n            \"content\": {\n              \"type\": \"i18n\",\n              \"key\": \"greetings.hello\",\n              \"params\": {\n                \"name\": {\n                  \"type\": \"JSExpression\",\n                  \"value\": \"this.item\"\n                }\n              }\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"i18n\": {\n    \"zh-CN\": {\n      \"greetings.hello\": \"${name}, 你好！\"\n    },\n    \"en-US\": {\n      \"greetings.hello\": \"Hello, ${name}!\"\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/tolerate-eval-errors-1-loop.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\nimport { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\nconst inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\nconst outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n\njest.setTimeout(60 * 60 * 1000);\n\ntest('loop should be generated link __$$evalArray(xxx).map', async () => {\n  await exportProject(\n    inputSchemaJsonFile,\n    outputDir,\n    {},\n    { inStrictMode: true, tolerateEvalErrors: true },\n  );\n\n  const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n  expect(generatedPageFileContent).toContain(\n    '{__$$evalArray(() => this.state.users).map((item, index) =>',\n  );\n});\n\nfunction exportProject(\n  importPath: string,\n  outputPath: string,\n  mergeSchema?: Partial<IPublicTypeProjectSchema>,\n  options?: IceJsProjectBuilderOptions,\n) {\n  const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });\n  const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };\n  const builder = CodeGenerator.solutions.icejs(options);\n\n  return builder.generateProject(schema).then(async (result) => {\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n\nfunction readOutputTextFile(outputFilePath: string): string {\n  return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/tolerate-eval-errors-2-nested-loop.schema.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"react-greetings\",\n      \"version\": \"1.0.0\",\n      \"componentName\": \"Greetings\",\n      \"exportName\": \"Greetings\",\n      \"destructuring\": true\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_ocl137q7oc1\",\n      \"fileName\": \"test\",\n      \"props\": { \"style\": {} },\n      \"lifeCycles\": {},\n      \"dataSource\": { \"list\": [] },\n      \"state\": {\n        \"name\": \"lowcode world\",\n        \"users\": null\n      },\n      \"methods\": {},\n      \"children\": [\n        {\n          \"componentName\": \"Greetings\",\n          \"id\": \"node_ocl137q7oc4\",\n          \"loop\": {\n            \"type\": \"JSExpression\",\n            \"value\": \"this.state.users\"\n          },\n          \"loopArgs\": [\"item\", \"\"],\n          \"props\": {\n            \"content\": {\n              \"type\": \"i18n\",\n              \"key\": \"greetings.hello\",\n              \"params\": { \"name\": { \"type\": \"JSExpression\", \"value\": \"this.item\" } }\n            }\n          },\n          \"children\": [\n            {\n              \"componentName\": \"Greetings\",\n              \"id\": \"node_ocl137q7oc4\",\n              \"loop\": {\n                \"type\": \"JSExpression\",\n                \"value\": \"this.state.messages\"\n              },\n              \"loopArgs\": [\"msg\", \"\"],\n              \"props\": {\n                \"content\": {\n                  \"type\": \"JSExpression\",\n                  \"value\": \"this.msg\"\n                }\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {\n    \"zh-CN\": {\n      \"greetings.hello\": \"${name}, 你好！\"\n    },\n    \"en-US\": {\n      \"greetings.hello\": \"Hello, ${name}!\"\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/bugfix/tolerate-eval-errors-2-nested-loop.test.ts",
    "content": "import CodeGenerator from '../../src';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { createDiskPublisher } from '../helpers/solutionHelper';\nimport { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';\n\nconst testCaseBaseName = path.basename(__filename, '.test.ts');\nconst inputSchemaJsonFile = path.join(__dirname, `${testCaseBaseName}.schema.json`);\nconst outputDir = path.join(__dirname, `${testCaseBaseName}.generated`);\n\njest.setTimeout(60 * 60 * 1000);\n\ntest('loop should be generated link __$$evalArray(xxx).map', async () => {\n  await exportProject(\n    inputSchemaJsonFile,\n    outputDir,\n    {},\n    { inStrictMode: true, tolerateEvalErrors: true },\n  );\n\n  const generatedPageFileContent = readOutputTextFile('demo-project/src/pages/Test/index.jsx');\n  expect(generatedPageFileContent).toContain(\n    '{__$$evalArray(() => this.state.users).map((item, index) =>',\n  );\n\n  expect(generatedPageFileContent).toContain(\n    '{__$$evalArray(() => __$$context.state.messages).map(',\n  );\n});\n\nfunction exportProject(\n  importPath: string,\n  outputPath: string,\n  mergeSchema?: Partial<IPublicTypeProjectSchema>,\n  options?: IceJsProjectBuilderOptions,\n) {\n  const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });\n  const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };\n  const builder = CodeGenerator.solutions.icejs(options);\n\n  return builder.generateProject(schema).then(async (result) => {\n    const publisher = createDiskPublisher();\n    await publisher.publish({\n      project: result,\n      outputPath,\n      projectSlug: 'demo-project',\n      createProjectFolder: true,\n    });\n    return result;\n  });\n}\n\nfunction readOutputTextFile(outputFilePath: string): string {\n  return fs.readFileSync(path.resolve(outputDir, outputFilePath), 'utf-8');\n}\n"
  },
  {
    "path": "modules/code-generator/tests/cli.test.ts",
    "content": "import { run } from '../src/cli';\n\ndescribe('cli', () => {\n  // standalone 模式下不需要测试 cli\n  if (process.env.TEST_TARGET === 'standalone') {\n    it('should ignore', () => {\n      expect(true).toBe(true);\n    });\n    return;\n  }\n\n  it('should works for the default example-schema.json', async () => {\n    const res = await run(['example-schema.json'], {\n      solution: 'icejs',\n      output: './demo',\n    });\n    expect(res).toBe(0);\n  });\n\n  it('should works for the default example-schema.json5', async () => {\n    const res = await run(['example-schema.json5'], {\n      solution: 'icejs',\n      output: './demo',\n    });\n    expect(res).toBe(0);\n  });\n\n  it('should returns error for no schema file', async () => {\n    const res = await run([], {\n      solution: 'icejs',\n      output: './demo',\n    });\n\n    expect(res).not.toBe(0);\n  });\n\n  it('should returns error for to many schema files', async () => {\n    const res = await run(['example-schema.json', 'example-schema.json5'], {\n      solution: 'icejs',\n    });\n    expect(res).not.toBe(0);\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/.gitignore",
    "content": "actual/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.19.18\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-fetch-handler\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Form, Input, NumberPicker, Select, Button } from '@alifd/next';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(window.location.search),\n      fetch: __$$createFetchRequestHandler(),\n    },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter' };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'urlParams',\n          type: 'urlParams',\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n          options: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'user',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'orders',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/orders',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data.result;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n      dataHandler: function (dataMap) {\n        console.info('All datasources loaded:', dataMap);\n      },\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n\n    console.log('componentDidMount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}>\n        <Form\n          labelCol={__$$eval(() => this.state.colNum)}\n          style={{}}\n          ref={this._refsManager.linkRef('testForm')}\n        >\n          <Form.Item label=\"姓名：\" name=\"name\" initValue=\"李雷\">\n            <Input placeholder=\"请输入\" size=\"medium\" style={{ width: 320 }} />\n          </Form.Item>\n          <Form.Item label=\"年龄：\" name=\"age\" initValue=\"22\">\n            <NumberPicker size=\"medium\" type=\"normal\" />\n          </Form.Item>\n          <Form.Item label=\"职业：\" name=\"profession\">\n            <Select\n              dataSource={[\n                { label: '教师', value: 't' },\n                { label: '医生', value: 'd' },\n                { label: '歌手', value: 's' },\n              ]}\n            />\n          </Form.Item>\n          <div style={{ textAlign: 'center' }}>\n            <Button.Group>\n              {__$$evalArray(() => ['a', 'b', 'c']).map((item, index) =>\n                ((__$$context) =>\n                  !!__$$eval(() => index >= 1) && (\n                    <Button type=\"primary\" style={{ margin: '0 5px 0 5px' }}>\n                      {__$$eval(() => item)}\n                    </Button>\n                  ))(__$$createChildContext(__$$context, { item, index }))\n              )}\n            </Button.Group>\n          </div>\n        </Form>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/schema.json5",
    "content": "{\n\t\"version\": \"1.0.0\",\n\t\"componentsMap\": [\n\t\t{\n\t\t\t\"componentName\": \"Button\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\",\n\t\t\t\"subName\": \"Group\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Input\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Input\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\",\n\t\t\t\"subName\": \"Item\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"NumberPicker\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Select\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Select\"\n\t\t}\n\t],\n\t\"componentsTree\": [\n\t\t{\n\t\t\t\"componentName\": \"Page\",\n\t\t\t\"id\": \"node$1\",\n\t\t\t\"meta\": {\n\t\t\t\t\"title\": \"测试\",\n\t\t\t\t\"router\": \"/\"\n\t\t\t},\n\t\t\t\"props\": {\n\t\t\t\t\"ref\": \"outterView\",\n\t\t\t\t\"autoLoading\": true\n\t\t\t},\n\t\t\t\"fileName\": \"test\",\n\t\t\t\"state\": {\n\t\t\t\t\"text\": \"outter\"\n\t\t\t},\n\t\t\t\"lifeCycles\": {\n\t\t\t\t\"componentDidMount\": {\n\t\t\t\t\t\"type\": \"JSFunction\",\n\t\t\t\t\t\"value\": \"function() { console.log('componentDidMount'); }\"\n\t\t\t\t}\n\t\t\t},\n\t\t\tdataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/user\n          {\n            id: 'user',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data;\\n}',\n            },\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/orders\n          {\n            id: 'orders',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: \"https://shs.xxx.com/mock/1458/demo/orders\",\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data.result;\\n}',\n            },\n          },\n        ],\n        dataHandler: {\n          type: 'JSExpression',\n          value: 'function (dataMap) {\\n  console.info(\"All datasources loaded:\", dataMap);\\n}',\n        },\n      },\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"componentName\": \"Form\",\n\t\t\t\t\t\"id\": \"node$2\",\n\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\"labelCol\": {\n\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\"value\": \"this.state.colNum\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"style\": {},\n\t\t\t\t\t\t\"ref\": \"testForm\"\n\t\t\t\t\t},\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$3\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"姓名：\",\n\t\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\t\"initValue\": \"李雷\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Input\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$4\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"placeholder\": \"请输入\",\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\"width\": 320\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$5\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"年龄：\",\n\t\t\t\t\t\t\t\t\"name\": \"age\",\n\t\t\t\t\t\t\t\t\"initValue\": \"22\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$6\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$7\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"职业：\",\n\t\t\t\t\t\t\t\t\"name\": \"profession\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Select\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$8\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"dataSource\": [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"教师\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"t\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"医生\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"d\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"歌手\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"s\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Div\",\n\t\t\t\t\t\t\t\"id\": \"node$9\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\"textAlign\": \"center\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$a\",\n\t\t\t\t\t\t\t\t\t\"props\": {},\n\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$b\",\n\t\t\t\t\t\t\t\t\t\t\t\"condition\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"this.index >= 1\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"loop\": [\"a\", \"b\", \"c\"],\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"primary\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"this.item\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"constants\": {\n\t\t\"ENV\": \"prod\",\n\t\t\"DOMAIN\": \"xxx.xxx.com\"\n\t},\n\t\"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n\t\"config\": {\n\t\t\"sdkVersion\": \"1.0.3\",\n\t\t\"historyMode\": \"hash\",\n\t\t\"targetRootID\": \"J_Container\",\n\t\t\"layout\": {\n\t\t\t\"componentName\": \"BasicLayout\",\n\t\t\t\"props\": {\n\t\t\t\t\"logo\": \"...\",\n\t\t\t\t\"name\": \"测试网站\"\n\t\t\t}\n\t\t},\n\t\t\"theme\": {\n\t\t\t\"package\": \"@alife/theme-fusion\",\n\t\t\t\"version\": \"^0.1.0\",\n\t\t\t\"primary\": \"#ff9966\"\n\t\t}\n\t},\n\t\"meta\": {\n\t\t\"name\": \"demo应用\",\n\t\t\"git_group\": \"appGroup\",\n\t\t\"project_name\": \"app_demo\",\n\t\t\"description\": \"这是一个测试应用\",\n\t\t\"spma\": \"spa23d\",\n\t\t\"creator\": \"月飞\"\n\t}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.19.18\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'i18n-jwg27yo4': '你好',\n    'i18n-jwg27yo3': '中国',\n  },\n  'en-US': {\n    'i18n-jwg27yo4': 'Hello',\n    'i18n-jwg27yo3': 'China',\n  },\n};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Form, Input, NumberPicker, Select, Button } from '@alifd/next';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter' };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidMount() {\n    console.log('componentDidMount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}>\n        <Form\n          labelCol={__$$eval(() => this.state.colNum)}\n          style={{}}\n          ref={this._refsManager.linkRef('testForm')}\n        >\n          <Form.Item\n            label={__$$eval(() => this.i18n('i18n-jwg27yo4'))}\n            name=\"name\"\n            initValue=\"李雷\"\n          >\n            <Input placeholder=\"请输入\" size=\"medium\" style={{ width: 320 }} />\n          </Form.Item>\n          <Form.Item label=\"年龄：\" name=\"age\" initValue=\"22\">\n            <NumberPicker size=\"medium\" type=\"normal\" />\n          </Form.Item>\n          <Form.Item label=\"职业：\" name=\"profession\">\n            <Select\n              dataSource={[\n                { label: '教师', value: 't' },\n                { label: '医生', value: 'd' },\n                { label: '歌手', value: 's' },\n              ]}\n            />\n          </Form.Item>\n          <div style={{ textAlign: 'center' }}>\n            <Button.Group>\n              <Button\n                type=\"primary\"\n                style={{ margin: '0 5px 0 5px' }}\n                htmlType=\"submit\"\n              >\n                提交\n              </Button>\n              <Button\n                type=\"normal\"\n                style={{ margin: '0 5px 0 5px' }}\n                htmlType=\"reset\"\n              >\n                重置\n              </Button>\n            </Button.Group>\n          </div>\n        </Form>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/schema.json5",
    "content": "{\n\t\"version\": \"1.0.0\",\n\t\"componentsMap\": [\n\t\t{\n\t\t\t\"componentName\": \"Button\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\",\n\t\t\t\"subName\": \"Group\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Input\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Input\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\",\n\t\t\t\"subName\": \"Item\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"NumberPicker\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Select\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Select\"\n\t\t}\n\t],\n\t\"componentsTree\": [\n\t\t{\n\t\t\t\"componentName\": \"Page\",\n\t\t\t\"id\": \"node$1\",\n\t\t\t\"meta\": {\n\t\t\t\t\"title\": \"测试\",\n\t\t\t\t\"router\": \"/\"\n\t\t\t},\n\t\t\t\"props\": {\n\t\t\t\t\"ref\": \"outterView\",\n\t\t\t\t\"autoLoading\": true\n\t\t\t},\n\t\t\t\"fileName\": \"test\",\n\t\t\t\"state\": {\n\t\t\t\t\"text\": \"outter\"\n\t\t\t},\n\t\t\t\"lifeCycles\": {\n\t\t\t\t\"componentDidMount\": {\n\t\t\t\t\t\"type\": \"JSFunction\",\n\t\t\t\t\t\"value\": \"function() { console.log('componentDidMount'); }\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"componentName\": \"Form\",\n\t\t\t\t\t\"id\": \"node$2\",\n\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\"labelCol\": {\n\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\"value\": \"this.state.colNum\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"style\": {},\n\t\t\t\t\t\t\"ref\": \"testForm\"\n\t\t\t\t\t},\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$3\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": {\n\t\t\t\t\t\t\t\t\ttype: 'JSExpression',\n\t\t\t\t\t\t\t\t\tvalue: 'this.i18n(\"i18n-jwg27yo4\")',\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\t\"initValue\": \"李雷\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Input\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$4\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"placeholder\": \"请输入\",\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\"width\": 320\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$5\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"年龄：\",\n\t\t\t\t\t\t\t\t\"name\": \"age\",\n\t\t\t\t\t\t\t\t\"initValue\": \"22\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$6\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$7\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"职业：\",\n\t\t\t\t\t\t\t\t\"name\": \"profession\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Select\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$8\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"dataSource\": [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"教师\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"t\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"医生\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"d\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"歌手\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"s\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Div\",\n\t\t\t\t\t\t\t\"id\": \"node$9\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\"textAlign\": \"center\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$a\",\n\t\t\t\t\t\t\t\t\t\"props\": {},\n\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$b\",\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"primary\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"htmlType\": \"submit\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\"提交\"\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$d\",\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"htmlType\": \"reset\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\"重置\"\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"constants\": {\n\t\t\"ENV\": \"prod\",\n\t\t\"DOMAIN\": \"xxx.xxx.com\"\n\t},\n\t\"i18n\": {\n\t\t\"zh-CN\": {\n\t\t\t\"i18n-jwg27yo4\": \"你好\",\n\t\t\t\"i18n-jwg27yo3\": \"中国\"\n\t\t},\n\t\t\"en-US\": {\n\t\t\t\"i18n-jwg27yo4\": \"Hello\",\n\t\t\t\"i18n-jwg27yo3\": \"China\"\n\t\t}\n\t},\n\t\"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n\t\"config\": {\n\t\t\"sdkVersion\": \"1.0.3\",\n\t\t\"historyMode\": \"hash\",\n\t\t\"targetRootID\": \"J_Container\",\n\t\t\"layout\": {\n\t\t\t\"componentName\": \"BasicLayout\",\n\t\t\t\"props\": {\n\t\t\t\t\"logo\": \"...\",\n\t\t\t\t\"name\": \"测试网站\"\n\t\t\t}\n\t\t},\n\t\t\"theme\": {\n\t\t\t\"package\": \"@alife/theme-fusion\",\n\t\t\t\"version\": \"^0.1.0\",\n\t\t\t\"primary\": \"#ff9966\"\n\t\t}\n\t},\n\t\"meta\": {\n\t\t\"name\": \"demo应用\",\n\t\t\"git_group\": \"appGroup\",\n\t\t\"project_name\": \"app_demo\",\n\t\t\"description\": \"这是一个测试应用\",\n\t\t\"spma\": \"spa23d\",\n\t\t\"creator\": \"月飞\"\n\t}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.26.15\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"@alilc/b6-page\": \"^0.1.0\",\n    \"@alilc/b6-text\": \"^0.1.0\",\n    \"@alilc/b6-compact-legao-builtin\": \"1.x\",\n    \"antd\": \"3.x\",\n    \"@alilc/b6-util-mocks\": \"1.x\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Page } from '@alilc/b6-page';\n\nimport { Text } from '@alilc/b6-text';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Aaaa$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(window.location.search),\n    },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'urlParams',\n          type: 'urlParams',\n          description: 'URL参数',\n          options: function () {\n            return {\n              uri: '',\n            };\n          }.bind(_this),\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div title=\"\" backgroundColor=\"#fff\" textColor=\"#333\" style={{}}>\n        <Text\n          content=\"欢迎使用 BuildSuccess！sadsad\"\n          style={{}}\n          fieldId=\"text_kp6ci11t\"\n        />\n      </div>\n    );\n  }\n}\n\nexport default Aaaa$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/utils.js",
    "content": "import legaoBuiltin from '@alilc/b6-compact-legao-builtin';\n\nimport { message, Modal as modal } from 'antd';\n\nimport { mocks } from '@alilc/b6-util-mocks';\n\nimport { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {\n  legaoBuiltin,\n\n  message,\n\n  mocks,\n\n  modal,\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/b6-page',\n      version: '^0.1.0',\n      componentName: 'Page',\n      destructuring: true,\n      exportName: 'Page',\n    },\n    {\n      package: '@alilc/b6-text',\n      version: '^0.1.0',\n      componentName: 'Text',\n      destructuring: true,\n      exportName: 'Text',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_ockp6ci0hm1',\n      props: {\n        title: '',\n        backgroundColor: '#fff',\n        textColor: '#333',\n        style: {},\n      },\n      fileName: 'aaaa',\n      dataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n            description: 'URL参数',\n            options: {\n              uri: '',\n            },\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Text',\n          id: 'node_ockp6ci0hm2',\n          props: {\n            content: '欢迎使用 BuildSuccess！sadsad',\n            style: {},\n            fieldId: 'text_kp6ci11t',\n          },\n        },\n      ],\n      meta: {\n        router: '/aaaa',\n      },\n      methodsModule: {\n        type: 'JSModule',\n        compiled: '\"use strict\";\\n\\nObject.defineProperty(exports, \"__esModule\", {\\n  value: true\\n});\\nexports.helloPage = helloPage;\\n\\n/**\\n * Private, and can be re-used functions\\n * Actions panel help documentation：\\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\\n */\\nfunction printLog(obj) {\\n  console.info(obj);\\n}\\n/**\\n * page function\\n */\\n\\n\\nfunction helloPage() {\\n  console.log(\\'hello page\\');\\n}',\n        source: \"/**\\n * Private, and can be re-used functions\\n * Actions panel help documentation：\\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\\n */\\nfunction printLog(obj) {\\n  console.info(obj);\\n}\\n\\n/**\\n * page function\\n */\\nexport function helloPage() {\\n  console.log('hello page');\\n}\",\n      },\n    },\n  ],\n  i18n: {},\n  utils: [\n    {\n      name: 'legaoBuiltin',\n      type: 'npm',\n      content: {\n        exportName: 'legaoBuiltin',\n        package: '@alilc/b6-compact-legao-builtin',\n        version: '1.x',\n      },\n    },\n    {\n      name: 'message',\n      type: 'npm',\n      content: {\n        package: 'antd',\n        version: '3.x',\n        destructuring: true,\n        exportName: 'message',\n      },\n    },\n    {\n      name: 'mocks',\n      type: 'npm',\n      content: {\n        package: '@alilc/b6-util-mocks',\n        version: '1.x',\n        exportName: 'mocks',\n        destructuring: true,\n      },\n    },\n    {\n      name: 'modal',\n      type: 'npm',\n      content: {\n        package: 'antd',\n        version: '3.x',\n        destructuring: true,\n        exportName: 'Modal',\n      },\n    },\n  ],\n  constants: {},\n  dataSource: {\n    list: [],\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n    miniAppBuildType: 'runtime',\n  },\n  meta: {\n    name: 'jinyuan-test2',\n    git_group: 'b6',\n    project_name: 'jinyuan-test2',\n    description: '瑾源测试',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.19.18\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'i18n-jwg27yo4': '你好',\n    'i18n-jwg27yo3': '中国',\n  },\n  'en-US': {\n    'i18n-jwg27yo4': 'Hello',\n    'i18n-jwg27yo3': 'China',\n  },\n};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport Super, {\n  Button,\n  Input as CustomInput,\n  Form,\n  NumberPicker,\n  Select,\n  SearchTable as SearchTableExport,\n} from '@alifd/next';\n\nimport SuperOther from '@alifd/next';\n\nimport '@alifd/next/lib/super/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/search-table/style';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst SuperSub = Super.Sub;\n\nconst SelectOption = Select.Option;\n\nconst SearchTable = SearchTableExport.default;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  componentDidMount() {}\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div>\n        <Super title={__$$eval(() => this.state.title)} />\n        <SuperSub />\n        <SuperOther />\n        <Button />\n        <Button.Group />\n        <CustomInput />\n        <Form.Item />\n        <NumberPicker />\n        <SelectOption />\n        <SearchTable />\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/schema.json5",
    "content": "{\n\t\"version\": \"1.0.0\",\n\t\"componentsMap\": [\n\t\t{\n\t\t\t\"componentName\": \"Super\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": false,\n\t\t\t\"exportName\": \"Super\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SuperOther\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": false,\n\t\t\t\"exportName\": \"Super\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SuperSub\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": false,\n\t\t\t\"exportName\": \"Super\",\n\t\t\t\"subName\": \"Sub\",\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SearchTable\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"SearchTable\",\n\t\t\t\"subName\": \"default\",\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\",\n\t\t\t\"subName\": \"Group\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"CustomInput\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Input\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\",\n\t\t\t\"subName\": \"Item\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"NumberPicker\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SelectOption\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Select\",\n\t\t\t\"subName\": \"Option\"\n\t\t}\n\t],\n\t\"componentsTree\": [\n\t\t{\n\t\t\t\"componentName\": \"Page\",\n\t\t\t\"id\": \"node$1\",\n\t\t\t\"meta\": {\n\t\t\t\t\"title\": \"测试\",\n\t\t\t\t\"router\": \"/\"\n\t\t\t},\n\t\t\t\"fileName\": \"test\",\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"componentName\": \"Super\",\n\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\"title\": {\n\t\t\t\t\t\t\t\"type\":\"variable\",\n\t\t\t\t\t\t\t\"value\":\"标题\",\n\t\t\t\t\t\t\t\"variable\":\"this.state.title\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ \"componentName\": \"SuperSub\" },\n\t\t\t\t{ \"componentName\": \"SuperOther\" },\n\t\t\t\t{ \"componentName\": \"Button\" },\n\t\t\t\t{ \"componentName\": \"Button.Group\" },\n\t\t\t\t{ \"componentName\": \"CustomInput\" },\n\t\t\t\t{ \"componentName\": \"Form.Item\" },\n\t\t\t\t{ \"componentName\": \"NumberPicker\" },\n\t\t\t\t{ \"componentName\": \"SelectOption\" },\n\t\t\t\t{ \"componentName\": \"SearchTable\" },\n\t\t\t]\n\t\t}\n\t],\n\t\"constants\": {\n\t\t\"ENV\": \"prod\",\n\t\t\"DOMAIN\": \"xxx.xxx.com\"\n\t},\n\t\"i18n\": {\n\t\t\"zh-CN\": {\n\t\t\t\"i18n-jwg27yo4\": \"你好\",\n\t\t\t\"i18n-jwg27yo3\": \"中国\"\n\t\t},\n\t\t\"en-US\": {\n\t\t\t\"i18n-jwg27yo4\": \"Hello\",\n\t\t\t\"i18n-jwg27yo3\": \"China\"\n\t\t}\n\t},\n\t\"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n\t\"config\": {\n\t\t\"sdkVersion\": \"1.0.3\",\n\t\t\"historyMode\": \"hash\",\n\t\t\"targetRootID\": \"J_Container\",\n\t\t\"layout\": {\n\t\t\t\"componentName\": \"BasicLayout\",\n\t\t\t\"props\": {\n\t\t\t\t\"logo\": \"...\",\n\t\t\t\t\"name\": \"测试网站\"\n\t\t\t}\n\t\t},\n\t\t\"theme\": {\n\t\t\t\"package\": \"@alife/theme-fusion\",\n\t\t\t\"version\": \"^0.1.0\",\n\t\t\t\"primary\": \"#ff9966\"\n\t\t}\n\t},\n\t\"meta\": {\n\t\t\"name\": \"demo应用\",\n\t\t\"git_group\": \"appGroup\",\n\t\t\"project_name\": \"app_demo\",\n\t\t\"description\": \"这是一个测试应用\",\n\t\t\"spma\": \"spa23d\",\n\t\t\"creator\": \"月飞\"\n\t}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.26.15\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-fetch-handler\": \"^1.0.0\",\n    \"@alife/container\": \"^1.0.0\",\n    \"@alife/mc-assets-1935\": \"0.1.9\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n  Text as NextText,\n} from '@alife/container/lib/index.js';\n\nimport { AliSearchTable as AliSearchTableExport } from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst NextBlockCell = NextBlock.Cell;\n\nconst AliSearchTable = AliSearchTableExport.default;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: { fetch: __$$createFetchRequestHandler() },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter', isShowDialog: false };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          type: 'fetch',\n          isInit: function () {\n            return true;\n          }.bind(_this),\n          options: function () {\n            return {\n              params: {},\n              method: 'GET',\n              isCors: true,\n              timeout: 5000,\n              headers: {},\n              uri: 'https://mocks.xxx.com/mock/jjpin/user/list',\n            };\n          }.bind(_this),\n          id: 'users',\n        },\n      ],\n    };\n  }\n\n  componentWillUnmount() {\n    console.log('will umount');\n  }\n\n  componentDidUpdate(prevProps, prevState, snapshot) {\n    console.log(this.state);\n  }\n\n  testFunc() {\n    console.log('test func');\n  }\n\n  onClick() {\n    this.setState({\n      isShowDialog: true,\n    });\n  }\n\n  closeDialog() {\n    this.setState({\n      isShowDialog: false,\n    });\n  }\n\n  onSearch(values) {\n    console.log('search form:', values);\n    console.log(this.dataSourceMap);\n    this.dataSourceMap['users'].load(values);\n  }\n\n  onClear() {\n    console.log('form reset');\n    this.setState({\n      isShowDialog: true,\n    });\n  }\n\n  onPageChange(page, pageSize) {\n    console.log(`page: ${page}, pageSize: ${pageSize}`);\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n\n    console.log('did mount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <NextPage\n          columns={12}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={\n            <NextP\n              wrap={true}\n              type=\"body2\"\n              verAlign=\"middle\"\n              textSpacing={true}\n              align=\"left\"\n              flex={true}\n            >\n              <NextText type=\"h5\">员工列表</NextText>\n            </NextP>\n          }\n          headerTest={[]}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns=\"1fr\"\n          >\n            <NextBlockCell\n              title=\"\"\n              primaryKey=\"732\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              colSpan={1}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={true}\n                type=\"body2\"\n                textSpacing={true}\n                verAlign=\"center\"\n                align=\"flex-start\"\n                flex={true}\n              >\n                <AliSearchTable\n                  dataSource={__$$eval(() => this.state.users.data)}\n                  rowKey=\"workid\"\n                  columns={[\n                    { title: '花名', dataIndex: 'cname' },\n                    { title: 'user_id', dataIndex: 'workid' },\n                    { title: '部门', dataIndex: 'dep' },\n                  ]}\n                  searchItems={[\n                    { label: '姓名', name: 'cname' },\n                    { label: '部门', name: 'dep' },\n                  ]}\n                  onSearch={function () {\n                    return this.onSearch.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                  onClear={function () {\n                    return this.onClear.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                  pagination={{\n                    defaultPageSize: '',\n                    onPageChange: function () {\n                      return this.onPageChange.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this),\n                    showSizeChanger: true,\n                  }}\n                />\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={1}\n          >\n            <NextBlockCell\n              title=\"\"\n              primaryKey=\"472\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              colSpan={1}\n              rowSpan={1}\n            />\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/schema.json5",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.9\",\n      \"exportName\": \"AliSearchTable\",\n      \"main\": \"build/lowcode/index.js\",\n      \"subName\": \"default\",\n      \"destructuring\": true,\n      \"componentName\": \"AliSearchTable\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextP\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"Cell\",\n      \"componentName\": \"NextBlockCell\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlock\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Text\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextText\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextPage\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"style\": {\n          \"height\": \"100%\"\n        }\n      },\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": [\n          {\n            \"type\": \"fetch\",\n            \"isInit\": true,\n            \"options\": {\n              \"params\": {},\n              \"method\": \"GET\",\n              \"isCors\": true,\n              \"timeout\": 5000,\n              \"headers\": {},\n              \"uri\": \"https://mocks.xxx.com/mock/jjpin/user/list\"\n            },\n            \"id\": \"users\"\n          }\n        ]\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}\",\n      \"lifeCycles\": {\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('did mount');\\n  }\"\n        },\n        \"componentWillUnmount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('will umount');\\n  }\"\n        },\n        \"componentDidUpdate\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(prevProps, prevState, snapshot) {\\n    console.log(this.state);\\n  }\"\n        }\n      },\n      \"methods\": {\n        \"testFunc\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('test func');\\n  }\"\n        },\n        \"onClick\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      isShowDialog: true\\n    })\\n  }\"\n        },\n        \"closeDialog\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      isShowDialog: false\\n    })\\n  }\"\n        },\n        \"onSearch\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(values) {\\n    console.log('search form:', values)\\n    console.log(this.dataSourceMap);\\n    this.dataSourceMap['users'].load(values)\\n  }\"\n        },\n        \"onClear\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('form reset')\\n    this.setState({\\n      isShowDialog: true\\n    })\\n  }\"\n        },\n        \"onPageChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(page, pageSize) {\\n    console.log(`page: ${page}, pageSize: ${pageSize}`)\\n  }\"\n        }\n      },\n      \"state\": {\n        \"text\": \"outter\",\n        \"isShowDialog\": false\n      },\n      \"children\": [\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ockkgjwi8z1\",\n          \"props\": {\n            \"columns\": 12,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": {\n              \"type\": \"JSSlot\",\n              \"value\": [\n                {\n                  \"componentName\": \"NextP\",\n                  \"id\": \"node_ockkgjwi8zn\",\n                  \"props\": {\n                    \"wrap\": true,\n                    \"type\": \"body2\",\n                    \"verAlign\": \"middle\",\n                    \"textSpacing\": true,\n                    \"align\": \"left\",\n                    \"flex\": true\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextText\",\n                      \"id\": \"node_ockkgjwi8zo\",\n                      \"props\": {\n                        \"type\": \"h5\",\n                        \"children\": \"员工列表\"\n                      }\n                    }\n                  ]\n                }\n              ],\n              \"title\": \"header\"\n            },\n            \"headerTest\": {\n              \"type\": \"JSSlot\",\n              \"value\": [],\n              \"title\": \"header\"\n            },\n            \"headerProps\": {\n              \"background\": \"surface\"\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"footer\"\n            },\n            \"minHeight\": \"100vh\"\n          },\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockkgjwi8z2\",\n              \"props\": {\n                \"prefix\": \"next-\",\n                \"placeholderStyle\": {\n                  \"height\": \"100%\"\n                },\n                \"noPadding\": false,\n                \"noBorder\": false,\n                \"background\": \"surface\",\n                \"colSpan\": 12,\n                \"rowSpan\": 1,\n                \"childTotalColumns\": \"1fr\"\n              },\n              \"title\": \"分区\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockkgjwi8z3\",\n                  \"props\": {\n                    \"title\": \"\",\n                    \"primaryKey\": \"732\",\n                    \"prefix\": \"next-\",\n                    \"placeholderStyle\": {\n                      \"height\": \"100%\"\n                    },\n                    \"colSpan\": 1,\n                    \"rowSpan\": 1\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ockkgjwi8zu\",\n                      \"props\": {\n                        \"wrap\": true,\n                        \"type\": \"body2\",\n                        \"textSpacing\": true,\n                        \"verAlign\": \"center\",\n                        \"align\": \"flex-start\",\n                        \"flex\": true\n                      },\n                      \"children\": [\n                        {\n                          \"componentName\": \"AliSearchTable\",\n                          \"id\": \"node_ockkgjwi8zv\",\n                          \"props\": {\n                            \"dataSource\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.state.users.data\"\n                            },\n                            \"rowKey\": \"workid\",\n                            \"columns\": [\n                              {\n                                \"title\": \"花名\",\n                                \"dataIndex\": \"cname\"\n                              },\n                              {\n                                \"title\": \"user_id\",\n                                \"dataIndex\": \"workid\"\n                              },\n                              {\n                                \"title\": \"部门\",\n                                \"dataIndex\": \"dep\"\n                              }\n                            ],\n                            \"searchItems\": [\n                              {\n                                \"label\": \"姓名\",\n                                \"name\": \"cname\"\n                              },\n                              {\n                                \"label\": \"部门\",\n                                \"name\": \"dep\"\n                              }\n                            ],\n                            \"onSearch\": {\n                              \"type\": \"JSFunction\",\n                              \"value\": \"function(){ return this.onSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                            },\n                            \"onClear\": {\n                              \"type\": \"JSFunction\",\n                              \"value\": \"function(){ return this.onClear.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                            },\n                            \"pagination\": {\n                              \"defaultPageSize\": \"\",\n                              \"onPageChange\": {\n                                \"type\": \"JSFunction\",\n                                \"value\": \"function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                              },\n                              \"showSizeChanger\": true\n                            }\n                          }\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ockm4jxd6313\",\n          \"props\": {\n            \"columns\": 12,\n            \"headerDivider\": true,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"header\"\n            },\n            \"headerProps\": {\n              \"background\": \"surface\"\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"footer\"\n            },\n            \"minHeight\": \"100vh\"\n          },\n          \"title\": \"页面\",\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockm4jxd6314\",\n              \"props\": {\n                \"prefix\": \"next-\",\n                \"placeholderStyle\": {\n                  \"height\": \"100%\"\n                },\n                \"noPadding\": false,\n                \"noBorder\": false,\n                \"background\": \"surface\",\n                \"colSpan\": 12,\n                \"rowSpan\": 1,\n                \"childTotalColumns\": 1\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockm4jxd6315\",\n                  \"props\": {\n                    \"title\": \"\",\n                    \"primaryKey\": \"472\",\n                    \"prefix\": \"next-\",\n                    \"placeholderStyle\": {\n                      \"height\": \"100%\"\n                    },\n                    \"colSpan\": 1,\n                    \"rowSpan\": 1\n                  }\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.26.15\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alife/container\": \"0.3.7\",\n    \"@alilc/antd-lowcode\": \"0.5.4\",\n    \"@alife/mc-assets-1935\": \"0.1.16\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport {\n  Card,\n  Space,\n  Typography,\n  Select,\n  Button,\n  Modal,\n  Form,\n  InputNumber,\n  Input,\n} from '@alilc/antd-lowcode/dist/antd-lowcode.esm.js';\n\nimport { AliAutoSearchTable } from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst NextBlockCell = NextBlock.Cell;\n\nconst AliAutoSearchTableDefault = AliAutoSearchTable.default;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      name: 'nongzhou',\n      gateways: [],\n      selectedGateway: null,\n      records: [],\n      modalVisible: false,\n    };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentWillUnmount() {\n    /* ... */\n  }\n\n  componentDidUpdate() {\n    /* ... */\n  }\n\n  onChange() {\n    /* ... */\n  }\n\n  getActions() {\n    /* ... */\n  }\n\n  onCreateOrder() {\n    /* ... */\n  }\n\n  onCancelModal() {\n    /* ... */\n  }\n\n  onConfirmCreateOrder() {\n    /* ... */\n  }\n\n  componentDidMount() {}\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n          style={{ cursor: 'pointer' }}\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            layoutmode=\"O\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={12}\n          >\n            <NextBlockCell\n              title=\"\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              layoutmode=\"O\"\n              childTotalColumns={12}\n              isAutoContainer={true}\n              colSpan={12}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                full={true}\n                flex={true}\n              >\n                <Card title=\"\">\n                  <Space size={0} align=\"center\" direction=\"horizontal\">\n                    <Typography.Text>所在网关：</Typography.Text>\n                    <Select\n                      style={{\n                        marginTop: '16px',\n                        marginRight: '16px',\n                        marginBottom: '16px',\n                        marginLeft: '16px',\n                        width: '400px',\n                        display: 'inline-block',\n                      }}\n                      options={__$$eval(() => this.state.gateways)}\n                      mode=\"single\"\n                      defaultValue={['auto-edd-uniproxy']}\n                      labelInValue={true}\n                      showSearch={true}\n                      allowClear={false}\n                      placeholder=\"请选取网关\"\n                      showArrow={true}\n                      loading={false}\n                      tokenSeparators={[]}\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onChange',\n                            relatedEventName: 'onChange',\n                          },\n                        ],\n                        eventList: [\n                          { name: 'onBlur', disabled: false },\n                          { name: 'onChange', disabled: true },\n                          { name: 'onDeselect', disabled: false },\n                          { name: 'onFocus', disabled: false },\n                          { name: 'onInputKeyDown', disabled: false },\n                          { name: 'onMouseEnter', disabled: false },\n                          { name: 'onMouseLeave', disabled: false },\n                          { name: 'onPopupScroll', disabled: false },\n                          { name: 'onSearch', disabled: false },\n                          { name: 'onSelect', disabled: false },\n                          { name: 'onDropdownVisibleChange', disabled: false },\n                        ],\n                      }}\n                      onChange={function () {\n                        this.onChange.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this)}\n                    />\n                  </Space>\n                  <Button\n                    type=\"primary\"\n                    style={{\n                      display: 'block',\n                      marginTop: '20px',\n                      marginBottom: '20px',\n                    }}\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onClick',\n                          relatedEventName: 'onCreateOrder',\n                        },\n                      ],\n                      eventList: [{ name: 'onClick', disabled: true }],\n                    }}\n                    onClick={function () {\n                      this.onCreateOrder.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  >\n                    创建发布单\n                  </Button>\n                  <Modal\n                    title=\"创建发布单\"\n                    visible={__$$eval(() => this.state.modalVisible)}\n                    footer=\"\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onCancel',\n                          relatedEventName: 'onCancelModal',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onCancel', disabled: true },\n                        { name: 'onOk', disabled: false },\n                      ],\n                    }}\n                    onCancel={function () {\n                      this.onCancelModal.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    zIndex={2000}\n                  >\n                    <Form\n                      labelCol={{ span: 6 }}\n                      wrapperCol={{ span: 14 }}\n                      onFinish={function () {\n                        this.onConfirmCreateOrder.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this)}\n                      name=\"basic\"\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onFinish',\n                            relatedEventName: 'onConfirmCreateOrder',\n                          },\n                        ],\n                        eventList: [\n                          { name: 'onFinish', disabled: true },\n                          { name: 'onFinishFailed', disabled: false },\n                          { name: 'onFieldsChange', disabled: false },\n                          { name: 'onValuesChange', disabled: false },\n                        ],\n                      }}\n                    >\n                      <Form.Item label=\"发布批次\">\n                        <InputNumber value={3} min={1} />\n                      </Form.Item>\n                      <Form.Item label=\"批次间隔时间\">\n                        <InputNumber value={3} />\n                      </Form.Item>\n                      <Form.Item label=\"备注 \">\n                        <Input.TextArea rows={3} placeholder=\"请输入\" />\n                      </Form.Item>\n                      <Form.Item\n                        wrapperCol={{ offset: 6 }}\n                        style={{\n                          flexDirection: 'row',\n                          alignItems: 'flex-end',\n                          justifyContent: 'center',\n                          display: 'flex',\n                        }}\n                        labelAlign=\"right\"\n                      >\n                        <Button type=\"primary\" htmlType=\"submit\">\n                          提交\n                        </Button>\n                        <Button\n                          style={{ marginLeft: 20 }}\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onClick',\n                                relatedEventName: 'onCancelModal',\n                              },\n                            ],\n                            eventList: [{ name: 'onClick', disabled: true }],\n                          }}\n                          onClick={function () {\n                            this.onCancelModal.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                        >\n                          取消\n                        </Button>\n                      </Form.Item>\n                    </Form>\n                  </Modal>\n                  <AliAutoSearchTableDefault\n                    rowKey=\"key\"\n                    dataSource={__$$eval(() => this.state.records)}\n                    columns={[\n                      {\n                        title: '发布名称',\n                        dataIndex: 'order_name',\n                        key: 'name',\n                      },\n                      {\n                        title: '类型',\n                        dataIndex: 'order_type_desc',\n                        key: 'age',\n                      },\n                      {\n                        title: '发布状态',\n                        dataIndex: 'order_status_desc',\n                        key: 'address',\n                      },\n                      { title: '发布人', dataIndex: 'creator_name' },\n                      { title: '当前批次/总批次', dataIndex: 'cur_batch_no' },\n                      {\n                        title: '发布机器/总机器',\n                        dataIndex: 'pubblish_ip_finish_num',\n                      },\n                      { title: '发布时间', dataIndex: 'publish_id' },\n                    ]}\n                    actions={__$$eval(() => this.actions || [])}\n                    getActions={function () {\n                      return this.getActions.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  />\n                </Card>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Text',\n      componentName: 'Typography.Text',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Space',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Space',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'InputNumber',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'InputNumber',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'TextArea',\n      componentName: 'Input.TextArea',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.16',\n      exportName: 'AliAutoSearchTable',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoSearchTableDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Card',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Card',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        componentDidMount: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n      },\n      methods: {\n        onChange: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        getActions: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        onCreateOrder: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        onCancelModal: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        onConfirmCreateOrder: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n      },\n      state: {\n        name: 'nongzhou',\n        gateways: [],\n        selectedGateway: null,\n        records: [],\n        modalVisible: false,\n      },\n      children: [\n        {\n          componentName: 'NextPage',\n          id: 'node_ocknqx3esma',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n            style: {\n              cursor: 'pointer',\n            },\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocknqx3esmb',\n              props: {\n                prefix: 'next-',\n                placeholderStyle: {\n                  height: '100%',\n                },\n                noPadding: false,\n                noBorder: false,\n                background: 'surface',\n                layoutmode: 'O',\n                colSpan: 12,\n                rowSpan: 1,\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocknqx3esmc',\n                  props: {\n                    title: '',\n                    prefix: 'next-',\n                    placeholderStyle: {\n                      height: '100%',\n                    },\n                    layoutmode: 'O',\n                    childTotalColumns: 12,\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocknqx3esm1j',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Card',\n                          id: 'node_ocknqx3esm1k',\n                          props: {\n                            title: '',\n                          },\n                          children: [\n                            {\n                              componentName: 'Space',\n                              id: 'node_ocknqx3esm1n',\n                              props: {\n                                size: 0,\n                                align: 'center',\n                                direction: 'horizontal',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Typography.Text',\n                                  id: 'node_ocknqx3esm1l',\n                                  props: {\n                                    children: '所在网关：',\n                                  },\n                                },\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ocknqx3esm1m',\n                                  props: {\n                                    style: {\n                                      marginTop: '16px',\n                                      marginRight: '16px',\n                                      marginBottom: '16px',\n                                      marginLeft: '16px',\n                                      width: '400px',\n                                      display: 'inline-block',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.gateways',\n                                    },\n                                    mode: 'single',\n                                    defaultValue: ['auto-edd-uniproxy'],\n                                    labelInValue: true,\n                                    showSearch: true,\n                                    allowClear: false,\n                                    placeholder: '请选取网关',\n                                    showArrow: true,\n                                    loading: false,\n                                    tokenSeparators: [],\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onChange',\n                                          relatedEventName: 'onChange',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onBlur',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onChange',\n                                          disabled: true,\n                                        },\n                                        {\n                                          name: 'onDeselect',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onFocus',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onInputKeyDown',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onMouseEnter',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onMouseLeave',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onPopupScroll',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onSearch',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onSelect',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onDropdownVisibleChange',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                    onChange: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Button',\n                              id: 'node_ockntwgdsn7',\n                              props: {\n                                type: 'primary',\n                                children: '创建发布单',\n                                style: {\n                                  display: 'block',\n                                  marginTop: '20px',\n                                  marginBottom: '20px',\n                                },\n                                __events: {\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'onCreateOrder',\n                                    },\n                                  ],\n                                  eventList: [\n                                    {\n                                      name: 'onClick',\n                                      disabled: true,\n                                    },\n                                  ],\n                                },\n                                onClick: {\n                                  type: 'JSFunction',\n                                  value: 'function(){this.onCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                              },\n                            },\n                            {\n                              componentName: 'Modal',\n                              id: 'node_ockntx4eo9p',\n                              props: {\n                                title: '创建发布单',\n                                visible: {\n                                  type: 'JSExpression',\n                                  value: 'this.state.modalVisible',\n                                },\n                                footer: '',\n                                __events: {\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onCancel',\n                                      relatedEventName: 'onCancelModal',\n                                    },\n                                  ],\n                                  eventList: [\n                                    {\n                                      name: 'onCancel',\n                                      disabled: true,\n                                    },\n                                    {\n                                      name: 'onOk',\n                                      disabled: false,\n                                    },\n                                  ],\n                                },\n                                onCancel: {\n                                  type: 'JSFunction',\n                                  value: 'function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                                zIndex: 2000,\n                              },\n                              hidden: true,\n                              children: [\n                                {\n                                  componentName: 'Form',\n                                  id: 'node_ockntx4eo9s',\n                                  props: {\n                                    labelCol: {\n                                      span: 6,\n                                    },\n                                    wrapperCol: {\n                                      span: 14,\n                                    },\n                                    onFinish: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onConfirmCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    name: 'basic',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onFinish',\n                                          relatedEventName: 'onConfirmCreateOrder',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onFinish',\n                                          disabled: true,\n                                        },\n                                        {\n                                          name: 'onFinishFailed',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onFieldsChange',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onValuesChange',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                  },\n                                  children: [\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo91k',\n                                      props: {\n                                        label: '发布批次',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'InputNumber',\n                                          id: 'node_ockntx4eo91l',\n                                          props: {\n                                            value: 3,\n                                            min: 1,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo91r',\n                                      props: {\n                                        label: '批次间隔时间',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'InputNumber',\n                                          id: 'node_ockntx4eo91s',\n                                          props: {\n                                            value: 3,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo91y',\n                                      props: {\n                                        label: '备注 ',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Input.TextArea',\n                                          id: 'node_ockntx4eo91z',\n                                          props: {\n                                            rows: 3,\n                                            placeholder: '请输入',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo9v',\n                                      props: {\n                                        wrapperCol: {\n                                          offset: 6,\n                                        },\n                                        style: {\n                                          flexDirection: 'row',\n                                          alignItems: 'flex-end',\n                                          justifyContent: 'center',\n                                          display: 'flex',\n                                        },\n                                        labelAlign: 'right',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ockntx4eo9w',\n                                          props: {\n                                            type: 'primary',\n                                            children: '提交',\n                                            htmlType: 'submit',\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ockntx4eo9x',\n                                          props: {\n                                            style: {\n                                              marginLeft: 20,\n                                            },\n                                            children: '取消',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'onCancelModal',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  ],\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'AliAutoSearchTableDefault',\n                              id: 'node_ocknqx3esm1q',\n                              props: {\n                                rowKey: 'key',\n                                dataSource: {\n                                  type: 'JSExpression',\n                                  value: 'this.state.records',\n                                },\n                                columns: [\n                                  {\n                                    title: '发布名称',\n                                    dataIndex: 'order_name',\n                                    key: 'name',\n                                  },\n                                  {\n                                    title: '类型',\n                                    dataIndex: 'order_type_desc',\n                                    key: 'age',\n                                  },\n                                  {\n                                    title: '发布状态',\n                                    dataIndex: 'order_status_desc',\n                                    key: 'address',\n                                  },\n                                  {\n                                    title: '发布人',\n                                    dataIndex: 'creator_name',\n                                  },\n                                  {\n                                    title: '当前批次/总批次',\n                                    dataIndex: 'cur_batch_no',\n                                  },\n                                  {\n                                    title: '发布机器/总机器',\n                                    dataIndex: 'pubblish_ip_finish_num',\n                                  },\n                                  {\n                                    title: '发布时间',\n                                    dataIndex: 'publish_id',\n                                  },\n                                ],\n                                actions: {\n                                  type: 'JSExpression',\n                                  value: 'this.actions || []',\n                                },\n                                getActions: {\n                                  type: 'JSFunction',\n                                  value: 'function(){ return this.getActions.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                              },\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.19.18\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-fetch-handler\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Form, Input, NumberPicker, Select, Button } from '@alifd/next';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(window.location.search),\n      fetch: __$$createFetchRequestHandler(),\n    },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter' };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'urlParams',\n          type: 'urlParams',\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n          options: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'user',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'orders',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/orders',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data.result;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n      dataHandler: function (dataMap) {\n        console.info('All datasources loaded:', dataMap);\n      },\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n\n    console.log('componentDidMount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}>\n        <Form\n          labelCol={__$$eval(() => this.state.colNum)}\n          style={{}}\n          ref={this._refsManager.linkRef('testForm')}\n        >\n          <Form.Item label=\"姓名：\" name=\"name\" initValue=\"李雷\">\n            <Input placeholder=\"请输入\" size=\"medium\" style={{ width: 320 }} />\n          </Form.Item>\n          <Form.Item label=\"年龄：\" name=\"age\" initValue=\"22\">\n            <NumberPicker size=\"medium\" type=\"normal\" />\n          </Form.Item>\n          <Form.Item label=\"职业：\" name=\"profession\">\n            <Select\n              dataSource={[\n                { label: '教师', value: 't' },\n                { label: '医生', value: 'd' },\n                { label: '歌手', value: 's' },\n              ]}\n            />\n          </Form.Item>\n          <div style={{ textAlign: 'center' }}>\n            <Button.Group>\n              {__$$evalArray(() => ['a', 'b', 'c']).map((item, index) =>\n                ((__$$context) =>\n                  !!false && (\n                    <Button type=\"primary\" style={{ margin: '0 5px 0 5px' }}>\n                      {__$$eval(() => item)}\n                    </Button>\n                  ))(__$$createChildContext(__$$context, { item, index }))\n              )}\n            </Button.Group>\n          </div>\n        </Form>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Button',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Button',\n    },\n    {\n      componentName: 'Button.Group',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Button',\n      subName: 'Group',\n    },\n    {\n      componentName: 'Input',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Input',\n    },\n    {\n      componentName: 'Form',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Form',\n    },\n    {\n      componentName: 'Form.Item',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Form',\n      subName: 'Item',\n    },\n    {\n      componentName: 'NumberPicker',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'NumberPicker',\n    },\n    {\n      componentName: 'Select',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Select',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node$1',\n      meta: {\n        title: '测试',\n        router: '/',\n      },\n      props: {\n        ref: 'outterView',\n        autoLoading: true,\n      },\n      fileName: 'test',\n      state: {\n        text: 'outter',\n      },\n      lifeCycles: {\n        componentDidMount: {\n          type: 'JSFunction',\n          value: \"function() { console.log('componentDidMount'); }\",\n        },\n      },\n      dataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/user\n          {\n            id: 'user',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data;\\n}',\n            },\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/orders\n          {\n            id: 'orders',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/orders',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data.result;\\n}',\n            },\n          },\n        ],\n        dataHandler: {\n          type: 'JSFunction',\n          value: 'function (dataMap) {\\n  console.info(\"All datasources loaded:\", dataMap);\\n}',\n        },\n      },\n      children: [\n        {\n          componentName: 'Form',\n          id: 'node$2',\n          props: {\n            labelCol: {\n              type: 'JSExpression',\n              value: 'this.state.colNum',\n            },\n            style: {},\n            ref: 'testForm',\n          },\n          children: [\n            {\n              componentName: 'Form.Item',\n              id: 'node$3',\n              props: {\n                label: '姓名：',\n                name: 'name',\n                initValue: '李雷',\n              },\n              children: [\n                {\n                  componentName: 'Input',\n                  id: 'node$4',\n                  props: {\n                    placeholder: '请输入',\n                    size: 'medium',\n                    style: {\n                      width: 320,\n                    },\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node$5',\n              props: {\n                label: '年龄：',\n                name: 'age',\n                initValue: '22',\n              },\n              children: [\n                {\n                  componentName: 'NumberPicker',\n                  id: 'node$6',\n                  props: {\n                    size: 'medium',\n                    type: 'normal',\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node$7',\n              props: {\n                label: '职业：',\n                name: 'profession',\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node$8',\n                  props: {\n                    dataSource: [\n                      {\n                        label: '教师',\n                        value: 't',\n                      },\n                      {\n                        label: '医生',\n                        value: 'd',\n                      },\n                      {\n                        label: '歌手',\n                        value: 's',\n                      },\n                    ],\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Div',\n              id: 'node$9',\n              props: {\n                style: {\n                  textAlign: 'center',\n                },\n              },\n              children: [\n                {\n                  componentName: 'Button.Group',\n                  id: 'node$a',\n                  props: {},\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node$b',\n                      condition: false,\n                      loop: ['a', 'b', 'c'],\n                      props: {\n                        type: 'primary',\n                        style: {\n                          margin: '0 5px 0 5px',\n                        },\n                      },\n                      children: [\n                        {\n                          type: 'JSExpression',\n                          value: 'this.item',\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  constants: {\n    ENV: 'prod',\n    DOMAIN: 'xxx.xxx.com',\n  },\n  css: 'body {font-size: 12px;} .table { width: 100px;}',\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'J_Container',\n    layout: {\n      componentName: 'BasicLayout',\n      props: {\n        logo: '...',\n        name: '测试网站',\n      },\n    },\n    theme: {\n      package: '@alife/theme-fusion',\n      version: '^0.1.0',\n      primary: '#ff9966',\n    },\n  },\n  meta: {\n    name: 'demo应用',\n    git_group: 'appGroup',\n    project_name: 'app_demo',\n    description: '这是一个测试应用',\n    spma: 'spa23d',\n    creator: '月飞',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.26.15\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alilc/antd-lowcode\": \"0.8.0\",\n    \"@alife/container\": \"0.3.7\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Modal,\n  Steps,\n  Form,\n  Input,\n  Checkbox,\n  Select,\n  DatePicker,\n  InputNumber,\n  Button,\n} from '@alilc/antd-lowcode/dist/antd-lowcode.esm.js';\n\nimport {\n  Text as NextText,\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst NextBlockCell = NextBlock.Cell;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      books: [],\n      currentStep: 0,\n      isModifyDialogVisible: false,\n      isModifyStatus: false,\n      secondCommitText: '完成并提交',\n      thirdAuditText: '审核中',\n      thirdButtonText: '修改',\n      customerProjectInfo: {\n        id: null,\n        systemProjectName: null,\n        projectVersionTypeArray: null,\n        projectVersionType: null,\n        versionLine: 2,\n        expectedTime: null,\n        expectedNum: null,\n        projectModal: null,\n        displayWidth: null,\n        displayHeight: null,\n        displayInch: null,\n        displayDpi: null,\n        mainSoc: null,\n        cpuCoreNum: null,\n        instructions: null,\n        osVersion: null,\n        status: null,\n      },\n      versionLinesArray: [\n        { label: 'AmapAuto 485', value: 1 },\n        { label: 'AmapAuto 505', value: 2 },\n      ],\n      projectModalsArray: [\n        { label: '车机', value: 1 },\n        { label: '车镜', value: 2 },\n        { label: '记录仪', value: 3 },\n        { label: '其他', value: 4 },\n      ],\n      osVersionsArray: [\n        { label: '安卓5', value: 1 },\n        { label: '安卓6', value: 2 },\n        { label: '安卓7', value: 3 },\n        { label: '安卓8', value: 4 },\n        { label: '安卓9', value: 5 },\n        { label: '安卓10', value: 6 },\n      ],\n      instructionsArray: [\n        { label: 'ARM64-V8', value: 'ARM64-V8' },\n        { label: 'ARM32-V7', value: 'ARM32-V7' },\n        { label: 'X86', value: 'X86' },\n        { label: 'X64', value: 'X64' },\n      ],\n    };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidUpdate(prevProps, prevState, snapshot) {}\n\n  componentWillUnmount() {}\n\n  __jp__init() {\n    /*...*/\n  }\n\n  __jp__initRouter() {\n    /*...*/\n  }\n\n  __jp__initDataSource() {\n    /*...*/\n  }\n\n  __jp__initEnv() {\n    /*...*/\n  }\n\n  __jp__initUtils() {\n    /*...*/\n  }\n\n  onFinishFirst() {\n    /*...*/\n  }\n\n  onClickPreSecond() {\n    /*...*/\n  }\n\n  onFinishSecond() {\n    /*...*/\n  }\n\n  onClickModifyThird() {\n    /*...*/\n  }\n\n  onOkModifyDialogThird() {\n    //第三步 修改 对话框 确定\n\n    this.setState({\n      currentStep: 0,\n      isModifyDialogVisible: false,\n    });\n  }\n\n  onCancelModifyDialogThird() {\n    //第三步 修改 对话框 取消\n\n    this.setState({\n      isModifyDialogVisible: false,\n    });\n  }\n\n  onFinishFailed() {}\n\n  onClickPreThird() {\n    // 第三步 上一步\n    this.setState({\n      currentStep: 1,\n    });\n  }\n\n  onClickFirstBack() {\n    // 第一步 返回按钮\n    this.$router.push('/myProjectList');\n  }\n\n  onClickSecondBack() {\n    // 第二步 返回按钮\n    this.$router.push('/myProjectList');\n  }\n\n  onClickThirdBack() {\n    // 第三步 返回按钮\n    this.$router.push('/myProjectList');\n  }\n\n  onValuesChange(_, values) {\n    this.setState({\n      customerProjectInfo: {\n        ...this.state.customerProjectInfo,\n        ...values,\n      },\n    });\n  }\n\n  componentDidMount() {}\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <Modal\n          title=\"是否修改\"\n          visible={__$$eval(() => this.state.isModifyDialogVisible)}\n          okText=\"确认\"\n          okType=\"\"\n          forceRender={false}\n          cancelText=\"取消\"\n          zIndex={2000}\n          destroyOnClose={false}\n          confirmLoading={false}\n          __events={{\n            eventDataList: [\n              {\n                type: 'componentEvent',\n                name: 'onOk',\n                relatedEventName: 'onOkModifyDialogThird',\n              },\n              {\n                type: 'componentEvent',\n                name: 'onCancel',\n                relatedEventName: 'onCancelModifyDialogThird',\n              },\n            ],\n            eventList: [\n              { name: 'onCancel', disabled: true },\n              { name: 'onOk', disabled: true },\n            ],\n          }}\n          onOk={function () {\n            this.onOkModifyDialogThird.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n          onCancel={function () {\n            this.onCancelModifyDialogThird.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n        >\n          <NextText\n            type=\"inherit\"\n            style={{\n              fontStyle: 'normal',\n              textAlign: 'left',\n              display: 'block',\n              fontFamily: 'arial, helvetica, microsoft yahei',\n              fontWeight: 'normal',\n            }}\n          >\n            修改将撤回此前填写的信息\n          </NextText>\n        </Modal>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n          style={{}}\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            layoutmode=\"O\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={12}\n          >\n            <NextBlockCell\n              title=\"\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              layoutmode=\"O\"\n              childTotalColumns={12}\n              isAutoContainer={true}\n              colSpan={12}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n                style={{ marginBottom: '24px' }}\n              >\n                <Steps current={__$$eval(() => this.state.currentStep)}>\n                  <Steps.Step title=\"版本申请\" description=\"\" />\n                  <Steps.Step title=\"机器配置\" subTitle=\"\" description=\"\" />\n                  <Steps.Step title=\"项目审批\" description=\"\" />\n                </Steps>\n              </NextP>\n              {!!__$$eval(() => this.state.currentStep === 0) && (\n                <NextP\n                  wrap={false}\n                  type=\"body2\"\n                  verAlign=\"middle\"\n                  textSpacing={true}\n                  align=\"left\"\n                  full={true}\n                  flex={true}\n                  style={{ display: 'flex', justifyContent: 'center' }}\n                >\n                  <Form\n                    labelCol={{ span: 10 }}\n                    wrapperCol={{ span: 10 }}\n                    onFinish={function () {\n                      this.onFinishFirst.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    name=\"basic\"\n                    style={{\n                      display: 'flex',\n                      flexDirection: 'column',\n                      width: '600px',\n                      justifyContent: 'center',\n                    }}\n                    layout=\"vertical\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onFinish',\n                          relatedEventName: 'onFinishFirst',\n                        },\n                        {\n                          type: 'componentEvent',\n                          name: 'onValuesChange',\n                          relatedEventName: 'onValuesChange',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onFinish', disabled: true },\n                        { name: 'onFinishFailed', disabled: false },\n                        { name: 'onFieldsChange', disabled: false },\n                        { name: 'onValuesChange', disabled: true },\n                      ],\n                    }}\n                    initialValues={__$$eval(\n                      () => this.state.customerProjectInfo\n                    )}\n                    onValuesChange={function () {\n                      this.onValuesChange.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  >\n                    {!!false && (\n                      <Form.Item\n                        label=\"\"\n                        style={{ width: '600px' }}\n                        colon={false}\n                        name=\"id\"\n                      >\n                        <Input\n                          placeholder=\"\"\n                          style={{ width: '600px' }}\n                          bordered={false}\n                          disabled={true}\n                        />\n                      </Form.Item>\n                    )}\n                    <Form.Item\n                      label=\"版本类型选择\"\n                      name=\"projectVersionTypeArray\"\n                      initialValue=\"\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ flexDirection: 'column', width: '600px' }}\n                      requiredobj={{\n                        required: true,\n                        message: '请选择版本类型',\n                      }}\n                    >\n                      <Checkbox.Group\n                        options={[\n                          { label: '基础版本', value: '3' },\n                          { label: 'AR导航', value: '1' },\n                          { label: '货车导航', value: '2' },\n                          { label: 'UI定制', value: '4', disabled: false },\n                        ]}\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"版本线选择\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ width: '600px' }}\n                      name=\"versionLine\"\n                      requiredobj={{ required: true, message: '请选择版本线' }}\n                      extra=\"\"\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.versionLinesArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        placeholder=\"请选择版本线\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"项目名称\"\n                      colon={false}\n                      required={true}\n                      style={{ display: 'flex' }}\n                      labelAlign=\"left\"\n                      extra=\"\"\n                      name=\"systemProjectName\"\n                      requiredobj={{\n                        required: true,\n                        message: '请按格式填写项目名称',\n                      }}\n                      typeobj={{\n                        type: 'string',\n                        message:\n                          '请输入项目名称，格式：公司简称-产品名称-版本类型',\n                      }}\n                      lenobj={{\n                        max: 100,\n                        message: '项目名称不能超过100个字符',\n                      }}\n                    >\n                      <Input\n                        placeholder=\"公司简称-产品名称-版本类型\"\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"预期交付时间\"\n                      style={{ width: '600px' }}\n                      colon={false}\n                      required={true}\n                      name=\"expectedTime\"\n                      labelAlign=\"left\"\n                      requiredobj={{\n                        required: true,\n                        message: '请填写预期交付时间',\n                      }}\n                    >\n                      <DatePicker\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"预期出货量\"\n                      style={{ width: '600px' }}\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请填写预期出货量',\n                      }}\n                      name=\"expectedNum\"\n                      labelAlign=\"left\"\n                      colon={false}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"单位（台）使用该版本的机器数量+预计出货量，请如实填写\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                        size=\"middle\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      wrapperCol={{ offset: '' }}\n                      style={{\n                        flexDirection: 'row',\n                        alignItems: 'baseline',\n                        justifyContent: 'space-between',\n                        width: '600px',\n                        display: 'block',\n                      }}\n                      labelAlign=\"left\"\n                      colon={false}\n                    >\n                      <Button\n                        style={{ margin: '0px' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickFirstBack',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickFirstBack.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        返回\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{\n                          boxShadow: 'rgba(31, 56, 88, 0.2) 0px 0px 0px 0px',\n                          float: 'right',\n                        }}\n                        __events={{\n                          eventDataList: [],\n                          eventList: [{ name: 'onClick', disabled: false }],\n                        }}\n                      >\n                        下一步\n                      </Button>\n                    </Form.Item>\n                  </Form>\n                </NextP>\n              )}\n              {!!__$$eval(() => this.state.currentStep === 1) && (\n                <NextP\n                  wrap={false}\n                  type=\"body2\"\n                  verAlign=\"middle\"\n                  textSpacing={true}\n                  align=\"left\"\n                  full={true}\n                  flex={true}\n                  style={{ display: 'flex', justifyContent: 'center' }}\n                >\n                  <Form\n                    labelCol={{ span: 10 }}\n                    wrapperCol={{ span: 10 }}\n                    onFinish={function () {\n                      this.onFinishSecond.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    name=\"basic\"\n                    style={{\n                      display: 'flex',\n                      flexDirection: 'column',\n                      width: '600px',\n                      justifyContent: 'center',\n                      height: '800px',\n                    }}\n                    layout=\"vertical\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onFinish',\n                          relatedEventName: 'onFinishSecond',\n                        },\n                        {\n                          type: 'componentEvent',\n                          name: 'onValuesChange',\n                          relatedEventName: 'onValuesChange',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onFinish', disabled: true },\n                        { name: 'onFinishFailed', disabled: false },\n                        { name: 'onFieldsChange', disabled: false },\n                        { name: 'onValuesChange', disabled: true },\n                      ],\n                    }}\n                    initialValues={__$$eval(\n                      () => this.state.customerProjectInfo\n                    )}\n                    onValuesChange={function () {\n                      this.onValuesChange.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  >\n                    <Form.Item\n                      label=\"设备类型选择\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ width: '600px' }}\n                      name=\"projectModal\"\n                      requiredobj={{\n                        required: true,\n                        message: '请选择设备类型',\n                      }}\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.projectModalsArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        placeholder=\"请选择设备类型\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕分辨率宽\"\n                      style={{ width: '600px' }}\n                      name=\"displayWidth\"\n                      colon={false}\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入屏幕分辨率宽',\n                      }}\n                      labelAlign=\"left\"\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"例如1280\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕分辨率高\"\n                      style={{ width: '600px' }}\n                      labelAlign=\"left\"\n                      colon={false}\n                      name=\"displayHeight\"\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入屏幕分辨率高',\n                      }}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"例如720\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕尺寸（inch）\"\n                      style={{ width: '600px' }}\n                      name=\"displayInch\"\n                      labelAlign=\"left\"\n                      required={true}\n                      colon={false}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入屏幕尺寸',\n                      }}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"请输入尺寸\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕DPI\"\n                      style={{ width: '600px' }}\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={false}\n                      name=\"displayDpi\"\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"UI定制项目必填\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"芯片名称\"\n                      colon={false}\n                      required={true}\n                      style={{ display: 'flex' }}\n                      labelAlign=\"left\"\n                      extra=\"\"\n                      name=\"mainSoc\"\n                      requiredobj={{\n                        required: true,\n                        message: '请输入芯片名称',\n                      }}\n                      lenobj={{ max: 50, message: '芯片名称不能超过50个字符' }}\n                    >\n                      <Input\n                        placeholder=\"请输入芯片名称\"\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"芯片核数\"\n                      style={{ width: '600px' }}\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入芯片核数',\n                      }}\n                      name=\"cpuCoreNum\"\n                      labelAlign=\"left\"\n                      colon={false}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"请输入芯片核数\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        defaultValue=\"\"\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"指令集\"\n                      style={{ width: '600px' }}\n                      required={true}\n                      requiredobj={{ required: true, message: '请选择指令集' }}\n                      name=\"instructions\"\n                      colon={false}\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.instructionsArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"系统版本\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ width: '600px' }}\n                      name=\"osVersion\"\n                      requiredobj={{\n                        required: true,\n                        message: '请选择系统版本',\n                      }}\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.osVersionsArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        placeholder=\"请选择系统版本\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      wrapperCol={{ offset: '' }}\n                      style={{\n                        flexDirection: 'row',\n                        width: '600px',\n                        display: 'flex',\n                      }}\n                    >\n                      <Button\n                        style={{ marginLeft: '0' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickSecondBack',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickSecondBack.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        返回\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{ float: 'right', marginLeft: '20px' }}\n                        loading={__$$eval(\n                          () =>\n                            this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT\n                        )}\n                      >\n                        {__$$eval(() => this.state.secondCommitText)}\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{ marginLeft: '0px', float: 'right' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickPreSecond',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickPreSecond.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        上一步\n                      </Button>\n                    </Form.Item>\n                  </Form>\n                </NextP>\n              )}\n              {!!__$$eval(() => this.state.currentStep === 2) && (\n                <NextP\n                  wrap={false}\n                  type=\"body2\"\n                  verAlign=\"middle\"\n                  textSpacing={true}\n                  align=\"left\"\n                  full={true}\n                  flex={true}\n                  style={{ display: 'flex', justifyContent: 'center' }}\n                >\n                  <Form\n                    labelCol={{ span: 10 }}\n                    wrapperCol={{ span: 10 }}\n                    onFinishFailed={function () {\n                      this.onFinishFailed.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    name=\"basic\"\n                    style={{\n                      display: 'flex',\n                      flexDirection: 'column',\n                      width: '600px',\n                      justifyContent: 'center',\n                    }}\n                    layout=\"vertical\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onFinishFailed',\n                          relatedEventName: 'onFinishFailed',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onFinish', disabled: false },\n                        { name: 'onFinishFailed', disabled: true },\n                        { name: 'onFieldsChange', disabled: false },\n                        { name: 'onValuesChange', disabled: false },\n                      ],\n                    }}\n                  >\n                    <Form.Item label=\"\">\n                      <Steps\n                        current={1}\n                        style={{\n                          width: '600px',\n                          display: 'flex',\n                          justifyContent: 'space-around',\n                          alignItems: 'center',\n                          height: '300px',\n                        }}\n                        labelPlacement=\"horizontal\"\n                        direction=\"vertical\"\n                      >\n                        <Steps.Step\n                          title=\"提交完成\"\n                          description=\"\"\n                          style={{ width: '200px' }}\n                        />\n                        <Steps.Step\n                          title={__$$eval(() => this.state.thirdAuditText)}\n                          subTitle=\"\"\n                          description=\"\"\n                          style={{ width: '200px' }}\n                        />\n                      </Steps>\n                    </Form.Item>\n                    <Form.Item\n                      wrapperCol={{ offset: '' }}\n                      style={{\n                        flexDirection: 'row',\n                        width: '600px',\n                        display: 'flex',\n                      }}\n                    >\n                      <Button\n                        style={{ marginLeft: '0' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickThirdBack',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickThirdBack.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        返回\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{ float: 'right', marginLeft: '20px' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickModifyThird',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickModifyThird.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        {__$$eval(() => this.state.thirdButtonText)}\n                      </Button>\n                      {!!__$$eval(\n                        () => this.state.customerProjectInfo.status > 2\n                      ) && (\n                        <Button\n                          type=\"primary\"\n                          htmlType=\"submit\"\n                          style={{ marginLeft: '0px', float: 'right' }}\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onClick',\n                                relatedEventName: 'onClickPreThird',\n                              },\n                            ],\n                            eventList: [{ name: 'onClick', disabled: true }],\n                          }}\n                          onClick={function () {\n                            this.onClickPreThird.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                        >\n                          上一步\n                        </Button>\n                      )}\n                    </Form.Item>\n                  </Form>\n                </NextP>\n              )}\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Text',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextText',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Steps',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Step',\n      componentName: 'Steps.Step',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Steps',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Steps',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Input',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Checkbox',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Group',\n      componentName: 'Checkbox.Group',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'DatePicker',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'DatePicker',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'InputNumber',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'InputNumber',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        constructor: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        componentDidMount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function(prevProps, prevState, snapshot) {}',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n      },\n      methods: {\n        __jp__init: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initRouter: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initDataSource: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initEnv: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initUtils: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onFinishFirst: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onClickPreSecond: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onFinishSecond: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onClickModifyThird: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onOkModifyDialogThird: {\n          type: 'JSFunction',\n          value: 'function() {\\n    //第三步 修改 对话框 确定\\n\\n    this.setState({\\n      currentStep: 0,\\n      isModifyDialogVisible: false,\\n    });\\n  }',\n        },\n        onCancelModifyDialogThird: {\n          type: 'JSFunction',\n          value: 'function() {\\n    //第三步 修改 对话框 取消\\n\\n    this.setState({\\n      isModifyDialogVisible: false,\\n    });\\n  }',\n        },\n        onFinishFailed: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n        onClickPreThird: {\n          type: 'JSFunction',\n          value: 'function() {\\n    // 第三步 上一步\\n    this.setState({\\n      currentStep: 1,\\n    });\\n  }',\n        },\n        onClickFirstBack: {\n          type: 'JSFunction',\n          value: \"function() {\\n    // 第一步 返回按钮\\n    this.$router.push('/myProjectList');\\n  }\",\n        },\n        onClickSecondBack: {\n          type: 'JSFunction',\n          value: \"function() {\\n    // 第二步 返回按钮\\n    this.$router.push('/myProjectList');\\n  }\",\n        },\n        onClickThirdBack: {\n          type: 'JSFunction',\n          value: \"function() {\\n    // 第三步 返回按钮\\n    this.$router.push('/myProjectList');\\n  }\",\n        },\n        onValuesChange: {\n          type: 'JSFunction',\n          value: 'function(_, values) {\\n    this.setState({\\n      customerProjectInfo: {\\n        ...this.state.customerProjectInfo,\\n        ...values,\\n      },\\n    });\\n  }',\n        },\n      },\n      state: {\n        books: [],\n        currentStep: 0,\n        isModifyDialogVisible: false,\n        isModifyStatus: false,\n        secondCommitText: '完成并提交',\n        thirdAuditText: '审核中',\n        thirdButtonText: '修改',\n        customerProjectInfo: {\n          id: null,\n          systemProjectName: null,\n          projectVersionTypeArray: null,\n          projectVersionType: null,\n          versionLine: 2,\n          expectedTime: null,\n          expectedNum: null,\n          projectModal: null,\n          displayWidth: null,\n          displayHeight: null,\n          displayInch: null,\n          displayDpi: null,\n          mainSoc: null,\n          cpuCoreNum: null,\n          instructions: null,\n          osVersion: null,\n          status: null,\n        },\n        versionLinesArray: [\n          {\n            label: 'AmapAuto 485',\n            value: 1,\n          },\n          {\n            label: 'AmapAuto 505',\n            value: 2,\n          },\n        ],\n        projectModalsArray: [\n          {\n            label: '车机',\n            value: 1,\n          },\n          {\n            label: '车镜',\n            value: 2,\n          },\n          {\n            label: '记录仪',\n            value: 3,\n          },\n          {\n            label: '其他',\n            value: 4,\n          },\n        ],\n        osVersionsArray: [\n          {\n            label: '安卓5',\n            value: 1,\n          },\n          {\n            label: '安卓6',\n            value: 2,\n          },\n          {\n            label: '安卓7',\n            value: 3,\n          },\n          {\n            label: '安卓8',\n            value: 4,\n          },\n          {\n            label: '安卓9',\n            value: 5,\n          },\n          {\n            label: '安卓10',\n            value: 6,\n          },\n        ],\n        instructionsArray: [\n          {\n            label: 'ARM64-V8',\n            value: 'ARM64-V8',\n          },\n          {\n            label: 'ARM32-V7',\n            value: 'ARM32-V7',\n          },\n          {\n            label: 'X86',\n            value: 'X86',\n          },\n          {\n            label: 'X64',\n            value: 'X64',\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Modal',\n          id: 'node_ockodngwu940',\n          props: {\n            title: '是否修改',\n            visible: {\n              type: 'JSExpression',\n              value: 'this.state.isModifyDialogVisible',\n            },\n            okText: '确认',\n            okType: '',\n            forceRender: false,\n            cancelText: '取消',\n            zIndex: 2000,\n            destroyOnClose: false,\n            confirmLoading: false,\n            __events: {\n              eventDataList: [\n                {\n                  type: 'componentEvent',\n                  name: 'onOk',\n                  relatedEventName: 'onOkModifyDialogThird',\n                },\n                {\n                  type: 'componentEvent',\n                  name: 'onCancel',\n                  relatedEventName: 'onCancelModifyDialogThird',\n                },\n              ],\n              eventList: [\n                {\n                  name: 'onCancel',\n                  disabled: true,\n                },\n                {\n                  name: 'onOk',\n                  disabled: true,\n                },\n              ],\n            },\n            onOk: {\n              type: 'JSFunction',\n              value: 'function(){this.onOkModifyDialogThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n            onCancel: {\n              type: 'JSFunction',\n              value: 'function(){this.onCancelModifyDialogThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n          },\n          hidden: true,\n          children: [\n            {\n              componentName: 'NextText',\n              id: 'node_ockodngwu946',\n              props: {\n                type: 'inherit',\n                children: '修改将撤回此前填写的信息',\n                style: {\n                  fontStyle: 'normal',\n                  textAlign: 'left',\n                  display: 'block',\n                  fontFamily: 'arial, helvetica, microsoft yahei',\n                  fontWeight: 'normal',\n                },\n              },\n            },\n          ],\n        },\n        {\n          componentName: 'NextPage',\n          id: 'node_ocko19zplh1',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n            style: {},\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocko19zplh2',\n              props: {\n                prefix: 'next-',\n                placeholderStyle: {\n                  height: '100%',\n                },\n                noPadding: false,\n                noBorder: false,\n                background: 'surface',\n                layoutmode: 'O',\n                colSpan: 12,\n                rowSpan: 1,\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocko19zplh3',\n                  props: {\n                    title: '',\n                    prefix: 'next-',\n                    placeholderStyle: {\n                      height: '100%',\n                    },\n                    layoutmode: 'O',\n                    childTotalColumns: 12,\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockoco6icv1w',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                        style: {\n                          marginBottom: '24px',\n                        },\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Steps',\n                          id: 'node_ockoco6icv1x',\n                          props: {\n                            current: {\n                              type: 'JSExpression',\n                              value: 'this.state.currentStep',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Steps.Step',\n                              id: 'node_ockoco6icv1y',\n                              props: {\n                                title: '版本申请',\n                                description: '',\n                              },\n                            },\n                            {\n                              componentName: 'Steps.Step',\n                              id: 'node_ockoco6icv1z',\n                              props: {\n                                title: '机器配置',\n                                subTitle: '',\n                                description: '',\n                              },\n                            },\n                            {\n                              componentName: 'Steps.Step',\n                              id: 'node_ockoco6icv20',\n                              props: {\n                                title: '项目审批',\n                                description: '',\n                              },\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockoco6icv12w',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                        style: {\n                          display: 'flex',\n                          justifyContent: 'center',\n                        },\n                      },\n                      title: '段落',\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.state.currentStep === 0',\n                      },\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ockoco6icv12x',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 10,\n                            },\n                            onFinish: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinishFirst.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            style: {\n                              display: 'flex',\n                              flexDirection: 'column',\n                              width: '600px',\n                              justifyContent: 'center',\n                            },\n                            layout: 'vertical',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinish',\n                                  relatedEventName: 'onFinishFirst',\n                                },\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onValuesChange',\n                                  relatedEventName: 'onValuesChange',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: true,\n                                },\n                              ],\n                            },\n                            initialValues: {\n                              type: 'JSExpression',\n                              value: 'this.state.customerProjectInfo',\n                            },\n                            onValuesChange: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onValuesChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockojhvrkn2u',\n                              props: {\n                                label: '',\n                                style: {\n                                  width: '600px',\n                                },\n                                colon: false,\n                                name: 'id',\n                              },\n                              condition: false,\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ockojhvrkn2v',\n                                  props: {\n                                    placeholder: '',\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    bordered: false,\n                                    disabled: true,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv12y',\n                              props: {\n                                label: '版本类型选择',\n                                name: 'projectVersionTypeArray',\n                                initialValue: '',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  flexDirection: 'column',\n                                  width: '600px',\n                                },\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择版本类型',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Checkbox.Group',\n                                  id: 'node_ockoco6icv12z',\n                                  props: {\n                                    options: [\n                                      {\n                                        label: '基础版本',\n                                        value: '3',\n                                      },\n                                      {\n                                        label: 'AR导航',\n                                        value: '1',\n                                      },\n                                      {\n                                        label: '货车导航',\n                                        value: '2',\n                                      },\n                                      {\n                                        label: 'UI定制',\n                                        value: '4',\n                                        disabled: false,\n                                      },\n                                    ],\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv13a',\n                              props: {\n                                label: '版本线选择',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'versionLine',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择版本线',\n                                },\n                                extra: '',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockoco6icv13b',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.versionLinesArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    placeholder: '请选择版本线',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv13o',\n                              props: {\n                                label: '项目名称',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  display: 'flex',\n                                },\n                                labelAlign: 'left',\n                                extra: '',\n                                name: 'systemProjectName',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请按格式填写项目名称',\n                                },\n                                typeobj: {\n                                  type: 'string',\n                                  message: '请输入项目名称，格式：公司简称-产品名称-版本类型',\n                                },\n                                lenobj: {\n                                  max: 100,\n                                  message: '项目名称不能超过100个字符',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ockoco6icv13p',\n                                  props: {\n                                    placeholder: '公司简称-产品名称-版本类型',\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv13v',\n                              props: {\n                                label: '预期交付时间',\n                                style: {\n                                  width: '600px',\n                                },\n                                colon: false,\n                                required: true,\n                                name: 'expectedTime',\n                                labelAlign: 'left',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请填写预期交付时间',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'DatePicker',\n                                  id: 'node_ockoco6icv13w',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bv8',\n                              props: {\n                                label: '预期出货量',\n                                style: {\n                                  width: '600px',\n                                },\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请填写预期出货量',\n                                },\n                                name: 'expectedNum',\n                                labelAlign: 'left',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bv9',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '单位（台）使用该版本的机器数量+预计出货量，请如实填写',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                    size: 'middle',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv130',\n                              props: {\n                                wrapperCol: {\n                                  offset: '',\n                                },\n                                style: {\n                                  flexDirection: 'row',\n                                  alignItems: 'baseline',\n                                  justifyContent: 'space-between',\n                                  width: '600px',\n                                  display: 'block',\n                                },\n                                labelAlign: 'left',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv132',\n                                  props: {\n                                    style: {\n                                      margin: '0px',\n                                    },\n                                    children: '返回',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickFirstBack',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickFirstBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv131',\n                                  props: {\n                                    type: 'primary',\n                                    children: '下一步',\n                                    htmlType: 'submit',\n                                    style: {\n                                      boxShadow: 'rgba(31, 56, 88, 0.2) 0px 0px 0px 0px',\n                                      float: 'right',\n                                    },\n                                    __events: {\n                                      eventDataList: [],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockoco6icv1ue',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                        style: {\n                          display: 'flex',\n                          justifyContent: 'center',\n                        },\n                      },\n                      title: '段落',\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.state.currentStep === 1',\n                      },\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ockoco6icv1uf',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 10,\n                            },\n                            onFinish: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinishSecond.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            style: {\n                              display: 'flex',\n                              flexDirection: 'column',\n                              width: '600px',\n                              justifyContent: 'center',\n                              height: '800px',\n                            },\n                            layout: 'vertical',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinish',\n                                  relatedEventName: 'onFinishSecond',\n                                },\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onValuesChange',\n                                  relatedEventName: 'onValuesChange',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: true,\n                                },\n                              ],\n                            },\n                            initialValues: {\n                              type: 'JSExpression',\n                              value: 'this.state.customerProjectInfo',\n                            },\n                            onValuesChange: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onValuesChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv1ui',\n                              props: {\n                                label: '设备类型选择',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'projectModal',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择设备类型',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockoco6icv1uj',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.projectModalsArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    placeholder: '请选择设备类型',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bv17',\n                              props: {\n                                label: '屏幕分辨率宽',\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'displayWidth',\n                                colon: false,\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入屏幕分辨率宽',\n                                },\n                                labelAlign: 'left',\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bv18',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '例如1280',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bv10',\n                              props: {\n                                label: '屏幕分辨率高',\n                                style: {\n                                  width: '600px',\n                                },\n                                labelAlign: 'left',\n                                colon: false,\n                                name: 'displayHeight',\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入屏幕分辨率高',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bv11',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '例如720',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bvt',\n                              props: {\n                                label: '屏幕尺寸（inch）',\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'displayInch',\n                                labelAlign: 'left',\n                                required: true,\n                                colon: false,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入屏幕尺寸',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bvu',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '请输入尺寸',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bvm',\n                              props: {\n                                label: '屏幕DPI',\n                                style: {\n                                  width: '600px',\n                                },\n                                labelAlign: 'left',\n                                colon: false,\n                                required: false,\n                                name: 'displayDpi',\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bvn',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: 'UI定制项目必填',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv1v3',\n                              props: {\n                                label: '芯片名称',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  display: 'flex',\n                                },\n                                labelAlign: 'left',\n                                extra: '',\n                                name: 'mainSoc',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入芯片名称',\n                                },\n                                lenobj: {\n                                  max: 50,\n                                  message: '芯片名称不能超过50个字符',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ockoco6icv1v4',\n                                  props: {\n                                    placeholder: '请输入芯片名称',\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bvf',\n                              props: {\n                                label: '芯片核数',\n                                style: {\n                                  width: '600px',\n                                },\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入芯片核数',\n                                },\n                                name: 'cpuCoreNum',\n                                labelAlign: 'left',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bvg',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '请输入芯片核数',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    defaultValue: '',\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpxba11aa',\n                              props: {\n                                label: '指令集',\n                                style: {\n                                  width: '600px',\n                                },\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择指令集',\n                                },\n                                name: 'instructions',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockpxba11ab',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.instructionsArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockodz1kiqh',\n                              props: {\n                                label: '系统版本',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'osVersion',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择系统版本',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockodz1kiqi',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.osVersionsArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    placeholder: '请选择系统版本',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv1uq',\n                              props: {\n                                wrapperCol: {\n                                  offset: '',\n                                },\n                                style: {\n                                  flexDirection: 'row',\n                                  width: '600px',\n                                  display: 'flex',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv1ur',\n                                  props: {\n                                    style: {\n                                      marginLeft: '0',\n                                    },\n                                    children: '返回',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickSecondBack',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickSecondBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv1vb',\n                                  props: {\n                                    type: 'primary',\n                                    children: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.secondCommitText',\n                                    },\n                                    htmlType: 'submit',\n                                    style: {\n                                      float: 'right',\n                                      marginLeft: '20px',\n                                    },\n                                    loading: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv1us',\n                                  props: {\n                                    type: 'primary',\n                                    children: '上一步',\n                                    htmlType: 'submit',\n                                    style: {\n                                      marginLeft: '0px',\n                                      float: 'right',\n                                    },\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickPreSecond',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickPreSecond.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockodngwu9m',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                        style: {\n                          display: 'flex',\n                          justifyContent: 'center',\n                        },\n                      },\n                      title: '段落',\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.state.currentStep === 2',\n                      },\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ockodngwu9n',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 10,\n                            },\n                            onFinishFailed: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinishFailed.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            style: {\n                              display: 'flex',\n                              flexDirection: 'column',\n                              width: '600px',\n                              justifyContent: 'center',\n                            },\n                            layout: 'vertical',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinishFailed',\n                                  relatedEventName: 'onFinishFailed',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: false,\n                                },\n                              ],\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockodngwu91m',\n                              props: {\n                                label: '',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Steps',\n                                  id: 'node_ockodngwu91n',\n                                  props: {\n                                    current: 1,\n                                    style: {\n                                      width: '600px',\n                                      display: 'flex',\n                                      justifyContent: 'space-around',\n                                      alignItems: 'center',\n                                      height: '300px',\n                                    },\n                                    labelPlacement: 'horizontal',\n                                    direction: 'vertical',\n                                  },\n                                  children: [\n                                    {\n                                      componentName: 'Steps.Step',\n                                      id: 'node_ockodngwu91o',\n                                      props: {\n                                        title: '提交完成',\n                                        description: '',\n                                        style: {\n                                          width: '200px',\n                                        },\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Steps.Step',\n                                      id: 'node_ockodngwu91p',\n                                      props: {\n                                        title: {\n                                          type: 'JSExpression',\n                                          value: 'this.state.thirdAuditText',\n                                        },\n                                        subTitle: '',\n                                        description: '',\n                                        style: {\n                                          width: '200px',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockodngwu914',\n                              props: {\n                                wrapperCol: {\n                                  offset: '',\n                                },\n                                style: {\n                                  flexDirection: 'row',\n                                  width: '600px',\n                                  display: 'flex',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockodngwu915',\n                                  props: {\n                                    style: {\n                                      marginLeft: '0',\n                                    },\n                                    children: '返回',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickThirdBack',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickThirdBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockodngwu916',\n                                  props: {\n                                    type: 'primary',\n                                    children: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.thirdButtonText',\n                                    },\n                                    htmlType: 'submit',\n                                    style: {\n                                      float: 'right',\n                                      marginLeft: '20px',\n                                    },\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickModifyThird',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickModifyThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockosjrkvr1d',\n                                  props: {\n                                    type: 'primary',\n                                    children: '上一步',\n                                    htmlType: 'submit',\n                                    style: {\n                                      marginLeft: '0px',\n                                      float: 'right',\n                                    },\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickPreThird',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickPreThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                  condition: {\n                                    type: 'JSExpression',\n                                    value: 'this.state.customerProjectInfo.status > 2',\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.26.15\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-http-handler\": \"^1.0.0\",\n    \"@alilc/lowcode-components\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Page, Table } from '@alilc/lowcode-components';\n\nimport { createHttpHandler as __$$createHttpRequestHandler } from '@alilc/lowcode-datasource-http-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Example$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: { http: __$$createHttpRequestHandler() },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'userList',\n          type: 'http',\n          description: '用户列表',\n          options: function () {\n            return {\n              uri: 'https://api.example.com/user/list',\n            };\n          }.bind(_this),\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div>\n        <Table\n          dataSource={__$$eval(() => this.dataSourceMap['userList'])}\n          columns={[\n            { dataIndex: 'name', title: '姓名' },\n            { dataIndex: 'age', title: '年龄' },\n          ]}\n        />\n      </div>\n    );\n  }\n}\n\nexport default Example$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/lowcode-components',\n      version: '^1.0.0',\n      componentName: 'Page',\n      destructuring: true,\n      exportName: 'Page',\n    },\n    {\n      package: '@alilc/lowcode-components',\n      version: '^1.0.0',\n      componentName: 'Table',\n      destructuring: true,\n      exportName: 'Table',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_ockp6ci0hm1',\n      props: {},\n      fileName: 'example',\n      dataSource: {\n        list: [\n          {\n            id: 'userList',\n            type: 'http',\n            description: '用户列表',\n            options: {\n              uri: 'https://api.example.com/user/list',\n            },\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Table',\n          id: 'node_ockp6ci0hm22',\n          props: {\n            dataSource: {\n              type: 'DataSource',\n              id: 'userList',\n            },\n            columns: [\n              {\n                dataIndex: 'name',\n                title: '姓名',\n              },\n              {\n                dataIndex: 'age',\n                title: '年龄',\n              },\n            ],\n          },\n        },\n      ],\n    },\n  ],\n  meta: {\n    name: 'example',\n    description: 'Example',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.19.18\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-jsonp-handler\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Switch } from '@alifd/next';\n\nimport { createJsonpHandler as __$$createJsonpRequestHandler } from '@alilc/lowcode-datasource-jsonp-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport '@alifd/next/lib/switch/style';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass $$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: { jsonp: __$$createJsonpRequestHandler() },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'todos',\n          isInit: function () {\n            return true;\n          }.bind(_this),\n          type: 'jsonp',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io',\n            };\n          }.bind(_this),\n          dataHandler: function dataHandler(data) {\n            return data.data;\n          },\n        },\n      ],\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div>\n        {__$$evalArray(() => this.dataSourceMap.todos.data).map((item, index) =>\n          ((__$$context) => (\n            <div>\n              <Switch\n                checkedChildren=\"开\"\n                unCheckedChildren=\"关\"\n                checked={__$$eval(() => item.done)}\n              />\n            </div>\n          ))(__$$createChildContext(__$$context, { item, index }))\n        )}\n      </div>\n    );\n  }\n}\n\nexport default $$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Switch',\n      package: '@alifd/next',\n      version: '1.19.18',\n      exportName: 'Switch',\n      destructuring: true,\n      subName: '',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      children: [\n        {\n          componentName: 'Div',\n          props: {},\n          children: [\n            {\n              componentName: 'Switch',\n              props: {\n                checkedChildren: '开',\n                unCheckedChildren: '关',\n                checked: {\n                  type: 'JSExpression',\n                  value: 'this.item.done',\n                },\n              },\n            },\n          ],\n          loop: {\n            type: 'JSExpression',\n            value: 'this.dataSourceMap.todos.data',\n          },\n        },\n      ],\n      dataSource: {\n        list: [\n          {\n            id: 'todos',\n            isInit: true,\n            type: 'jsonp',\n            options: {\n              method: 'GET',\n              uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io',\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function dataHandler(data) {return data.data;}',\n            },\n          },\n        ],\n      },\n    },\n  ],\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.26.15\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alilc/antd-lowcode-materials\": \"0.9.4\",\n    \"@alife/mc-assets-1935\": \"0.1.42\",\n    \"@alife/container\": \"0.3.7\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Modal,\n  Button,\n  Typography,\n  Form,\n  Select,\n  Input,\n  ConfigProvider,\n  Tooltip,\n  Empty,\n} from '@alilc/antd-lowcode-materials/dist/antd-lowcode.esm.js';\n\nimport {\n  AliAutoDiv,\n  AliAutoSearchTable,\n} from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst AliAutoDivDefault = AliAutoDiv.default;\n\nconst AliAutoSearchTableDefault = AliAutoSearchTable.default;\n\nconst NextBlockCell = NextBlock.Cell;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      pkgs: [],\n      total: 0,\n      isSearch: false,\n      projects: [],\n      results: [],\n      resultVisible: false,\n    };\n\n    this.__jp__init();\n    this.statusDesc = {\n      0: '失败',\n      1: '成功',\n      2: '构建中',\n      3: '构建超时',\n    };\n    this.pageParams = {};\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidUpdate(prevProps, prevState, snapshot) {}\n\n  componentWillUnmount() {}\n\n  __jp__init() {\n    /*...*/\n  }\n\n  __jp__initRouter() {\n    if (window.arsenal) {\n      this.$router = new window.jianpin.ArsenalRouter({\n        app: this.props.microApp,\n      });\n    } else {\n      this.$router = new window.jianpin.ArsenalRouter();\n    }\n  }\n\n  __jp__initDataSource() {\n    /*...*/\n  }\n\n  __jp__initEnv() {\n    /*...*/\n  }\n\n  __jp__initConfig() {\n    /*...*/\n  }\n\n  __jp__initUtils() {\n    this.$utils = {\n      message: window.jianpin.utils.message,\n      axios: window.jianpin.utils.axios,\n      moment: window.jianpin.utils.moment,\n    };\n  }\n\n  fetchPkgs() {\n    /*...*/\n  }\n\n  onPageChange(pageIndex, pageSize) {\n    this.pageParams = {\n      pageIndex,\n      pageSize,\n    };\n    this.fetchPkgs();\n  }\n\n  renderTime(time) {\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n  }\n\n  renderUserName(user) {\n    return user.user_name;\n  }\n\n  reload() {\n    /*...*/\n  }\n\n  handleResult() {\n    /*...*/\n  }\n\n  handleDetail() {\n    // 跳转详情页面 TODO\n  }\n\n  onResultCancel() {\n    this.setState({\n      resultVisible: false,\n    });\n  }\n\n  formatResult(item) {\n    if (!item) {\n      return '暂无结果';\n    }\n    const { channel, plat, version, status } = item;\n    return [channel, plat, version, status].join('-');\n  }\n\n  handleDownload() {\n    /*...*/\n  }\n\n  onFinish() {\n    /*...*/\n  }\n\n  componentDidMount() {\n    this.$ds.resolve('PROJECTS', {\n      params: {\n        size: 5000,\n      },\n    });\n    // if (this.state.init === false) {\n    //   this.setState({\n    //     init: true,\n    //   });\n    // }\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <Modal\n          title=\"查看结果\"\n          visible={__$$eval(() => this.state.resultVisible)}\n          footer={\n            <Button\n              type=\"primary\"\n              __events={{\n                eventDataList: [\n                  {\n                    type: 'componentEvent',\n                    name: 'onClick',\n                    relatedEventName: 'onResultCancel',\n                  },\n                ],\n                eventList: [{ name: 'onClick', disabled: true }],\n              }}\n              onClick={function () {\n                this.onResultCancel.apply(\n                  this,\n                  Array.prototype.slice.call(arguments).concat([])\n                );\n              }.bind(this)}\n            >\n              确定\n            </Button>\n          }\n          __events={{\n            eventDataList: [\n              {\n                type: 'componentEvent',\n                name: 'onCancel',\n                relatedEventName: 'onResultCancel',\n              },\n            ],\n            eventList: [\n              { name: 'onCancel', disabled: true },\n              { name: 'onOk', disabled: false },\n            ],\n          }}\n          onCancel={function () {\n            this.onResultCancel.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n          width=\"720px\"\n          centered={true}\n        >\n          {__$$evalArray(() => this.state.results).map((item, index) =>\n            ((__$$context) => (\n              <AliAutoDivDefault style={{ width: '100%' }}>\n                {!!__$$eval(\n                  () =>\n                    __$$context.state.results &&\n                    __$$context.state.results.length > 0\n                ) && (\n                  <AliAutoDivDefault\n                    style={{\n                      width: '100%',\n                      textAlign: 'left',\n                      marginBottom: '10px',\n                    }}\n                  >\n                    <Button\n                      type=\"primary\"\n                      size=\"small\"\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onClick',\n                            relatedEventName: 'handleDownload',\n                          },\n                        ],\n                        eventList: [{ name: 'onClick', disabled: true }],\n                      }}\n                      onClick={function () {\n                        this.handleDownload.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(__$$context)}\n                    >\n                      下载全部\n                    </Button>\n                  </AliAutoDivDefault>\n                )}\n                <Typography.Text>\n                  {__$$eval(() => __$$context.formatResult(item))}\n                </Typography.Text>\n                {!!__$$eval(() => item.download_link) && (\n                  <Typography.Link\n                    href={__$$eval(() => item.download_link)}\n                    target=\"_blank\"\n                  >\n                    {' '}\n                    - 点击下载\n                  </Typography.Link>\n                )}\n                {!!__$$eval(() => item.release_notes) && (\n                  <Typography.Link\n                    href={__$$eval(() => item.release_notes)}\n                    target=\"_blank\"\n                  >\n                    {' '}\n                    - 跳转发布节点\n                  </Typography.Link>\n                )}\n              </AliAutoDivDefault>\n            ))(__$$createChildContext(__$$context, { item, index }))\n          )}\n        </Modal>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            layoutmode=\"O\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={12}\n          >\n            <NextBlockCell\n              title=\"\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              layoutmode=\"O\"\n              childTotalColumns={12}\n              isAutoContainer={true}\n              colSpan={12}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                full={true}\n                flex={true}\n              >\n                <Form\n                  labelCol={{ span: 10 }}\n                  wrapperCol={{ span: 14 }}\n                  onFinish={function () {\n                    this.onFinish.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                  name=\"basic\"\n                  layout=\"inline\"\n                  __events={{\n                    eventDataList: [\n                      {\n                        type: 'componentEvent',\n                        name: 'onFinish',\n                        relatedEventName: 'onFinish',\n                      },\n                    ],\n                    eventList: [\n                      { name: 'onFinish', disabled: true },\n                      { name: 'onFinishFailed', disabled: false },\n                      { name: 'onFieldsChange', disabled: false },\n                      { name: 'onValuesChange', disabled: false },\n                    ],\n                  }}\n                >\n                  <Form.Item label=\"项目名称/渠道号\" name=\"channel_id\">\n                    <Select\n                      style={{ width: '280px' }}\n                      options={__$$eval(() => this.state.projects)}\n                      showArrow={true}\n                      tokenSeparators={[]}\n                      showSearch={true}\n                    />\n                  </Form.Item>\n                  <Form.Item label=\"版本号\" name=\"buildId\">\n                    <Input\n                      placeholder=\"请输入\"\n                      style={{ width: '280px' }}\n                      size=\"middle\"\n                    />\n                  </Form.Item>\n                  <Form.Item label=\"构建人\" name=\"user_id\">\n                    <Select\n                      style={{ width: 200 }}\n                      options={[\n                        { label: 'A', value: 'A' },\n                        { label: 'B', value: 'B' },\n                        { label: 'C', value: 'C' },\n                      ]}\n                      showSearch={true}\n                    />\n                  </Form.Item>\n                  <Form.Item label=\"ID\" name=\"id\">\n                    <Input placeholder=\"请输入\" style={{ width: '160px' }} />\n                  </Form.Item>\n                  <Form.Item wrapperCol={{ offset: 6 }}>\n                    <Button type=\"primary\" htmlType=\"submit\">\n                      查询\n                    </Button>\n                  </Form.Item>\n                </Form>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock childTotalColumns={12}>\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                <ConfigProvider locale=\"zh-CN\">\n                  {!!__$$eval(\n                    () =>\n                      !this.state.isSearch ||\n                      (this.state.isSearch && this.state.pkgs.length > 0)\n                  ) && (\n                    <AliAutoSearchTableDefault\n                      rowKey=\"key\"\n                      dataSource={__$$eval(() => this.state.pkgs)}\n                      columns={[\n                        {\n                          title: 'ID',\n                          dataIndex: 'id',\n                          key: 'name',\n                          width: 80,\n                        },\n                        {\n                          title: '渠道号',\n                          dataIndex: 'channels',\n                          key: 'age',\n                          width: 142,\n                          render: (text, record, index) =>\n                            ((__$$context) =>\n                              __$$evalArray(() => text.split(',')).map(\n                                (item, index) =>\n                                  ((__$$context) => (\n                                    <Typography.Text\n                                      style={{ display: 'block' }}\n                                    >\n                                      {__$$eval(() => item)}\n                                    </Typography.Text>\n                                  ))(\n                                    __$$createChildContext(__$$context, {\n                                      item,\n                                      index,\n                                    })\n                                  )\n                              ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                        },\n                        {\n                          title: '版本号',\n                          dataIndex: 'dic_version',\n                          key: 'address',\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Tooltip\n                                title={__$$evalArray(() => text || []).map(\n                                  (item, index) =>\n                                    ((__$$context) => (\n                                      <Typography.Text\n                                        style={{\n                                          display: 'block',\n                                          color: '#FFFFFF',\n                                        }}\n                                      >\n                                        {__$$eval(\n                                          () =>\n                                            item.channelId +\n                                            ' / ' +\n                                            item.version\n                                        )}\n                                      </Typography.Text>\n                                    ))(\n                                      __$$createChildContext(__$$context, {\n                                        item,\n                                        index,\n                                      })\n                                    )\n                                )}\n                              >\n                                <Typography.Text>\n                                  {__$$eval(() => text[0].version)}\n                                </Typography.Text>\n                              </Tooltip>\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 120,\n                        },\n                        { title: '构建Job', dataIndex: 'job_name', width: 180 },\n                        {\n                          title: '构建类型',\n                          dataIndex: 'packaging_type',\n                          width: 94,\n                        },\n                        {\n                          title: '构建状态',\n                          dataIndex: 'status',\n                          render: (text, record, index) =>\n                            ((__$$context) => [\n                              <Typography.Text>\n                                {__$$eval(() => __$$context.statusDesc[text])}\n                              </Typography.Text>,\n                              !!__$$eval(() => text === 2) && (\n                                <Icon\n                                  type=\"SyncOutlined\"\n                                  size={16}\n                                  spin={true}\n                                  style={{ marginLeft: '10px' }}\n                                />\n                              ),\n                            ])(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 100,\n                        },\n                        {\n                          title: '构建时间',\n                          dataIndex: 'start_time',\n                          render: function () {\n                            return this.renderTime.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this),\n                          width: 148,\n                        },\n                        {\n                          title: '构建人',\n                          dataIndex: 'user',\n                          render: function () {\n                            return this.renderUserName.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this),\n                          width: 80,\n                        },\n                        {\n                          title: 'Jenkins 链接',\n                          dataIndex: 'jenkins_link',\n                          render: (text, record, index) =>\n                            ((__$$context) => [\n                              !!__$$eval(() => text) && (\n                                <Typography.Link\n                                  href={__$$eval(() => text)}\n                                  target=\"_blank\"\n                                >\n                                  查看\n                                </Typography.Link>\n                              ),\n                              !!__$$eval(() => !text) && (\n                                <Typography.Text>暂无</Typography.Text>\n                              ),\n                            ])(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 120,\n                        },\n                        {\n                          title: '测试平台链接',\n                          dataIndex: 'is_run_testing',\n                          width: 120,\n                          render: (text, record, index) =>\n                            ((__$$context) => [\n                              !!__$$eval(() => text) && (\n                                <Typography.Link\n                                  href=\"http://rivermap.alibaba.net/dashboard/testExecute\"\n                                  target=\"_blank\"\n                                >\n                                  查看\n                                </Typography.Link>\n                              ),\n                              !!__$$eval(() => !text) && (\n                                <Typography.Text>暂无</Typography.Text>\n                              ),\n                            ])(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                        },\n                        { title: '触发源', dataIndex: 'source', width: 120 },\n                        {\n                          title: '详情',\n                          dataIndex: 'id',\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Button\n                                type=\"link\"\n                                size=\"small\"\n                                style={{ padding: '0px' }}\n                                __events={{\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'handleDetail',\n                                    },\n                                  ],\n                                  eventList: [\n                                    { name: 'onClick', disabled: true },\n                                  ],\n                                }}\n                                onClick={function () {\n                                  this.handleDetail.apply(\n                                    this,\n                                    Array.prototype.slice\n                                      .call(arguments)\n                                      .concat([])\n                                  );\n                                }.bind(__$$context)}\n                              >\n                                查看\n                              </Button>\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 80,\n                          fixed: 'right',\n                        },\n                        {\n                          title: '结果',\n                          dataIndex: 'id',\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Button\n                                type=\"link\"\n                                size=\"small\"\n                                style={{ padding: '0px' }}\n                                __events={{\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'handleResult',\n                                      paramStr: 'this.text',\n                                    },\n                                  ],\n                                  eventList: [\n                                    { name: 'onClick', disabled: true },\n                                  ],\n                                }}\n                                onClick={function () {\n                                  this.handleResult.apply(\n                                    this,\n                                    Array.prototype.slice\n                                      .call(arguments)\n                                      .concat([])\n                                  );\n                                }.bind(__$$context)}\n                                ghost={false}\n                                href={__$$eval(() => text)}\n                              >\n                                查看\n                              </Button>\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 80,\n                          fixed: 'right',\n                        },\n                        {\n                          title: '重新执行',\n                          dataIndex: 'id',\n                          width: 92,\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Button\n                                type=\"text\"\n                                children=\"\"\n                                icon={\n                                  <Icon\n                                    type=\"ReloadOutlined\"\n                                    size={14}\n                                    color=\"#0593d3\"\n                                    style={{\n                                      padding: '3px',\n                                      border: '1px solid #0593d3',\n                                      borderRadius: '14px',\n                                      cursor: 'pointer',\n                                      height: '22px',\n                                    }}\n                                    spin={false}\n                                  />\n                                }\n                                shape=\"circle\"\n                                __events={{\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'reload',\n                                    },\n                                  ],\n                                  eventList: [\n                                    { name: 'onClick', disabled: true },\n                                  ],\n                                }}\n                                onClick={function () {\n                                  this.reload.apply(\n                                    this,\n                                    Array.prototype.slice\n                                      .call(arguments)\n                                      .concat([])\n                                  );\n                                }.bind(__$$context)}\n                              />\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          fixed: 'right',\n                        },\n                      ]}\n                      actions={[]}\n                      pagination={{\n                        total: __$$eval(() => this.state.total),\n                        defaultPageSize: 8,\n                        onPageChange: function () {\n                          return this.onPageChange.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this),\n                      }}\n                      scrollX={1200}\n                    />\n                  )}\n                </ConfigProvider>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock childTotalColumns={12}>\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                {!!__$$eval(\n                  () => this.state.pkgs.length < 1 && this.state.isSearch\n                ) && <Empty description=\"暂无数据\" />}\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.42',\n      exportName: 'AliAutoDiv',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoDivDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Text',\n      componentName: 'Typography.Text',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Link',\n      componentName: 'Typography.Link',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Input',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.42',\n      exportName: 'AliAutoSearchTable',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoSearchTableDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'ConfigProvider',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'ConfigProvider',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Empty',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Empty',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Tooltip',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Tooltip',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        constructor: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.__jp__init();\\n    this.statusDesc = {\\n      0: '失败',\\n      1: '成功',\\n      2: '构建中',\\n      3: '构建超时',\\n    };\\n    this.pageParams = {};\\n  }\",\n        },\n        componentDidMount: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.$ds.resolve('PROJECTS', {\\n      params: {\\n        size: 5000,\\n      },\\n    });\\n    // if (this.state.init === false) {\\n    //   this.setState({\\n    //     init: true,\\n    //   });\\n    // }\\n  }\",\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function(prevProps, prevState, snapshot) {}',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n      },\n      methods: {\n        __jp__init: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initRouter: {\n          type: 'JSFunction',\n          value: 'function() {\\n  if (window.arsenal) {\\n    this.$router = new window.jianpin.ArsenalRouter({\\n      app: this.props.microApp,\\n    });\\n  } else {\\n    this.$router = new window.jianpin.ArsenalRouter();\\n  }\\n}',\n        },\n        __jp__initDataSource: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initEnv: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initConfig: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initUtils: {\n          type: 'JSFunction',\n          value: 'function() {\\n  this.$utils = {\\n    message: window.jianpin.utils.message,\\n    axios: window.jianpin.utils.axios,\\n    moment: window.jianpin.utils.moment,\\n  };\\n}',\n        },\n        fetchPkgs: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onPageChange: {\n          type: 'JSFunction',\n          value: 'function(pageIndex, pageSize) {\\n    this.pageParams = {\\n      pageIndex,\\n      pageSize,\\n    };\\n    this.fetchPkgs();\\n  }',\n        },\n        renderTime: {\n          type: 'JSFunction',\n          value: \"function(time) {\\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\\n  }\",\n        },\n        renderUserName: {\n          type: 'JSFunction',\n          value: 'function(user) {\\n    return user.user_name;\\n  }',\n        },\n        reload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleResult: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleDetail: {\n          type: 'JSFunction',\n          value: 'function() {\\n    // 跳转详情页面 TODO\\n  }',\n        },\n        onResultCancel: {\n          type: 'JSFunction',\n          value: 'function() {\\n    this.setState({\\n      resultVisible: false,\\n    });\\n  }',\n        },\n        formatResult: {\n          type: 'JSFunction',\n          value: \"function(item) {\\n    if (!item) {\\n      return '暂无结果';\\n    }\\n    const { channel, plat, version, status } = item;\\n    return [channel, plat, version, status].join('-');\\n  }\",\n        },\n        handleDownload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onFinish: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n      },\n      state: {\n        pkgs: [],\n        total: 0,\n        isSearch: false,\n        projects: [],\n        results: [],\n        resultVisible: false,\n      },\n      children: [\n        {\n          componentName: 'Modal',\n          id: 'node_ocksh9yppxb',\n          props: {\n            title: '查看结果',\n            visible: {\n              type: 'JSExpression',\n              value: 'this.state.resultVisible',\n            },\n            footer: {\n              type: 'JSSlot',\n              value: [\n                {\n                  componentName: 'Button',\n                  id: 'node_ocksh9yppxf',\n                  props: {\n                    type: 'primary',\n                    children: '确定',\n                    __events: {\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onClick',\n                          relatedEventName: 'onResultCancel',\n                        },\n                      ],\n                      eventList: [\n                        {\n                          name: 'onClick',\n                          disabled: true,\n                        },\n                      ],\n                    },\n                    onClick: {\n                      type: 'JSFunction',\n                      value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                    },\n                  },\n                },\n              ],\n            },\n            __events: {\n              eventDataList: [\n                {\n                  type: 'componentEvent',\n                  name: 'onCancel',\n                  relatedEventName: 'onResultCancel',\n                },\n              ],\n              eventList: [\n                {\n                  name: 'onCancel',\n                  disabled: true,\n                },\n                {\n                  name: 'onOk',\n                  disabled: false,\n                },\n              ],\n            },\n            onCancel: {\n              type: 'JSFunction',\n              value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n            width: '720px',\n            centered: true,\n          },\n          hidden: true,\n          children: [\n            {\n              componentName: 'AliAutoDivDefault',\n              id: 'node_ockshazuxa4',\n              props: {\n                style: {\n                  width: '100%',\n                },\n              },\n              loop: {\n                type: 'JSExpression',\n                value: 'this.state.results',\n              },\n              children: [\n                {\n                  componentName: 'AliAutoDivDefault',\n                  id: 'node_ockshazuxai',\n                  props: {\n                    style: {\n                      width: '100%',\n                      textAlign: 'left',\n                      marginBottom: '10px',\n                    },\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.state.results && this.state.results.length > 0',\n                  },\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node_ockshazuxah',\n                      props: {\n                        type: 'primary',\n                        children: '下载全部',\n                        size: 'small',\n                        __events: {\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'handleDownload',\n                            },\n                          ],\n                          eventList: [\n                            {\n                              name: 'onClick',\n                              disabled: true,\n                            },\n                          ],\n                        },\n                        onClick: {\n                          type: 'JSFunction',\n                          value: 'function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Typography.Text',\n                  id: 'node_ockshazuxa5',\n                  props: {\n                    children: {\n                      type: 'JSExpression',\n                      value: 'this.formatResult(this.item)',\n                    },\n                  },\n                },\n                {\n                  componentName: 'Typography.Link',\n                  id: 'node_ockshazuxa6',\n                  props: {\n                    href: {\n                      type: 'JSExpression',\n                      value: 'this.item.download_link',\n                    },\n                    target: '_blank',\n                    children: ' - 点击下载',\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.item.download_link',\n                  },\n                },\n                {\n                  componentName: 'Typography.Link',\n                  id: 'node_ockshazuxa7',\n                  props: {\n                    href: {\n                      type: 'JSExpression',\n                      value: 'this.item.release_notes',\n                    },\n                    target: '_blank',\n                    children: ' - 跳转发布节点',\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.item.release_notes',\n                  },\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'NextPage',\n          id: 'node_ocko19zplh1',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocko19zplh2',\n              props: {\n                prefix: 'next-',\n                placeholderStyle: {\n                  height: '100%',\n                },\n                noPadding: false,\n                noBorder: false,\n                background: 'surface',\n                layoutmode: 'O',\n                colSpan: 12,\n                rowSpan: 1,\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocko19zplh3',\n                  props: {\n                    title: '',\n                    prefix: 'next-',\n                    placeholderStyle: {\n                      height: '100%',\n                    },\n                    layoutmode: 'O',\n                    childTotalColumns: 12,\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocks8dtt1ms',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ocks8dtt1mt',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 14,\n                            },\n                            onFinish: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            layout: 'inline',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinish',\n                                  relatedEventName: 'onFinish',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: false,\n                                },\n                              ],\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1mz',\n                              props: {\n                                label: '项目名称/渠道号',\n                                name: 'channel_id',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ocksfuhwhsd',\n                                  props: {\n                                    style: {\n                                      width: '280px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.projects',\n                                    },\n                                    showArrow: true,\n                                    tokenSeparators: [],\n                                    showSearch: true,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1m12',\n                              props: {\n                                label: '版本号',\n                                name: 'buildId',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ocksfuhwhs3',\n                                  props: {\n                                    placeholder: '请输入',\n                                    style: {\n                                      width: '280px',\n                                    },\n                                    size: 'middle',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1m18',\n                              props: {\n                                label: '构建人',\n                                name: 'user_id',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ocksfuhwhsi',\n                                  props: {\n                                    style: {\n                                      width: 200,\n                                    },\n                                    options: [\n                                      {\n                                        label: 'A',\n                                        value: 'A',\n                                      },\n                                      {\n                                        label: 'B',\n                                        value: 'B',\n                                      },\n                                      {\n                                        label: 'C',\n                                        value: 'C',\n                                      },\n                                    ],\n                                    showSearch: true,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1m19',\n                              props: {\n                                label: 'ID',\n                                name: 'id',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ocksfuhwhs8',\n                                  props: {\n                                    placeholder: '请输入',\n                                    style: {\n                                      width: '160px',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1mw',\n                              props: {\n                                wrapperCol: {\n                                  offset: 6,\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ocks8dtt1mx',\n                                  props: {\n                                    type: 'primary',\n                                    children: '查询',\n                                    htmlType: 'submit',\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ockshc4ifn1b',\n              props: {\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ockshc4ifn1c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockshc4ifn1d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'ConfigProvider',\n                          id: 'node_ockshc4ifn1e',\n                          props: {\n                            locale: 'zh-CN',\n                          },\n                          children: [\n                            {\n                              componentName: 'AliAutoSearchTableDefault',\n                              id: 'node_ocksfuhwhsx',\n                              props: {\n                                rowKey: 'key',\n                                dataSource: {\n                                  type: 'JSExpression',\n                                  value: 'this.state.pkgs',\n                                },\n                                columns: [\n                                  {\n                                    title: 'ID',\n                                    dataIndex: 'id',\n                                    key: 'name',\n                                    width: 80,\n                                  },\n                                  {\n                                    title: '渠道号',\n                                    dataIndex: 'channels',\n                                    key: 'age',\n                                    width: 142,\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh2bq0428',\n                                          props: {\n                                            children: {\n                                              type: 'JSExpression',\n                                              value: 'this.item',\n                                            },\n                                            style: {\n                                              display: 'block',\n                                            },\n                                          },\n                                          loop: {\n                                            type: 'JSExpression',\n                                            value: \"this.text.split(',')\",\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  },\n                                  {\n                                    title: '版本号',\n                                    dataIndex: 'dic_version',\n                                    key: 'address',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Tooltip',\n                                          id: 'node_ocksso4xavj',\n                                          props: {\n                                            title: {\n                                              type: 'JSSlot',\n                                              value: [\n                                                {\n                                                  componentName: 'Typography.Text',\n                                                  id: 'node_ocksso4xavn',\n                                                  props: {\n                                                    children: {\n                                                      type: 'JSExpression',\n                                                      value: \"this.item. channelId + ' / ' +  this.item.version\",\n                                                    },\n                                                    style: {\n                                                      display: 'block',\n                                                      color: '#FFFFFF',\n                                                    },\n                                                  },\n                                                  loop: {\n                                                    type: 'JSExpression',\n                                                    value: 'this.text || []',\n                                                  },\n                                                },\n                                              ],\n                                            },\n                                          },\n                                          children: [\n                                            {\n                                              componentName: 'Typography.Text',\n                                              id: 'node_ocksso4xavm',\n                                              props: {\n                                                children: {\n                                                  type: 'JSExpression',\n                                                  value: 'this.text[0].version',\n                                                },\n                                              },\n                                            },\n                                          ],\n                                        },\n                                      ],\n                                    },\n                                    width: 120,\n                                  },\n                                  {\n                                    title: '构建Job',\n                                    dataIndex: 'job_name',\n                                    width: 180,\n                                  },\n                                  {\n                                    title: '构建类型',\n                                    dataIndex: 'packaging_type',\n                                    width: 94,\n                                  },\n                                  {\n                                    title: '构建状态',\n                                    dataIndex: 'status',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh3jkxzw',\n                                          props: {\n                                            children: {\n                                              type: 'JSExpression',\n                                              value: 'this.statusDesc[this.text]',\n                                            },\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Icon',\n                                          id: 'node_ocksh3jkxzx',\n                                          props: {\n                                            type: 'SyncOutlined',\n                                            size: 16,\n                                            spin: true,\n                                            style: {\n                                              marginLeft: '10px',\n                                            },\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: 'this.text === 2',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 100,\n                                  },\n                                  {\n                                    title: '构建时间',\n                                    dataIndex: 'start_time',\n                                    render: {\n                                      type: 'JSFunction',\n                                      value: 'function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    width: 148,\n                                  },\n                                  {\n                                    title: '构建人',\n                                    dataIndex: 'user',\n                                    render: {\n                                      type: 'JSFunction',\n                                      value: 'function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    width: 80,\n                                  },\n                                  {\n                                    title: 'Jenkins 链接',\n                                    dataIndex: 'jenkins_link',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Link',\n                                          id: 'node_ocksh64kbx21',\n                                          props: {\n                                            href: {\n                                              type: 'JSExpression',\n                                              value: 'this.text',\n                                            },\n                                            target: '_blank',\n                                            children: '查看',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: 'this.text',\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh64kbx22',\n                                          props: {\n                                            children: '暂无',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: '!this.text',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 120,\n                                  },\n                                  {\n                                    title: '测试平台链接',\n                                    dataIndex: 'is_run_testing',\n                                    width: 120,\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Link',\n                                          id: 'node_ocksh3jkxz3e',\n                                          props: {\n                                            href: 'http://rivermap.alibaba.net/dashboard/testExecute',\n                                            target: '_blank',\n                                            children: '查看',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: 'this.text',\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh3jkxz3f',\n                                          props: {\n                                            children: '暂无',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: '!this.text',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  },\n                                  {\n                                    title: '触发源',\n                                    dataIndex: 'source',\n                                    width: 120,\n                                  },\n                                  {\n                                    title: '详情',\n                                    dataIndex: 'id',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocksh8yryw7',\n                                          props: {\n                                            type: 'link',\n                                            children: '查看',\n                                            size: 'small',\n                                            style: {\n                                              padding: '0px',\n                                            },\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'handleDetail',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 80,\n                                    fixed: 'right',\n                                  },\n                                  {\n                                    title: '结果',\n                                    dataIndex: 'id',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocksh9v6jw7',\n                                          props: {\n                                            type: 'link',\n                                            children: '查看',\n                                            size: 'small',\n                                            style: {\n                                              padding: '0px',\n                                            },\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'handleResult',\n                                                  paramStr: 'this.text',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            ghost: false,\n                                            href: {\n                                              type: 'JSExpression',\n                                              value: 'this.text',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 80,\n                                    fixed: 'right',\n                                  },\n                                  {\n                                    title: '重新执行',\n                                    dataIndex: 'id',\n                                    width: 92,\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocksh96rad1g',\n                                          props: {\n                                            type: 'text',\n                                            children: '',\n                                            icon: {\n                                              type: 'JSSlot',\n                                              value: [\n                                                {\n                                                  componentName: 'Icon',\n                                                  id: 'node_ocksh96rad1j',\n                                                  props: {\n                                                    type: 'ReloadOutlined',\n                                                    size: 14,\n                                                    color: '#0593d3',\n                                                    style: {\n                                                      padding: '3px',\n                                                      border: '1px solid #0593d3',\n                                                      borderRadius: '14px',\n                                                      cursor: 'pointer',\n                                                      height: '22px',\n                                                    },\n                                                    spin: false,\n                                                  },\n                                                },\n                                              ],\n                                            },\n                                            shape: 'circle',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'reload',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    fixed: 'right',\n                                  },\n                                ],\n                                actions: [],\n                                pagination: {\n                                  total: {\n                                    type: 'JSExpression',\n                                    value: 'this.state.total',\n                                  },\n                                  defaultPageSize: 8,\n                                  onPageChange: {\n                                    type: 'JSFunction',\n                                    value: 'function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                  },\n                                },\n                                scrollX: 1200,\n                              },\n                              condition: {\n                                type: 'JSExpression',\n                                value: '!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)',\n                              },\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocksk6f8fa3b',\n              props: {\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocksk6f8fa3c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocksk6f8fa3d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Empty',\n                          id: 'node_ocksk6f8fa3e',\n                          props: {\n                            description: '暂无数据',\n                          },\n                          condition: {\n                            type: 'JSExpression',\n                            value: 'this.state.pkgs.length < 1 && this.state.isSearch',\n                          },\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.browserslistrc",
    "content": "defaults\nios_saf 9\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/README.md",
    "content": "This project is generated by lowcode-code-generator & lowcode-solution-icejs3."
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts",
    "content": "import { join } from 'path';\nimport { defineConfig } from '@ice/app';\nimport _ from 'lodash';\nimport fusion from '@ice/plugin-fusion';\nimport locales from '@ice/plugin-moment-locales';\nimport type { Plugin } from '@ice/app/esm/types';\n\ninterface PluginOptions {\n  id: string;\n}\n\nconst plugin: Plugin<PluginOptions> = (options) => ({\n  // name 可选，插件名称\n  name: 'plugin-name',\n  // setup 必选，用于定制工程构建配置\n  setup: ({ onGetConfig, modifyUserConfig }) => {\n    modifyUserConfig('codeSplitting', 'page');\n\n    onGetConfig((config) => {\n      config.entry = {\n        web: join(process.cwd(), '.ice/entry.client.tsx'),\n      };\n\n      config.cssFilename = '[name].css';\n\n      config.configureWebpack = config.configureWebpack || [];\n      config.configureWebpack?.push((webpackConfig) => {\n        if (webpackConfig.output) {\n          webpackConfig.output.filename = '[name].js';\n          webpackConfig.output.chunkFilename = '[name].js';\n        }\n        return webpackConfig;\n      });\n\n      config.swcOptions = _.merge(config.swcOptions, {\n        compilationConfig: {\n          jsc: {\n            transform: {\n              react: {\n                runtime: 'classic',\n              },\n            },\n          },\n        },\n      });\n\n      // 解决 webpack publicPath 问题\n      config.transforms = config.transforms || [];\n      config.transforms.push((source: string, id: string) => {\n        if (id.includes('.ice/entry.client.tsx')) {\n          let code = `\n          if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {\n            // @ts-ignore\n            __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');\n            window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};\n            window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;\n          }\n          `;\n          code += source;\n          return { code };\n        }\n      });\n    });\n  },\n});\n\n// The project config, see https://v3.ice.work/docs/guide/basic/config\nconst minify = process.env.NODE_ENV === 'production' ? 'swc' : false;\nexport default defineConfig(() => ({\n  ssr: false,\n  ssg: false,\n  minify,\n\n  externals: {\n    react: 'React',\n    'react-dom': 'ReactDOM',\n    'react-dom/client': 'ReactDOM',\n    '@alifd/next': 'Next',\n    lodash: 'var window._',\n    '@alilc/lowcode-engine': 'var window.AliLowCodeEngine',\n  },\n  plugins: [\n    fusion({\n      importStyle: 'sass',\n    }),\n    locales(),\n    plugin(),\n  ],\n}));\n\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs3-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"icejs 3 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-router\": \"^6.9.0\",\n    \"react-router-dom\": \"^6.9.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@alifd/next\": \"1.26.15\",\n    \"@ice/runtime\": \"~1.1.0\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alilc/antd-lowcode-materials\": \"0.11.0\",\n    \"@alife/mc-assets-1935\": \"0.1.43\",\n    \"@alife/container\": \"0.3.7\"\n  },\n  \"devDependencies\": {\n    \"@ice/app\": \"~3.1.0\",\n    \"@types/react\": \"^18.0.0\",\n    \"@types/react-dom\": \"^18.0.0\",\n    \"@types/node\": \"^18.11.17\",\n    \"@ice/plugin-fusion\": \"^1.0.1\",\n    \"@ice/plugin-moment-locales\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"ice start\",\n    \"build\": \"ice build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/app.ts",
    "content": "import { defineAppConfig } from 'ice';\n\n// App config, see https://v3.ice.work/docs/guide/basic/app\nexport default defineAppConfig(() => ({\n  // Set your configs here.\n  app: {\n    rootId: 'App',\n  },\n  router: {\n    type: 'browser',\n    basename: '/',\n  },\n}));\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx",
    "content": "import React from 'react';\nimport { Meta, Title, Links, Main, Scripts } from 'ice';\n\nexport default function Document() {\n  return (\n    <html>\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"description\" content=\"ice.js 3 lite scaffold\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n        <Meta />\n        <Title />\n        <Links />\n      </head>\n      <body>\n        <Main />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js\" />\n        <script crossOrigin=\"anonymous\" src=\"//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js\" />\n        <Scripts />\n      </body>\n    </html>\n  );\n}"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FF7300;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: #FF7300;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, useLocation } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const location = useLocation();\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nexport default Navigation;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Modal,\n  Button,\n  Typography,\n  Form,\n  Select,\n  Input,\n  Tooltip,\n  Icon,\n  Empty,\n} from '@alilc/antd-lowcode-materials/dist/antd-lowcode.esm.js';\n\nimport {\n  AliAutoDiv,\n  AliAutoSearchTable,\n} from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst AliAutoDivDefault = AliAutoDiv.default;\n\nconst AliAutoSearchTableDefault = AliAutoSearchTable.default;\n\nconst NextBlockCell = NextBlock.Cell;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      pkgs: [],\n      total: 0,\n      isSearch: false,\n      projects: [],\n      results: [],\n      resultVisible: false,\n      userOptions: [],\n      searchValues: { user_id: '', channel_id: '' },\n    };\n\n    this.__jp__init();\n    this.statusDesc = {\n      0: '失败',\n      1: '成功',\n      2: '构建中',\n      3: '构建超时',\n    };\n    this.pageParams = {};\n    this.searchParams = {};\n    this.userTimeout = null;\n    this.currentUser = null;\n    this.notFoundContent = null;\n    this.projectTimeout = null;\n    this.currentProject = null;\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidUpdate(prevProps, prevState, snapshot) {}\n\n  componentWillUnmount() {}\n\n  __jp__init() {\n    /*...*/\n  }\n\n  __jp__initRouter() {\n    /*...*/\n  }\n\n  __jp__initDataSource() {\n    /*...*/\n  }\n\n  __jp__initEnv() {\n    /*...*/\n  }\n\n  __jp__initConfig() {\n    /*...*/\n  }\n\n  __jp__initUtils() {\n    /*...*/\n  }\n\n  setSearchItem() {\n    /*...*/\n  }\n\n  fetchProject() {\n    /*...*/\n  }\n\n  handleProjectSearch() {\n    /*...*/\n  }\n\n  handleProjectChange(id) {\n    this.setSearchItem({\n      channel_id: id,\n    });\n  }\n\n  fetchUser() {\n    /*...*/\n  }\n\n  handleUserSearch() {\n    /*...*/\n  }\n\n  handleUserChange(user) {\n    console.log('debug user', user);\n    this.setSearchItem({\n      user_id: user,\n    });\n  }\n\n  fetchPkgs() {\n    /*...*/\n  }\n\n  onPageChange(pageIndex, pageSize) {\n    this.pageParams = {\n      pageIndex,\n      pageSize,\n    };\n    this.fetchPkgs();\n  }\n\n  renderTime(time) {\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n  }\n\n  renderUserName(user) {\n    return user.user_name;\n  }\n\n  reload() {\n    /*...*/\n  }\n\n  handleResult() {\n    /*...*/\n  }\n\n  handleDetail() {\n    /*...*/\n  }\n\n  onResultCancel() {\n    /*...*/\n  }\n\n  formatResult() {\n    /*...*/\n  }\n\n  handleDownload() {\n    /*...*/\n  }\n\n  onFinish() {\n    /*...*/\n  }\n\n  componentDidMount() {\n    this.$ds.resolve('PROJECTS');\n    if (this.userTimeout) {\n      clearTimeout(this.userTimeout);\n      this.userTimeout = null;\n    }\n    if (this.projectTimeout) {\n      clearTimeout(this.projectTimeout);\n      this.projectTimeout = null;\n    }\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <Modal\n          title=\"查看结果\"\n          visible={__$$eval(() => this.state.resultVisible)}\n          footer={\n            <Button\n              type=\"primary\"\n              __events={{\n                eventDataList: [\n                  {\n                    type: 'componentEvent',\n                    name: 'onClick',\n                    relatedEventName: 'onResultCancel',\n                  },\n                ],\n                eventList: [{ name: 'onClick', disabled: true }],\n              }}\n              onClick={function () {\n                this.onResultCancel.apply(\n                  this,\n                  Array.prototype.slice.call(arguments).concat([])\n                );\n              }.bind(this)}\n            >\n              确定\n            </Button>\n          }\n          __events={{\n            eventDataList: [\n              {\n                type: 'componentEvent',\n                name: 'onCancel',\n                relatedEventName: 'onResultCancel',\n              },\n            ],\n            eventList: [\n              { name: 'onCancel', disabled: true },\n              { name: 'onOk', disabled: false },\n            ],\n          }}\n          onCancel={function () {\n            this.onResultCancel.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n          width=\"720px\"\n          centered={true}\n          closable={true}\n          keyboard={true}\n          mask={true}\n          maskClosable={true}\n        >\n          <AliAutoDivDefault style={{ width: '100%' }}>\n            {!!__$$eval(\n              () => this.state.results && this.state.results.length > 0\n            ) && (\n              <AliAutoDivDefault\n                style={{\n                  width: '100%',\n                  textAlign: 'left',\n                  marginBottom: '16px',\n                }}\n              >\n                <Button\n                  type=\"primary\"\n                  size=\"small\"\n                  __events={{\n                    eventDataList: [\n                      {\n                        type: 'componentEvent',\n                        name: 'onClick',\n                        relatedEventName: 'handleDownload',\n                      },\n                    ],\n                    eventList: [{ name: 'onClick', disabled: true }],\n                  }}\n                  onClick={function () {\n                    this.handleDownload.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                >\n                  下载全部\n                </Button>\n              </AliAutoDivDefault>\n            )}\n            {__$$evalArray(() => this.state.results).map((item, index) =>\n              ((__$$context) => (\n                <AliAutoDivDefault style={{ width: '100%', marginTop: '10px' }}>\n                  <Typography.Text>\n                    {__$$eval(() => __$$context.formatResult(item))}\n                  </Typography.Text>\n                  {!!__$$eval(() => item.download_link) && (\n                    <Typography.Link\n                      href={__$$eval(() => item.download_link)}\n                      target=\"_blank\"\n                    >\n                      {' '}\n                      - 点击下载\n                    </Typography.Link>\n                  )}\n                  {!!__$$eval(() => item.release_notes) && (\n                    <Typography.Link\n                      href={__$$eval(() => item.release_notes)}\n                      target=\"_blank\"\n                    >\n                      {' '}\n                      - 跳转发布节点\n                    </Typography.Link>\n                  )}\n                </AliAutoDivDefault>\n              ))(__$$createChildContext(__$$context, { item, index }))\n            )}\n          </AliAutoDivDefault>\n        </Modal>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface', style: { padding: '' } }}\n          footer={null}\n          minHeight=\"100vh\"\n          contentProps={{ noPadding: false, background: 'transparent' }}\n        >\n          <NextBlock childTotalColumns={12}>\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                <AliAutoDivDefault style={{ width: '100%', display: 'flex' }}>\n                  <AliAutoDivDefault style={{ flex: '1' }}>\n                    <Form\n                      labelCol={{ span: 10 }}\n                      wrapperCol={{ span: 14 }}\n                      onFinish={function () {\n                        this.onFinish.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this)}\n                      name=\"basic\"\n                      layout=\"inline\"\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onFinish',\n                            relatedEventName: 'onFinish',\n                          },\n                        ],\n                        eventList: [\n                          { name: 'onFinish', disabled: true },\n                          { name: 'onFinishFailed', disabled: false },\n                          { name: 'onFieldsChange', disabled: false },\n                          { name: 'onValuesChange', disabled: false },\n                        ],\n                      }}\n                      colon={true}\n                      labelAlign=\"right\"\n                      preserve={true}\n                      scrollToFirstError={true}\n                      size=\"middle\"\n                      values={__$$eval(() => this.state.searchValues)}\n                    >\n                      <Form.Item\n                        label=\"项目名称/渠道号\"\n                        name=\"channel_id\"\n                        labelAlign=\"right\"\n                        colon={true}\n                      >\n                        <Select\n                          style={{ width: '320px' }}\n                          options={__$$eval(() => this.state.projects)}\n                          showArrow={false}\n                          tokenSeparators={[]}\n                          showSearch={true}\n                          defaultActiveFirstOption={true}\n                          size=\"middle\"\n                          bordered={true}\n                          filterOption={true}\n                          optionFilterProp=\"label\"\n                          allowClear={true}\n                          placeholder=\"请输入项目名称/渠道号\"\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onChange',\n                                relatedEventName: 'handleProjectChange',\n                              },\n                              {\n                                type: 'componentEvent',\n                                name: 'onSearch',\n                                relatedEventName: 'handleProjectSearch',\n                              },\n                            ],\n                            eventList: [\n                              { name: 'onBlur', disabled: false },\n                              { name: 'onChange', disabled: true },\n                              { name: 'onDeselect', disabled: false },\n                              { name: 'onFocus', disabled: false },\n                              { name: 'onInputKeyDown', disabled: false },\n                              { name: 'onMouseEnter', disabled: false },\n                              { name: 'onMouseLeave', disabled: false },\n                              { name: 'onPopupScroll', disabled: false },\n                              { name: 'onSearch', disabled: true },\n                              { name: 'onSelect', disabled: false },\n                              {\n                                name: 'onDropdownVisibleChange',\n                                disabled: false,\n                              },\n                            ],\n                          }}\n                          onChange={function () {\n                            this.handleProjectChange.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                          onSearch={function () {\n                            this.handleProjectSearch.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                        />\n                      </Form.Item>\n                      <Form.Item label=\"版本号\" name=\"buildId\">\n                        <Input\n                          placeholder=\"请输入版本号\"\n                          style={{ width: '180px' }}\n                          size=\"middle\"\n                          bordered={true}\n                        />\n                      </Form.Item>\n                      <Form.Item label=\"构建人\" name=\"user_id\">\n                        <Select\n                          style={{ width: '210px' }}\n                          options={__$$eval(() => this.state.userOptions)}\n                          showSearch={true}\n                          defaultActiveFirstOption={false}\n                          size=\"middle\"\n                          bordered={true}\n                          filterOption={true}\n                          optionFilterProp=\"label\"\n                          notFoundContent={__$$eval(\n                            () => this.userNotFoundContent\n                          )}\n                          showArrow={false}\n                          placeholder=\"请输入构建人\"\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onChange',\n                                relatedEventName: 'handleUserChange',\n                              },\n                              {\n                                type: 'componentEvent',\n                                name: 'onSearch',\n                                relatedEventName: 'handleUserSearch',\n                              },\n                            ],\n                            eventList: [\n                              { name: 'onBlur', disabled: false },\n                              { name: 'onChange', disabled: true },\n                              { name: 'onDeselect', disabled: false },\n                              { name: 'onFocus', disabled: false },\n                              { name: 'onInputKeyDown', disabled: false },\n                              { name: 'onMouseEnter', disabled: false },\n                              { name: 'onMouseLeave', disabled: false },\n                              { name: 'onPopupScroll', disabled: false },\n                              { name: 'onSearch', disabled: true },\n                              { name: 'onSelect', disabled: false },\n                              {\n                                name: 'onDropdownVisibleChange',\n                                disabled: false,\n                              },\n                            ],\n                          }}\n                          onChange={function () {\n                            this.handleUserChange.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                          onSearch={function () {\n                            this.handleUserSearch.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                          allowClear={true}\n                        />\n                      </Form.Item>\n                      <Form.Item\n                        label=\"ID\"\n                        name=\"id\"\n                        labelAlign=\"right\"\n                        colon={true}\n                      >\n                        <Input\n                          placeholder=\"请输入ID\"\n                          style={{ width: '180px' }}\n                          bordered={true}\n                          size=\"middle\"\n                        />\n                      </Form.Item>\n                      <Form.Item\n                        wrapperCol={{ offset: 6 }}\n                        labelAlign=\"right\"\n                        colon={true}\n                        style={{ flex: '1', textAlign: 'right' }}\n                      >\n                        <Button\n                          type=\"primary\"\n                          htmlType=\"submit\"\n                          shape=\"default\"\n                          size=\"middle\"\n                        >\n                          查询\n                        </Button>\n                      </Form.Item>\n                    </Form>\n                  </AliAutoDivDefault>\n                  <AliAutoDivDefault style={{}}>\n                    <Button\n                      type=\"link\"\n                      htmlType=\"button\"\n                      shape=\"default\"\n                      size=\"middle\"\n                    >\n                      新增打包\n                    </Button>\n                  </AliAutoDivDefault>\n                </AliAutoDivDefault>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock\n            childTotalColumns={12}\n            mode=\"inset\"\n            layoutmode=\"O\"\n            autolayout=\"(12|1)\"\n          >\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                {!!__$$eval(\n                  () =>\n                    !this.state.isSearch ||\n                    (this.state.isSearch && this.state.pkgs.length > 0)\n                ) && (\n                  <AliAutoSearchTableDefault\n                    rowKey=\"key\"\n                    dataSource={__$$eval(() => this.state.pkgs)}\n                    columns={[\n                      { title: 'ID', dataIndex: 'id', key: 'name', width: 80 },\n                      {\n                        title: '渠道号',\n                        dataIndex: 'channels',\n                        key: 'age',\n                        width: 142,\n                        render: (text, record, index) =>\n                          ((__$$context) =>\n                            __$$evalArray(() => text.split(',')).map(\n                              (item, index) =>\n                                ((__$$context) => (\n                                  <Typography.Text style={{ display: 'block' }}>\n                                    {__$$eval(() => item)}\n                                  </Typography.Text>\n                                ))(\n                                  __$$createChildContext(__$$context, {\n                                    item,\n                                    index,\n                                  })\n                                )\n                            ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                      },\n                      {\n                        title: '版本号',\n                        dataIndex: 'dic_version',\n                        key: 'address',\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Tooltip\n                              title={__$$evalArray(() => text || []).map(\n                                (item, index) =>\n                                  ((__$$context) => (\n                                    <Typography.Text\n                                      style={{\n                                        display: 'block',\n                                        color: '#FFFFFF',\n                                      }}\n                                    >\n                                      {__$$eval(\n                                        () =>\n                                          item.channelId + ' / ' + item.version\n                                      )}\n                                    </Typography.Text>\n                                  ))(\n                                    __$$createChildContext(__$$context, {\n                                      item,\n                                      index,\n                                    })\n                                  )\n                              )}\n                            >\n                              <Typography.Text>\n                                {__$$eval(() => text[0].version)}\n                              </Typography.Text>\n                            </Tooltip>\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 120,\n                      },\n                      { title: '构建Job', dataIndex: 'job_name', width: 180 },\n                      {\n                        title: '构建类型',\n                        dataIndex: 'packaging_type',\n                        width: 94,\n                      },\n                      {\n                        title: '构建状态',\n                        dataIndex: 'status',\n                        render: (text, record, index) =>\n                          ((__$$context) => [\n                            <Typography.Text>\n                              {__$$eval(() => __$$context.statusDesc[text])}\n                            </Typography.Text>,\n                            !!__$$eval(() => text === 2) && (\n                              <Icon\n                                type=\"SyncOutlined\"\n                                size={16}\n                                spin={true}\n                                style={{ marginLeft: '10px' }}\n                              />\n                            ),\n                          ])(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 100,\n                      },\n                      {\n                        title: '构建时间',\n                        dataIndex: 'start_time',\n                        render: function () {\n                          return this.renderTime.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this),\n                        width: 148,\n                      },\n                      {\n                        title: '构建人',\n                        dataIndex: 'user',\n                        render: function () {\n                          return this.renderUserName.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this),\n                        width: 80,\n                      },\n                      {\n                        title: 'Jenkins 链接',\n                        dataIndex: 'jenkins_link',\n                        render: (text, record, index) =>\n                          ((__$$context) => [\n                            !!__$$eval(() => text) && (\n                              <Typography.Link\n                                href={__$$eval(() => text)}\n                                target=\"_blank\"\n                              >\n                                查看\n                              </Typography.Link>\n                            ),\n                            !!__$$eval(() => !text) && (\n                              <Typography.Text>暂无</Typography.Text>\n                            ),\n                          ])(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 120,\n                      },\n                      {\n                        title: '测试平台链接',\n                        dataIndex: 'is_run_testing',\n                        width: 120,\n                        render: (text, record, index) =>\n                          ((__$$context) => [\n                            !!__$$eval(() => text) && (\n                              <Typography.Link\n                                href=\"http://rivermap.alibaba.net/dashboard/testExecute\"\n                                target=\"_blank\"\n                              >\n                                查看\n                              </Typography.Link>\n                            ),\n                            !!__$$eval(() => !text) && (\n                              <Typography.Text>暂无</Typography.Text>\n                            ),\n                          ])(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                      },\n                      { title: '触发源', dataIndex: 'source', width: 120 },\n                      {\n                        title: '详情',\n                        dataIndex: 'id',\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Button\n                              type=\"link\"\n                              size=\"small\"\n                              style={{ padding: '0px' }}\n                              __events={{\n                                eventDataList: [\n                                  {\n                                    type: 'componentEvent',\n                                    name: 'onClick',\n                                    relatedEventName: 'handleDetail',\n                                  },\n                                ],\n                                eventList: [\n                                  { name: 'onClick', disabled: true },\n                                ],\n                              }}\n                              onClick={function () {\n                                this.handleDetail.apply(\n                                  this,\n                                  Array.prototype.slice\n                                    .call(arguments)\n                                    .concat([])\n                                );\n                              }.bind(__$$context)}\n                            >\n                              查看\n                            </Button>\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 80,\n                        fixed: 'right',\n                      },\n                      {\n                        title: '结果',\n                        dataIndex: 'id',\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Button\n                              type=\"link\"\n                              size=\"small\"\n                              style={{ padding: '0px' }}\n                              __events={{\n                                eventDataList: [\n                                  {\n                                    type: 'componentEvent',\n                                    name: 'onClick',\n                                    relatedEventName: 'handleResult',\n                                    paramStr: 'this.text',\n                                  },\n                                ],\n                                eventList: [\n                                  { name: 'onClick', disabled: true },\n                                ],\n                              }}\n                              onClick={function () {\n                                this.handleResult.apply(\n                                  this,\n                                  Array.prototype.slice\n                                    .call(arguments)\n                                    .concat([])\n                                );\n                              }.bind(__$$context)}\n                              ghost={false}\n                              href={__$$eval(() => text)}\n                            >\n                              查看\n                            </Button>\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 80,\n                        fixed: 'right',\n                      },\n                      {\n                        title: '重新执行',\n                        dataIndex: 'id',\n                        width: 92,\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Button\n                              type=\"text\"\n                              children=\"\"\n                              icon={\n                                <Icon\n                                  type=\"ReloadOutlined\"\n                                  size={14}\n                                  color=\"#0593d3\"\n                                  style={{\n                                    padding: '3px',\n                                    border: '1px solid #0593d3',\n                                    borderRadius: '14px',\n                                    cursor: 'pointer',\n                                    height: '22px',\n                                  }}\n                                  spin={false}\n                                />\n                              }\n                              shape=\"circle\"\n                              __events={{\n                                eventDataList: [\n                                  {\n                                    type: 'componentEvent',\n                                    name: 'onClick',\n                                    relatedEventName: 'reload',\n                                  },\n                                ],\n                                eventList: [\n                                  { name: 'onClick', disabled: true },\n                                ],\n                              }}\n                              onClick={function () {\n                                this.reload.apply(\n                                  this,\n                                  Array.prototype.slice\n                                    .call(arguments)\n                                    .concat([])\n                                );\n                              }.bind(__$$context)}\n                            />\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        fixed: 'right',\n                      },\n                    ]}\n                    actions={[]}\n                    pagination={{\n                      total: __$$eval(() => this.state.total),\n                      defaultPageSize: 10,\n                      onPageChange: function () {\n                        return this.onPageChange.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this),\n                      defaultPageIndex: 1,\n                    }}\n                    scrollX={1200}\n                    isPagination={true}\n                  />\n                )}\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock\n            childTotalColumns={12}\n            mode=\"inset\"\n            layoutmode=\"O\"\n            autolayout=\"(12|1)\"\n          >\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                {!!__$$eval(\n                  () => this.state.pkgs.length < 1 && this.state.isSearch\n                ) && <Empty description=\"暂无数据\" />}\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/layout.jsx",
    "content": "import { Outlet } from 'ice';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nexport default function Layout() {\n  return (\n    <BasicLayout>\n      <Outlet />\n    </BasicLayout>\n  );\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/typings.d.ts",
    "content": "/// <reference types=\"@ice/app/types\" />\n\nexport {};\ndeclare global {\n  interface Window {\n    g_config: Record<string, any>;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.43',\n      exportName: 'AliAutoDiv',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoDivDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Text',\n      componentName: 'Typography.Text',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Link',\n      componentName: 'Typography.Link',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Input',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Tooltip',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Tooltip',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Icon',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Icon',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.43',\n      exportName: 'AliAutoSearchTable',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoSearchTableDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Empty',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Empty',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        constructor: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.__jp__init();\\n    this.statusDesc = {\\n      0: '失败',\\n      1: '成功',\\n      2: '构建中',\\n      3: '构建超时',\\n    };\\n    this.pageParams = {};\\n    this.searchParams = {};\\n    this.userTimeout = null;\\n    this.currentUser = null;\\n    this.notFoundContent = null;\\n    this.projectTimeout = null;\\n    this.currentProject = null;\\n  }\",\n        },\n        componentDidMount: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.$ds.resolve('PROJECTS');\\n    if (this.userTimeout) {\\n      clearTimeout(this.userTimeout);\\n      this.userTimeout = null;\\n    }\\n    if (this.projectTimeout) {\\n      clearTimeout(this.projectTimeout);\\n      this.projectTimeout = null;\\n    }\\n  }\",\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function(prevProps, prevState, snapshot) {}',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n      },\n      methods: {\n        __jp__init: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initRouter: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initDataSource: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initEnv: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initConfig: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initUtils: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        setSearchItem: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        fetchProject: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleProjectSearch: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleProjectChange: {\n          type: 'JSFunction',\n          value: 'function(id) {\\n    this.setSearchItem({\\n      channel_id: id,\\n    });\\n  }',\n        },\n        fetchUser: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleUserSearch: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleUserChange: {\n          type: 'JSFunction',\n          value: \"function(user) {\\n    console.log('debug user', user);\\n    this.setSearchItem({\\n      user_id: user,\\n    });\\n  }\",\n        },\n        fetchPkgs: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onPageChange: {\n          type: 'JSFunction',\n          value: 'function(pageIndex, pageSize) {\\n    this.pageParams = {\\n      pageIndex,\\n      pageSize,\\n    };\\n    this.fetchPkgs();\\n  }',\n        },\n        renderTime: {\n          type: 'JSFunction',\n          value: \"function(time) {\\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\\n  }\",\n        },\n        renderUserName: {\n          type: 'JSFunction',\n          value: 'function(user) {\\n    return user.user_name;\\n  }',\n        },\n        reload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleResult: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleDetail: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onResultCancel: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        formatResult: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleDownload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onFinish: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n      },\n      state: {\n        pkgs: [],\n        total: 0,\n        isSearch: false,\n        projects: [],\n        results: [],\n        resultVisible: false,\n        userOptions: [],\n        searchValues: {\n          user_id: '',\n          channel_id: '',\n        },\n      },\n      children: [\n        {\n          componentName: 'Modal',\n          id: 'node_ocksh9yppxb',\n          props: {\n            title: '查看结果',\n            visible: {\n              type: 'JSExpression',\n              value: 'this.state.resultVisible',\n            },\n            footer: {\n              type: 'JSSlot',\n              value: [\n                {\n                  componentName: 'Button',\n                  id: 'node_ocksh9yppxf',\n                  props: {\n                    type: 'primary',\n                    children: '确定',\n                    __events: {\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onClick',\n                          relatedEventName: 'onResultCancel',\n                        },\n                      ],\n                      eventList: [\n                        {\n                          name: 'onClick',\n                          disabled: true,\n                        },\n                      ],\n                    },\n                    onClick: {\n                      type: 'JSFunction',\n                      value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                    },\n                  },\n                },\n              ],\n            },\n            __events: {\n              eventDataList: [\n                {\n                  type: 'componentEvent',\n                  name: 'onCancel',\n                  relatedEventName: 'onResultCancel',\n                },\n              ],\n              eventList: [\n                {\n                  name: 'onCancel',\n                  disabled: true,\n                },\n                {\n                  name: 'onOk',\n                  disabled: false,\n                },\n              ],\n            },\n            onCancel: {\n              type: 'JSFunction',\n              value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n            width: '720px',\n            centered: true,\n            closable: true,\n            keyboard: true,\n            mask: true,\n            maskClosable: true,\n          },\n          hidden: true,\n          children: [\n            {\n              componentName: 'AliAutoDivDefault',\n              id: 'node_ockshazuxa4',\n              props: {\n                style: {\n                  width: '100%',\n                },\n              },\n              children: [\n                {\n                  componentName: 'AliAutoDivDefault',\n                  id: 'node_ockshazuxai',\n                  props: {\n                    style: {\n                      width: '100%',\n                      textAlign: 'left',\n                      marginBottom: '16px',\n                    },\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.state.results && this.state.results.length > 0',\n                  },\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node_ockshazuxah',\n                      props: {\n                        type: 'primary',\n                        children: '下载全部',\n                        size: 'small',\n                        __events: {\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'handleDownload',\n                            },\n                          ],\n                          eventList: [\n                            {\n                              name: 'onClick',\n                              disabled: true,\n                            },\n                          ],\n                        },\n                        onClick: {\n                          type: 'JSFunction',\n                          value: 'function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'AliAutoDivDefault',\n                  id: 'node_ockt2muyfi4',\n                  props: {\n                    style: {\n                      width: '100%',\n                      marginTop: '10px',\n                    },\n                  },\n                  loop: {\n                    type: 'JSExpression',\n                    value: 'this.state.results',\n                  },\n                  children: [\n                    {\n                      componentName: 'Typography.Text',\n                      id: 'node_ockshazuxa5',\n                      props: {\n                        children: {\n                          type: 'JSExpression',\n                          value: 'this.formatResult(this.item)',\n                        },\n                      },\n                    },\n                    {\n                      componentName: 'Typography.Link',\n                      id: 'node_ockshazuxa6',\n                      props: {\n                        href: {\n                          type: 'JSExpression',\n                          value: 'this.item.download_link',\n                        },\n                        target: '_blank',\n                        children: ' - 点击下载',\n                      },\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.item.download_link',\n                      },\n                    },\n                    {\n                      componentName: 'Typography.Link',\n                      id: 'node_ockshazuxa7',\n                      props: {\n                        href: {\n                          type: 'JSExpression',\n                          value: 'this.item.release_notes',\n                        },\n                        target: '_blank',\n                        children: ' - 跳转发布节点',\n                      },\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.item.release_notes',\n                      },\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'NextPage',\n          id: 'node_ocko19zplh1',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n              style: {\n                padding: '',\n              },\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n            contentProps: {\n              noPadding: false,\n              background: 'transparent',\n            },\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ockt3t4q8565',\n              props: {\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ockt3t4q8566',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockt3t4q8567',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'AliAutoDivDefault',\n                          id: 'node_ockt3t4q8568',\n                          props: {\n                            style: {\n                              width: '100%',\n                              display: 'flex',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'AliAutoDivDefault',\n                              id: 'node_ockt3t4q857a',\n                              props: {\n                                style: {\n                                  flex: '1',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Form',\n                                  id: 'node_ocks8dtt1mt',\n                                  props: {\n                                    labelCol: {\n                                      span: 10,\n                                    },\n                                    wrapperCol: {\n                                      span: 14,\n                                    },\n                                    onFinish: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    name: 'basic',\n                                    layout: 'inline',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onFinish',\n                                          relatedEventName: 'onFinish',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onFinish',\n                                          disabled: true,\n                                        },\n                                        {\n                                          name: 'onFinishFailed',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onFieldsChange',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onValuesChange',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                    colon: true,\n                                    labelAlign: 'right',\n                                    preserve: true,\n                                    scrollToFirstError: true,\n                                    size: 'middle',\n                                    values: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.searchValues',\n                                    },\n                                  },\n                                  children: [\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1mz',\n                                      props: {\n                                        label: '项目名称/渠道号',\n                                        name: 'channel_id',\n                                        labelAlign: 'right',\n                                        colon: true,\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Select',\n                                          id: 'node_ocksfuhwhsd',\n                                          props: {\n                                            style: {\n                                              width: '320px',\n                                            },\n                                            options: {\n                                              type: 'JSExpression',\n                                              value: 'this.state.projects',\n                                            },\n                                            showArrow: false,\n                                            tokenSeparators: [],\n                                            showSearch: true,\n                                            defaultActiveFirstOption: true,\n                                            size: 'middle',\n                                            bordered: true,\n                                            filterOption: true,\n                                            optionFilterProp: 'label',\n                                            allowClear: true,\n                                            placeholder: '请输入项目名称/渠道号',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onChange',\n                                                  relatedEventName: 'handleProjectChange',\n                                                },\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onSearch',\n                                                  relatedEventName: 'handleProjectSearch',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onBlur',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onChange',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onDeselect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onFocus',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onInputKeyDown',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseEnter',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseLeave',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onPopupScroll',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onSearch',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onSelect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onDropdownVisibleChange',\n                                                  disabled: false,\n                                                },\n                                              ],\n                                            },\n                                            onChange: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleProjectChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            onSearch: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleProjectSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1m12',\n                                      props: {\n                                        label: '版本号',\n                                        name: 'buildId',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Input',\n                                          id: 'node_ocksfuhwhs3',\n                                          props: {\n                                            placeholder: '请输入版本号',\n                                            style: {\n                                              width: '180px',\n                                            },\n                                            size: 'middle',\n                                            bordered: true,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1m18',\n                                      props: {\n                                        label: '构建人',\n                                        name: 'user_id',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Select',\n                                          id: 'node_ocksfuhwhsi',\n                                          props: {\n                                            style: {\n                                              width: '210px',\n                                            },\n                                            options: {\n                                              type: 'JSExpression',\n                                              value: 'this.state.userOptions',\n                                            },\n                                            showSearch: true,\n                                            defaultActiveFirstOption: false,\n                                            size: 'middle',\n                                            bordered: true,\n                                            filterOption: true,\n                                            optionFilterProp: 'label',\n                                            notFoundContent: {\n                                              type: 'JSExpression',\n                                              value: 'this.userNotFoundContent',\n                                            },\n                                            showArrow: false,\n                                            placeholder: '请输入构建人',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onChange',\n                                                  relatedEventName: 'handleUserChange',\n                                                },\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onSearch',\n                                                  relatedEventName: 'handleUserSearch',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onBlur',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onChange',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onDeselect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onFocus',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onInputKeyDown',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseEnter',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseLeave',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onPopupScroll',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onSearch',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onSelect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onDropdownVisibleChange',\n                                                  disabled: false,\n                                                },\n                                              ],\n                                            },\n                                            onChange: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleUserChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            onSearch: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleUserSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            allowClear: true,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1m19',\n                                      props: {\n                                        label: 'ID',\n                                        name: 'id',\n                                        labelAlign: 'right',\n                                        colon: true,\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Input',\n                                          id: 'node_ocksfuhwhs8',\n                                          props: {\n                                            placeholder: '请输入ID',\n                                            style: {\n                                              width: '180px',\n                                            },\n                                            bordered: true,\n                                            size: 'middle',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1mw',\n                                      props: {\n                                        wrapperCol: {\n                                          offset: 6,\n                                        },\n                                        labelAlign: 'right',\n                                        colon: true,\n                                        style: {\n                                          flex: '1',\n                                          textAlign: 'right',\n                                        },\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocks8dtt1mx',\n                                          props: {\n                                            type: 'primary',\n                                            children: '查询',\n                                            htmlType: 'submit',\n                                            shape: 'default',\n                                            size: 'middle',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  ],\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'AliAutoDivDefault',\n                              id: 'node_ockt3t4q856b',\n                              props: {\n                                style: {},\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockt3t4q85y',\n                                  props: {\n                                    type: 'link',\n                                    children: '新增打包',\n                                    htmlType: 'button',\n                                    shape: 'default',\n                                    size: 'middle',\n                                  },\n                                  condition: true,\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ockshc4ifn1b',\n              props: {\n                childTotalColumns: 12,\n                mode: 'inset',\n                layoutmode: 'O',\n                autolayout: '(12|1)',\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ockshc4ifn1c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockshc4ifn1d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'AliAutoSearchTableDefault',\n                          id: 'node_ocksfuhwhsx',\n                          props: {\n                            rowKey: 'key',\n                            dataSource: {\n                              type: 'JSExpression',\n                              value: 'this.state.pkgs',\n                            },\n                            columns: [\n                              {\n                                title: 'ID',\n                                dataIndex: 'id',\n                                key: 'name',\n                                width: 80,\n                              },\n                              {\n                                title: '渠道号',\n                                dataIndex: 'channels',\n                                key: 'age',\n                                width: 142,\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh2bq0428',\n                                      props: {\n                                        children: {\n                                          type: 'JSExpression',\n                                          value: 'this.item',\n                                        },\n                                        style: {\n                                          display: 'block',\n                                        },\n                                      },\n                                      loop: {\n                                        type: 'JSExpression',\n                                        value: \"this.text.split(',')\",\n                                      },\n                                    },\n                                  ],\n                                },\n                              },\n                              {\n                                title: '版本号',\n                                dataIndex: 'dic_version',\n                                key: 'address',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Tooltip',\n                                      id: 'node_ocksts0jqgj',\n                                      props: {\n                                        title: {\n                                          type: 'JSSlot',\n                                          value: [\n                                            {\n                                              componentName: 'Typography.Text',\n                                              id: 'node_ocksts0jqgn',\n                                              props: {\n                                                children: {\n                                                  type: 'JSExpression',\n                                                  value: \"this.item. channelId + ' / ' +  this.item.version\",\n                                                },\n                                                style: {\n                                                  display: 'block',\n                                                  color: '#FFFFFF',\n                                                },\n                                              },\n                                              loop: {\n                                                type: 'JSExpression',\n                                                value: 'this.text || []',\n                                              },\n                                            },\n                                          ],\n                                        },\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksts0jqgm',\n                                          props: {\n                                            children: {\n                                              type: 'JSExpression',\n                                              value: 'this.text[0].version',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  ],\n                                },\n                                width: 120,\n                              },\n                              {\n                                title: '构建Job',\n                                dataIndex: 'job_name',\n                                width: 180,\n                              },\n                              {\n                                title: '构建类型',\n                                dataIndex: 'packaging_type',\n                                width: 94,\n                              },\n                              {\n                                title: '构建状态',\n                                dataIndex: 'status',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh3jkxzw',\n                                      props: {\n                                        children: {\n                                          type: 'JSExpression',\n                                          value: 'this.statusDesc[this.text]',\n                                        },\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Icon',\n                                      id: 'node_ocksh3jkxzx',\n                                      props: {\n                                        type: 'SyncOutlined',\n                                        size: 16,\n                                        spin: true,\n                                        style: {\n                                          marginLeft: '10px',\n                                        },\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: 'this.text === 2',\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 100,\n                              },\n                              {\n                                title: '构建时间',\n                                dataIndex: 'start_time',\n                                render: {\n                                  type: 'JSFunction',\n                                  value: 'function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                                width: 148,\n                              },\n                              {\n                                title: '构建人',\n                                dataIndex: 'user',\n                                render: {\n                                  type: 'JSFunction',\n                                  value: 'function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                                width: 80,\n                              },\n                              {\n                                title: 'Jenkins 链接',\n                                dataIndex: 'jenkins_link',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Link',\n                                      id: 'node_ocksh64kbx21',\n                                      props: {\n                                        href: {\n                                          type: 'JSExpression',\n                                          value: 'this.text',\n                                        },\n                                        target: '_blank',\n                                        children: '查看',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: 'this.text',\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh64kbx22',\n                                      props: {\n                                        children: '暂无',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: '!this.text',\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 120,\n                              },\n                              {\n                                title: '测试平台链接',\n                                dataIndex: 'is_run_testing',\n                                width: 120,\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Link',\n                                      id: 'node_ocksh3jkxz3e',\n                                      props: {\n                                        href: 'http://rivermap.alibaba.net/dashboard/testExecute',\n                                        target: '_blank',\n                                        children: '查看',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: 'this.text',\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh3jkxz3f',\n                                      props: {\n                                        children: '暂无',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: '!this.text',\n                                      },\n                                    },\n                                  ],\n                                },\n                              },\n                              {\n                                title: '触发源',\n                                dataIndex: 'source',\n                                width: 120,\n                              },\n                              {\n                                title: '详情',\n                                dataIndex: 'id',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Button',\n                                      id: 'node_ocksh8yryw7',\n                                      props: {\n                                        type: 'link',\n                                        children: '查看',\n                                        size: 'small',\n                                        style: {\n                                          padding: '0px',\n                                        },\n                                        __events: {\n                                          eventDataList: [\n                                            {\n                                              type: 'componentEvent',\n                                              name: 'onClick',\n                                              relatedEventName: 'handleDetail',\n                                            },\n                                          ],\n                                          eventList: [\n                                            {\n                                              name: 'onClick',\n                                              disabled: true,\n                                            },\n                                          ],\n                                        },\n                                        onClick: {\n                                          type: 'JSFunction',\n                                          value: 'function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 80,\n                                fixed: 'right',\n                              },\n                              {\n                                title: '结果',\n                                dataIndex: 'id',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Button',\n                                      id: 'node_ocksh9v6jw7',\n                                      props: {\n                                        type: 'link',\n                                        children: '查看',\n                                        size: 'small',\n                                        style: {\n                                          padding: '0px',\n                                        },\n                                        __events: {\n                                          eventDataList: [\n                                            {\n                                              type: 'componentEvent',\n                                              name: 'onClick',\n                                              relatedEventName: 'handleResult',\n                                              paramStr: 'this.text',\n                                            },\n                                          ],\n                                          eventList: [\n                                            {\n                                              name: 'onClick',\n                                              disabled: true,\n                                            },\n                                          ],\n                                        },\n                                        onClick: {\n                                          type: 'JSFunction',\n                                          value: 'function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                        },\n                                        ghost: false,\n                                        href: {\n                                          type: 'JSExpression',\n                                          value: 'this.text',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 80,\n                                fixed: 'right',\n                              },\n                              {\n                                title: '重新执行',\n                                dataIndex: 'id',\n                                width: 92,\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Button',\n                                      id: 'node_ocksh96rad1g',\n                                      props: {\n                                        type: 'text',\n                                        children: '',\n                                        icon: {\n                                          type: 'JSSlot',\n                                          value: [\n                                            {\n                                              componentName: 'Icon',\n                                              id: 'node_ocksh96rad1j',\n                                              props: {\n                                                type: 'ReloadOutlined',\n                                                size: 14,\n                                                color: '#0593d3',\n                                                style: {\n                                                  padding: '3px',\n                                                  border: '1px solid #0593d3',\n                                                  borderRadius: '14px',\n                                                  cursor: 'pointer',\n                                                  height: '22px',\n                                                },\n                                                spin: false,\n                                              },\n                                            },\n                                          ],\n                                        },\n                                        shape: 'circle',\n                                        __events: {\n                                          eventDataList: [\n                                            {\n                                              type: 'componentEvent',\n                                              name: 'onClick',\n                                              relatedEventName: 'reload',\n                                            },\n                                          ],\n                                          eventList: [\n                                            {\n                                              name: 'onClick',\n                                              disabled: true,\n                                            },\n                                          ],\n                                        },\n                                        onClick: {\n                                          type: 'JSFunction',\n                                          value: 'function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                                fixed: 'right',\n                              },\n                            ],\n                            actions: [],\n                            pagination: {\n                              total: {\n                                type: 'JSExpression',\n                                value: 'this.state.total',\n                              },\n                              defaultPageSize: 10,\n                              onPageChange: {\n                                type: 'JSFunction',\n                                value: 'function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                              },\n                              defaultPageIndex: 1,\n                            },\n                            scrollX: 1200,\n                            isPagination: true,\n                          },\n                          condition: {\n                            type: 'JSExpression',\n                            value: '!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)',\n                          },\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocksk6f8fa3b',\n              props: {\n                childTotalColumns: 12,\n                mode: 'inset',\n                layoutmode: 'O',\n                autolayout: '(12|1)',\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocksk6f8fa3c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocksk6f8fa3d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Empty',\n                          id: 'node_ocksk6f8fa3e',\n                          props: {\n                            description: '暂无数据',\n                          },\n                          condition: {\n                            type: 'JSExpression',\n                            value: 'this.state.pkgs.length < 1 && this.state.isSearch',\n                          },\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Text>Hello world!</Text>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/schema.json5",
    "content": "{\n  // 本例是一个非常简单的 Hello world 页面\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Text',\n          props: {},\n          children: 'Hello world!',\n        },\n      ],\n    },\n  ],\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-fetch-handler\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\",\n    \"rax-image\": \"^1.0.0\",\n    \"moment\": \"*\",\n    \"lodash\": \"*\",\n    \"universal-toast\": \"^1.2.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n\npage,\nbody {\n  width: 750rpx;\n  overflow-x: hidden;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport View from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport Image from 'rax-image';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {\n    clickCount: 0,\n    user: {\n      name: '张三',\n      age: 18,\n      avatar: 'https://gw.alicdn.com/tfs/TB1Ui9BMkY2gK0jSZFgXXc5OFXa-50-50.png',\n    },\n    orders: [\n      {\n        title: '【小米智能生活】米家扫地机器人家用全自动扫拖一体机拖地吸尘器',\n        price: 1799,\n        coverUrl: 'https://gw.alicdn.com/tfs/TB1dGVlRfb2gK0jSZK9XXaEgFXa-258-130.png',\n      },\n      {\n        title: '【限时下单立减】Apple/苹果 iPhone 11 4G全网通智能手机正品苏宁易购官方旗舰店苹果11',\n        price: 4999,\n        coverUrl: 'https://gw.alicdn.com/tfs/TB18gdJddTfau8jSZFwXXX1mVXa-1298-1202.png',\n      },\n    ],\n  };\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(__$$getSearchParams()),\n      fetch: __$$createFetchRequestHandler(),\n    },\n  });\n\n  _utils = this._defineUtils();\n\n  _lifeCycles = this._defineLifeCycles();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n\n    this._lifeCycles.didMount();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {\n    this._lifeCycles.willUnmount();\n  } /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <View>\n          <Text>Demo data source logic</Text>\n        </View>\n        <View>\n          <Text>=== User Info: ===</Text>\n        </View>\n        {!!__$$eval(() => __$$context.state.user) && (\n          <View style={{ flexDirection: 'row' }}>\n            <Image\n              source={{ uri: __$$eval(() => __$$context.state.user.avatar) }}\n              style={{ width: '32px', height: '32px' }}\n            />\n            <View onClick={__$$context.hello}>\n              <Text>{__$$eval(() => __$$context.state.user.name)}</Text>\n              <Text>{__$$eval(() => __$$context.state.user.age)}岁</Text>\n            </View>\n          </View>\n        )}\n        <View>\n          <Text>=== Orders: ===</Text>\n        </View>\n        {__$$evalArray(() => __$$eval(() => __$$context.state.orders)).map((order, index) =>\n          ((__$$context) => (\n            <View\n              style={{ flexDirection: 'row' }}\n              data-order={order}\n              onClick={(...__$$args) => {\n                if (__$$isMiniApp) {\n                  const __$$event = __$$args[0];\n                  const order = __$$event.target.dataset.order;\n                  return function () {\n                    __$$context.utils.recordEvent(`CLICK_ORDER`, order.title);\n                  }.apply(this, __$$args);\n                } else {\n                  return function () {\n                    __$$context.utils.recordEvent(`CLICK_ORDER`, order.title);\n                  }.apply(this, __$$args);\n                }\n              }}\n            >\n              <View>\n                <Image source={{ uri: __$$eval(() => order.coverUrl) }} style={{ width: '80px', height: '60px' }} />\n              </View>\n              <View>\n                <Text>{__$$eval(() => order.title)}</Text>\n                <Text>{__$$eval(() => __$$context.utils.formatPrice(order.price, '元'))}</Text>\n              </View>\n            </View>\n          ))(__$$createChildContext(__$$context, { order, index })),\n        )}\n        <View\n          onClick={function () {\n            __$$context.setState({\n              clickCount: __$$context.state.clickCount + 1,\n            });\n          }}\n        >\n          <Text>点击次数：{__$$eval(() => __$$context.state.clickCount)}(点击加 1)</Text>\n        </View>\n        <View>\n          <Text>操作提示：</Text>\n          <Text>1. 点击会员名，可以弹出 Toast &#34;Hello xxx!&#34;</Text>\n          <Text>2. 点击订单，会记录点击的订单信息，并弹出 Toast 提示</Text>\n          <Text>3. 最下面的【点击次数】，点一次应该加 1</Text>\n        </View>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return {\n      list: [\n        {\n          errorHandler: function (err) {\n            setTimeout(() => {\n              __$$context.setState({\n                __refresh: Date.now() + Math.random(),\n              });\n            }, 0);\n            throw err;\n          },\n          id: 'urlParams',\n          type: 'urlParams',\n          isInit: true,\n          options: function () {\n            return undefined;\n          },\n        },\n        {\n          errorHandler: function (err) {\n            setTimeout(() => {\n              __$$context.setState({\n                __refresh: Date.now() + Math.random(),\n              });\n            }, 0);\n            throw err;\n          },\n          id: 'user',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            };\n          },\n          dataHandler: function (response) {\n            if (!response.success) {\n              throw new Error(response.message);\n            }\n            return response.data;\n          },\n          isInit: true,\n        },\n        {\n          errorHandler: function (err) {\n            setTimeout(() => {\n              __$$context.setState({\n                __refresh: Date.now() + Math.random(),\n              });\n            }, 0);\n            throw err;\n          },\n          id: 'orders',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: __$$context.state.user.ordersApiUri,\n              isSync: true,\n            };\n          },\n          dataHandler: function (response) {\n            if (!response.success) {\n              throw new Error(response.message);\n            }\n            return response.data.result;\n          },\n          isInit: true,\n        },\n      ],\n      dataHandler: function (dataMap) {\n        console.info('All datasources loaded:', dataMap);\n      },\n    };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineLifeCycles() {\n    const __$$lifeCycles = {\n      didMount: function didMount() {\n        this.utils.Toast.show(`Hello ${this.state.user.name}!`);\n      },\n\n      willUnmount: function didMount() {\n        this.utils.Toast.show(`Bye, ${this.state.user.name}!`);\n      },\n    };\n\n    // 为所有的方法绑定上下文\n    Object.entries(__$$lifeCycles).forEach(([lifeCycleName, lifeCycleMethod]) => {\n      if (typeof lifeCycleMethod === 'function') {\n        __$$lifeCycles[lifeCycleName] = (...args) => {\n          return lifeCycleMethod.apply(this._context, args);\n        };\n      }\n    });\n\n    return __$$lifeCycles;\n  }\n\n  _defineMethods() {\n    return {\n      hello: function hello() {\n        this.utils.Toast.show(`Hello ${this.state.user.name}!`);\n        console.log(`Hello ${this.state.user.name}!`);\n      },\n    };\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/utils.js",
    "content": "import moment from 'moment';\n\nimport clone from 'lodash/clone';\n\nimport Toast from 'universal-toast';\n\nimport { createRef } from 'rax';\n\nconst formatPrice = function formatPrice(price, unit) {\n  return Number(price).toFixed(2) + unit;\n};\n\nconst recordEvent = function recordEvent(eventName, eventDetail) {\n  this.utils.Toast.show(`[EVENT]: ${eventName} ${eventDetail}`);\n  console.log(`[EVENT]: ${eventName} (detail: %o) (user: %o)`, eventDetail, this.state.user);\n};\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {\n  formatPrice,\n\n  recordEvent,\n\n  moment,\n\n  clone,\n\n  Toast,\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/schema.json5",
    "content": "{\n  // 本例是一个比较复杂的，带有循环和条件渲染的，以及有各种事件处理函数的页面\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'View',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'View',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n    {\n      componentName: 'Image',\n      package: 'rax-image',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Image',\n    },\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      state: {\n        clickCount: 0,\n        user: { name: '张三', age: 18, avatar: 'https://gw.alicdn.com/tfs/TB1Ui9BMkY2gK0jSZFgXXc5OFXa-50-50.png' },\n        orders: [\n          {\n            title: '【小米智能生活】米家扫地机器人家用全自动扫拖一体机拖地吸尘器',\n            price: 1799,\n            coverUrl: 'https://gw.alicdn.com/tfs/TB1dGVlRfb2gK0jSZK9XXaEgFXa-258-130.png',\n          },\n          {\n            title: '【限时下单立减】Apple/苹果 iPhone 11 4G全网通智能手机正品苏宁易购官方旗舰店苹果11',\n            price: 4999,\n            coverUrl: 'https://gw.alicdn.com/tfs/TB18gdJddTfau8jSZFwXXX1mVXa-1298-1202.png',\n          },\n        ],\n      },\n      props: {},\n      lifeCycles: {\n        didMount: {\n          type: 'JSExpression',\n          value: 'function didMount(){\\n  this.utils.Toast.show(`Hello ${this.state.user.name}!`);\\n}',\n        },\n        willUnmount: {\n          type: 'JSExpression',\n          value: 'function didMount(){\\n  this.utils.Toast.show(`Bye, ${this.state.user.name}!`);\\n}',\n        },\n      },\n      methods: {\n        hello: {\n          type: 'JSExpression',\n          value: 'function hello(){\\n  this.utils.Toast.show(`Hello ${this.state.user.name}!`);\\n  console.log(`Hello ${this.state.user.name}!`); }',\n        },\n      },\n      dataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/user\n          {\n            id: 'user',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.success){\\n    throw new Error(response.message);\\n  }\\n  return response.data;\\n}',\n            },\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/orders\n          {\n            id: 'orders',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: {\n                type: 'JSExpression',\n                value: 'this.state.user.ordersApiUri',\n              },\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.success){\\n    throw new Error(response.message);\\n  }\\n  return response.data.result;\\n}',\n            },\n          },\n        ],\n        dataHandler: {\n          type: 'JSExpression',\n          value: 'function (dataMap) {\\n  console.info(\"All datasources loaded:\", dataMap);\\n}',\n        },\n      },\n      children: [\n        {\n          componentName: 'View',\n          children: [\n            {\n              componentName: 'Text',\n              props: {},\n              children: 'Demo data source logic',\n            },\n          ],\n        },\n        {\n          componentName: 'View',\n          children: [\n            {\n              componentName: 'Text',\n              props: {},\n              children: '=== User Info: ===',\n            },\n          ],\n        },\n        {\n          componentName: 'View',\n          condition: {\n            type: 'JSExpression',\n            value: 'this.state.user',\n          },\n          props: {\n            style: { flexDirection: 'row' },\n          },\n          children: [\n            {\n              componentName: 'Image',\n              props: {\n                source: {\n                  uri: {\n                    type: 'JSExpression',\n                    value: 'this.state.user.avatar',\n                  },\n                },\n                style: {\n                  width: '32px',\n                  height: '32px',\n                },\n              },\n            },\n            {\n              componentName: 'View',\n              props: {\n                onClick: {\n                  type: 'JSExpression',\n                  value: 'this.hello',\n                },\n              },\n              children: [\n                {\n                  componentName: 'Text',\n                  children: {\n                    type: 'JSExpression',\n                    value: 'this.state.user.name',\n                  },\n                },\n                {\n                  componentName: 'Text',\n                  children: [\n                    {\n                      type: 'JSExpression',\n                      value: 'this.state.user.age',\n                    },\n                    '岁',\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'View',\n          children: [\n            {\n              componentName: 'Text',\n              props: {},\n              children: '=== Orders: ===',\n            },\n          ],\n        },\n        {\n          componentName: 'View',\n          loop: {\n            type: 'JSExpression',\n            value: 'this.state.orders',\n          },\n          loopArgs: ['order', 'index'],\n          props: {\n            style: { flexDirection: 'row' },\n            onClick: {\n              type: 'JSExpression',\n              value: 'function(){ this.utils.recordEvent(`CLICK_ORDER`, this.order.title) }',\n            },\n          },\n          children: [\n            {\n              componentName: 'View',\n              children: [\n                {\n                  componentName: 'Image',\n                  props: {\n                    source: {\n                      uri: {\n                        type: 'JSExpression',\n                        value: 'this.order.coverUrl',\n                      },\n                    },\n                    style: {\n                      width: '80px',\n                      height: '60px',\n                    },\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'View',\n              children: [\n                {\n                  componentName: 'Text',\n                  children: {\n                    type: 'JSExpression',\n                    value: 'this.order.title',\n                  },\n                },\n                {\n                  componentName: 'Text',\n                  children: {\n                    type: 'JSExpression',\n                    value: 'this.utils.formatPrice(this.order.price, \"元\")',\n                  },\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'View',\n          props: {\n            onClick: {\n              type: 'JSExpression',\n              value: 'function (){ this.setState({ clickCount: this.state.clickCount + 1 }) }',\n            },\n          },\n          children: [\n            {\n              componentName: 'Text',\n              children: [\n                '点击次数：',\n                {\n                  type: 'JSExpression',\n                  value: 'this.state.clickCount',\n                },\n                '(点击加 1)',\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'View',\n          children: [\n            {\n              componentName: 'Text',\n              props: {},\n              children: '操作提示：',\n            },\n            {\n              componentName: 'Text',\n              props: {},\n              children: '1. 点击会员名，可以弹出 Toast \"Hello xxx!\"',\n            },\n            {\n              componentName: 'Text',\n              props: {},\n              children: '2. 点击订单，会记录点击的订单信息，并弹出 Toast 提示',\n            },\n            {\n              componentName: 'Text',\n              props: {},\n              children: '3. 最下面的【点击次数】，点一次应该加 1',\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  utils: [\n    // 可以直接定义一个函数\n    {\n      name: 'formatPrice',\n      type: 'function',\n      content: {\n        type: 'JSExpression',\n        value: 'function formatPrice(price, unit) { return Number(price).toFixed(2) + unit; }',\n      },\n    },\n    // 在 utils 里面也可以用 this 访问当前上下文:\n    {\n      name: 'recordEvent',\n      type: 'function',\n      content: {\n        type: 'JSExpression',\n        value: 'function recordEvent(eventName, eventDetail) { \\n  this.utils.Toast.show(`[EVENT]: ${eventName} ${eventDetail}`);\\n  console.log(`[EVENT]: ${eventName} (detail: %o) (user: %o)`, eventDetail, this.state.user); }',\n      },\n    },\n    // 也可以直接从 npm 包引入 (下例等价于 `import moment from 'moment';`)\n    {\n      name: 'moment',\n      type: 'npm',\n      content: {\n        package: 'moment',\n        version: '*',\n        exportName: 'moment',\n      },\n    },\n    // 可以引入子目录（下例等价于 `import clone from 'lodash/clone';`)\n    {\n      name: 'clone',\n      type: 'npm',\n      content: {\n        package: 'lodash',\n        version: '*',\n        exportName: 'clone',\n        destructuring: false,\n        main: '/clone',\n      },\n    },\n    {\n      name: 'Toast',\n      type: 'npm',\n      content: {\n        package: 'universal-toast',\n        version: '^1.2.0',\n        exportName: 'Toast', // TODO: 这个 exportName 是否可以省略？省略后默认是上一层的 name？\n      },\n    },\n  ],\n  css: 'page,body{\\n  width: 750rpx;\\n  overflow-x: hidden;\\n}',\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\",\n    \"rax-link\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    },\n    {\n      \"path\": \"/list\",\n      \"source\": \"pages/List/index\"\n    },\n    {\n      \"path\": \"/detail\",\n      \"source\": \"pages/Detail/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n\npage,\nbody {\n  width: 750rpx;\n  overflow-x: hidden;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/pages/Detail/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/pages/Detail/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport View from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport Link from 'rax-link';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Detail$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <View>\n          <Text>This is the Detail Page</Text>\n        </View>\n        <Link href=\"javascript:history.back();\" miniappHref=\"navigateBack:\">\n          <Text>Go back</Text>\n        </Link>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Detail$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport View from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport Link from 'rax-link';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <View>\n          <Text>This is the Home Page</Text>\n        </View>\n        <Link href=\"#/list\" miniappHref=\"navigate:/pages/List/index\">\n          <Text>Go To The List Page</Text>\n        </Link>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/pages/List/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/pages/List/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport View from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport Link from 'rax-link';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass List$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <View>\n          <Text>This is the List Page</Text>\n        </View>\n        <Link href=\"#/detail\" miniappHref=\"navigate:/pages/Detail/index\">\n          <Text>Go To The Detail Page</Text>\n        </Link>\n        <Link href=\"javascript:history.back();\" miniappHref=\"navigateBack:\">\n          <Text>Go back</Text>\n        </Link>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default List$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/schema.json5",
    "content": "{\n  // 本例是一个路由测试页面，里面有几个页面，相互之间有跳转关系的\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'View',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'View',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n    {\n      componentName: 'Link',\n      package: 'rax-link',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Link',\n    },\n    {\n      componentName: 'Image',\n      package: 'rax-image',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Image',\n    },\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      fileName: 'home',\n      state: {},\n      dataSource: {\n        list: [],\n      },\n      meta: {\n        router: '/',\n      },\n      children: [\n        {\n          componentName: 'View',\n          children: [\n            {\n              componentName: 'Text',\n              children: 'This is the Home Page',\n            },\n          ],\n        },\n        {\n          componentName: 'Link',\n          props: {\n            href: '#/list',\n            miniappHref: 'navigate:/pages/List/index',\n          },\n          children: [\n            {\n              componentName: 'Text',\n              children: 'Go To The List Page',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'Page',\n      fileName: 'list',\n      state: {},\n      dataSource: {\n        list: [],\n      },\n      meta: {\n        router: '/list',\n      },\n      children: [\n        {\n          componentName: 'View',\n          children: [\n            {\n              componentName: 'Text',\n              children: 'This is the List Page',\n            },\n          ],\n        },\n        {\n          componentName: 'Link',\n          props: {\n            href: '#/detail',\n            miniappHref: 'navigate:/pages/Detail/index',\n          },\n          children: [\n            {\n              componentName: 'Text',\n              children: 'Go To The Detail Page',\n            },\n          ],\n        },\n        {\n          componentName: 'Link',\n          props: {\n            href: 'javascript:history.back();',\n            miniappHref: 'navigateBack:',\n          },\n          children: [\n            {\n              componentName: 'Text',\n              children: 'Go back',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'Page',\n      fileName: 'detail',\n      state: {},\n      dataSource: {\n        list: [],\n      },\n      meta: {\n        router: '/detail',\n      },\n      children: [\n        {\n          componentName: 'View',\n          children: [\n            {\n              componentName: 'Text',\n              children: 'This is the Detail Page',\n            },\n          ],\n        },\n        {\n          componentName: 'Link',\n          props: {\n            href: 'javascript:history.back();',\n            miniappHref: 'navigateBack:',\n          },\n          children: [\n            {\n              componentName: 'Text',\n              children: 'Go back',\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  css: 'page,body{\\n  width: 750rpx;\\n  overflow-x: hidden;\\n}',\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/README.md",
    "content": "# 这个 demo 是用来演示运行时的方案的。\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"],\n  \"miniapp\": {\n    \"buildType\": \"runtime\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"@alife/right-design-card\": \"*\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n\npage,\nbody {\n  width: 750rpx;\n  overflow-x: hidden;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Card from '@alife/right-design-card';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Card>\n          <Text>This is a demo card.</Text>\n        </Card>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/schema.json5",
    "content": "{\n  // 本例是为了测试一下小程序的 runtime 模式\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Card',\n      package: '@alife/right-design-card',\n      version: '*',\n      destructuring: false,\n      exportName: 'Card',\n    },\n    {\n      componentName: 'View',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'View',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n    {\n      componentName: 'Image',\n      package: 'rax-image',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Image',\n    },\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      state: {},\n      props: {},\n      lifeCycles: {},\n      methods: {},\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Card',\n          children: [\n            {\n              componentName: 'Text',\n              props: {},\n              children: 'This is a demo card.',\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  utils: [],\n  css: 'page,body{\\n  width: 750rpx;\\n  overflow-x: hidden;\\n}',\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n    miniAppBuildType: 'runtime',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Text\n          onClick={function () {\n            __$$context.setLocale(__$$context.getLocale() === 'en-US' ? 'zh-CN' : 'en-US');\n          }}\n        >\n          {__$$eval(() => __$$context.i18n['hello-world'])}\n        </Text>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/schema.json5",
    "content": "{\n  // 这是一个关于国际化的 schema 示例\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Text',\n          props: {\n            onClick: {\n              type: 'JSFunction',\n              value: \"function () {\\n  this.setLocale(this.getLocale() === 'en-US' ? 'zh-CN' : 'en-US');\\n}\",\n            },\n          },\n          children: [\n            {\n              type: 'JSExpression',\n              value: 'this.i18n[\"hello-world\"]',\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'hello-world': '你好，世界！',\n    },\n    'en-US': {\n      'hello-world': 'Hello world!',\n    },\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-table\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Table from 'rax-table';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Table\n          renderCell={(cellData, rowData, rowIndex) =>\n            ((__$$context) => <Text content={__$$eval(() => rowData.name)} />)(\n              __$$createChildContext(__$$context, {\n                cellData,\n                rowData,\n                rowIndex,\n              }),\n            )\n          }\n        />\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/schema.json5",
    "content": "{\n  // 这是一个关于 JSSlot 的 schema 示例\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n    {\n      componentName: 'Table',\n      package: 'rax-table',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Table',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Table',\n          props: {\n            renderCell: {\n              type: 'JSSlot',\n              params: ['cellData', 'rowData', 'rowIndex'],\n              value: [\n                {\n                  componentName: 'Text',\n                  props: {\n                    content: {\n                      type: 'JSExpression',\n                      value: 'this.rowData.name',\n                    },\n                  },\n                },\n              ],\n            },\n          },\n        },\n      ],\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'hello-world': '你好，世界！',\n    },\n    'en-US': {\n      'hello-world': 'Hello world!',\n    },\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Text\n          content=\"this is a line.&#10;this is another line.&#10;...\"\n        />\n        <Text\n          content=\"this is a line.&#10;this is another line.&#10;...\"\n        />\n        <Text>this is a line.&#10;this is another line.&#10;...</Text>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/schema.json5",
    "content": "{\n  // 这是一个关于 JSSlot 的 schema 示例\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Text',\n          props: {\n            content: 'this is a line.\\nthis is another line.\\n...'\n          },\n        },\n        {\n          componentName: 'Text',\n          props: {\n            content: {\n              type: \"JSExpression\",\n              value: '\"this is a line.\\\\nthis is another line.\\\\n...\"'\n            }\n          },\n        },\n        {\n          componentName: 'Text',\n          props: {\n          },\n          children: \"this is a line.\\nthis is another line.\\n...\"\n        },\n      ],\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'hello-world': '你好，世界！',\n    },\n    'en-US': {\n      'hello-world': 'Hello world!',\n    },\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-table\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Table from 'rax-table';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Table\n          renderCell={(cellData, rowData, rowIndex) =>\n            ((__$$context) => [<Text content=\"Hello world\" />, <Text content={__$$eval(() => rowData.name)} />])(\n              __$$createChildContext(__$$context, {\n                cellData,\n                rowData,\n                rowIndex,\n              }),\n            )\n          }\n        />\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/schema.json5",
    "content": "{\n  // 这是一个关于 JSSlot 的 schema 示例\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n    {\n      componentName: 'Table',\n      package: 'rax-table',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Table',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Table',\n          props: {\n            renderCell: {\n              type: 'JSSlot',\n              params: ['cellData', 'rowData', 'rowIndex'],\n              value: [\n                {\n                  componentName: 'Text',\n                  props: {\n                    content: 'Hello world',\n                  },\n                },\n                {\n                  componentName: 'Text',\n                  props: {\n                    content: {\n                      type: 'JSExpression',\n                      value: 'this.rowData.name',\n                    },\n                  },\n                },\n              ],\n            },\n          },\n        },\n      ],\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'hello-world': '你好，世界！',\n    },\n    'en-US': {\n      'hello-world': 'Hello world!',\n    },\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-table\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Table from 'rax-table';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Table\n          renderCell={(cellData, rowData, rowIndex) =>\n            ((__$$context) => [\n              <Text content=\"Hello world\" />,\n              !!__$$eval(() => __$$context.state.isNameVisible) && <Text content={__$$eval(() => rowData.name)} />,\n            ])(\n              __$$createChildContext(__$$context, {\n                cellData,\n                rowData,\n                rowIndex,\n              }),\n            )\n          }\n        />\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/schema.json5",
    "content": "{\n  // 这是一个关于 JSSlot 的 schema 示例\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n    {\n      componentName: 'Table',\n      package: 'rax-table',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Table',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Table',\n          props: {\n            renderCell: {\n              type: 'JSSlot',\n              params: ['cellData', 'rowData', 'rowIndex'],\n              value: [\n                {\n                  componentName: 'Text',\n                  props: {\n                    content: 'Hello world',\n                  },\n                },\n                {\n                  componentName: 'Text',\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.state.isNameVisible',\n                  },\n                  props: {\n                    content: {\n                      type: 'JSExpression',\n                      value: 'this.rowData.name',\n                    },\n                  },\n                },\n              ],\n            },\n          },\n        },\n      ],\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'hello-world': '你好，世界！',\n    },\n    'en-US': {\n      'hello-world': 'Hello world!',\n    },\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-table\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Table from 'rax-table';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Table\n          renderCell={(cellData, rowData, rowIndex) =>\n            ((__$$context) =>\n              __$$evalArray(() => __$$eval(() => __$$context.state.orders)).map((order, index) =>\n                ((__$$context) => <Text content={__$$eval(() => rowData.name)} />)(\n                  __$$createChildContext(__$$context, { order, index }),\n                ),\n              ))(\n              __$$createChildContext(__$$context, {\n                cellData,\n                rowData,\n                rowIndex,\n              }),\n            )\n          }\n        />\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/schema.json5",
    "content": "{\n  // 这是一个关于 JSSlot 的 schema 示例\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n    {\n      componentName: 'Table',\n      package: 'rax-table',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Table',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Table',\n          props: {\n            renderCell: {\n              type: 'JSSlot',\n              params: ['cellData', 'rowData', 'rowIndex'],\n              value: [\n                {\n                  componentName: 'Text',\n                  loop: {\n                    type: 'JSExpression',\n                    value: 'this.state.orders',\n                  },\n                  loopArgs: ['order', 'index'],\n                  props: {\n                    content: {\n                      type: 'JSExpression',\n                      value: 'this.rowData.name',\n                    },\n                  },\n                },\n              ],\n            },\n          },\n        },\n      ],\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'hello-world': '你好，世界！',\n    },\n    'en-US': {\n      'hello-world': 'Hello world!',\n    },\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"],\n  \"miniapp\": {\n    \"buildType\": \"runtime\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"@alilc/b6-page\": \"^0.1.0\",\n    \"@alilc/b6-text\": \"^0.1.0\",\n    \"@alilc/b6-compact-legao-builtin\": \"1.x\",\n    \"antd\": \"3.x\",\n    \"@alilc/b6-util-mocks\": \"1.x\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/aaaa\",\n      \"source\": \"pages/Aaaa/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"jinyuan-test2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>jinyuan-test2</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport { Page } from '@alilc/b6-page';\n\nimport { Text } from '@alilc/b6-text';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Aaaa$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(__$$getSearchParams()),\n    },\n  });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page title=\"\" backgroundColor=\"#fff\" textColor=\"#333\" style={{}}>\n        <Text content=\"欢迎使用 BuildSuccess！sadsad\" style={{}} fieldId=\"text_kp6ci11t\" />\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return {\n      list: [\n        {\n          errorHandler: function (err) {\n            setTimeout(() => {\n              __$$context.setState({\n                __refresh: Date.now() + Math.random(),\n              });\n            }, 0);\n            throw err;\n          },\n          id: 'urlParams',\n          type: 'urlParams',\n          description: 'URL参数',\n          options: function () {\n            return {\n              uri: '',\n            };\n          },\n          isInit: true,\n        },\n      ],\n    };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Aaaa$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/utils.js",
    "content": "import legaoBuiltin from '@alilc/b6-compact-legao-builtin';\n\nimport { message, Notification as notification, Modal as modal } from 'antd';\n\nimport { mocks } from '@alilc/b6-util-mocks';\n\nimport { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {\n  legaoBuiltin,\n\n  message,\n\n  notification,\n\n  mocks,\n\n  modal,\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/b6-page',\n      version: '^0.1.0',\n      componentName: 'Page',\n      destructuring: true,\n      exportName: 'Page',\n    },\n    {\n      package: '@alilc/b6-text',\n      version: '^0.1.0',\n      componentName: 'Text',\n      destructuring: true,\n      exportName: 'Text',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_ockp6ci0hm1',\n      props: {\n        title: '',\n        backgroundColor: '#fff',\n        textColor: '#333',\n        style: {},\n      },\n      fileName: 'aaaa',\n      dataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n            description: 'URL参数',\n            options: {\n              uri: '',\n            },\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Text',\n          id: 'node_ockp6ci0hm2',\n          props: {\n            content: '欢迎使用 BuildSuccess！sadsad',\n            style: {},\n            fieldId: 'text_kp6ci11t',\n          },\n        },\n      ],\n      meta: {\n        router: '/aaaa',\n      },\n      methodsModule: {\n        type: 'JSModule',\n        compiled: '\"use strict\";\\n\\nObject.defineProperty(exports, \"__esModule\", {\\n  value: true\\n});\\nexports.helloPage = helloPage;\\n\\n/**\\n * Private, and can be re-used functions\\n * Actions panel help documentation：\\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\\n */\\nfunction printLog(obj) {\\n  console.info(obj);\\n}\\n/**\\n * page function\\n */\\n\\n\\nfunction helloPage() {\\n  console.log(\\'hello page\\');\\n}',\n        source: \"/**\\n * Private, and can be re-used functions\\n * Actions panel help documentation：\\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\\n */\\nfunction printLog(obj) {\\n  console.info(obj);\\n}\\n\\n/**\\n * page function\\n */\\nexport function helloPage() {\\n  console.log('hello page');\\n}\",\n      },\n    },\n  ],\n  i18n: {},\n  utils: [\n    {\n      name: 'legaoBuiltin',\n      type: 'npm',\n      content: {\n        exportName: 'legaoBuiltin',\n        package: '@alilc/b6-compact-legao-builtin',\n        version: '1.x',\n      },\n    },\n    // 不带 componentName 的：\n    {\n      name: 'message',\n      type: 'npm',\n      content: {\n        package: 'antd',\n        version: '3.x',\n        destructuring: true,\n        exportName: 'message',\n      },\n    },\n    // 带有 componentName：\n    {\n      name: 'notification',\n      type: 'npm',\n      content: {\n        package: 'antd',\n        version: '3.x',\n        destructuring: true,\n        exportName: 'Notification',\n        componentName: 'notification',\n      },\n    },\n    {\n      name: 'mocks',\n      type: 'npm',\n      content: {\n        package: '@alilc/b6-util-mocks',\n        version: '1.x',\n        exportName: 'mocks',\n        destructuring: true,\n      },\n    },\n    {\n      name: 'modal',\n      type: 'npm',\n      content: {\n        package: 'antd',\n        version: '3.x',\n        destructuring: true,\n        exportName: 'Modal',\n      },\n    },\n  ],\n  constants: {},\n  dataSource: {\n    list: [],\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n    miniAppBuildType: 'runtime',\n  },\n  meta: {\n    name: 'jinyuan-test2',\n    git_group: 'b6',\n    project_name: 'jinyuan-test2',\n    description: '瑾源测试',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"rax-view\": \"^1.0.0\",\n    \"rax-text\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"/\",\n      \"source\": \"pages/Home/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"Rax App Demo\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>Rax App Demo</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'hello-world': '你好，世界！',\n  },\n  'en-US': {\n    'hello-world': 'Hello world!',\n  },\n};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/pages/Home/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/pages/Home/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport Page from 'rax-view';\n\nimport Text from 'rax-text';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils, { RefsManager } from '../../utils';\n\nimport './index.css';\n\nclass Home$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, { runtimeConfig: true });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Text\n          ref={__$$context._refsManager.linkRef('helloText')}\n          onClick={function () {\n            __$$context.setLocale(__$$context.getLocale() === 'en-US' ? 'zh-CN' : 'en-US');\n          }}\n        >\n          {__$$eval(() => __$$context.i18n['hello-world'])}\n        </Text>\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      $(refName) {\n        return self._refsManager.get(refName);\n      },\n      $$(refName) {\n        return self._refsManager.getAll(refName);\n      },\n      get _refsManager() {\n        if (!self._refsManager) {\n          self._refsManager = new RefsManager();\n        }\n        return self._refsManager;\n      },\n\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return { list: [] };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Home$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/schema.json5",
    "content": "{\n  // 这是一个关于国际化的 schema 示例\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Page',\n      package: 'rax-view',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Page',\n    },\n    {\n      componentName: 'Text',\n      package: 'rax-text',\n      version: '^1.0.0',\n      destructuring: false,\n      exportName: 'Text',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      lifeCycles: {},\n      fileName: 'home',\n      meta: {\n        router: '/',\n      },\n      dataSource: {\n        list: [],\n      },\n      children: [\n        {\n          componentName: 'Text',\n          props: {\n            ref: 'helloText',\n            onClick: {\n              type: 'JSFunction',\n              value: \"function () {\\n  this.setLocale(this.getLocale() === 'en-US' ? 'zh-CN' : 'en-US');\\n}\",\n            },\n          },\n          children: [\n            {\n              type: 'JSExpression',\n              value: 'this.i18n[\"hello-world\"]',\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'hello-world': '你好，世界！',\n    },\n    'en-US': {\n      'hello-world': 'Hello world!',\n    },\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n  },\n  meta: {\n    name: 'Rax App Demo',\n    git_group: 'demo-group',\n    project_name: 'demo-project',\n    description: '这是一个示例应用',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.eslintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.eslintrc.js",
    "content": "const { getESLintConfig } = require('@iceworks/spec');\n\n// https://www.npmjs.com/package/@iceworks/spec\nmodule.exports = {\n  ...getESLintConfig('rax'),\n  rules: {\n    'max-len': ['error', { code: 200 }],\n    'function-paren-newline': 'off',\n    '@typescript-eslint/indent': 'off',\n    'prettier/prettier': 'off',\n    'no-empty': 'off',\n    'no-unused-vars': 'off',\n    '@iceworks/best-practices/recommend-functional-component': 'off',\n  },\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n*~\n*.swp\n*.log\n\n.DS_Store\n.idea/\n.temp/\n\nbuild/\ndist/\nlib/\ncoverage/\nnode_modules/\n.rax/\n\ntemplate.yml"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.prettierignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.prettierrc.js",
    "content": "const { getPrettierConfig } = require('@iceworks/spec');\n\nmodule.exports = getPrettierConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.stylelintignore",
    "content": "node_modules/\nlib/\ndist/\nbuild/\ncoverage/\ndemo/\nes/\n.rax/\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.stylelintrc.js",
    "content": "const { getStylelintConfig } = require('@iceworks/spec');\n\nmodule.exports = getStylelintConfig('rax');\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/README.md",
    "content": "# rax-materials-basic-app\n\n## Getting Started\n\n### `npm run start`\n\nRuns the app in development mode.\n\nOpen [http://localhost:3333](http://localhost:3333) to view it in the browser.\n\nThe page will reload if you make edits.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/build.json",
    "content": "{\n  \"inlineStyle\": false,\n  \"plugins\": [],\n  \"targets\": [\"web\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"rax-demo-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"rax-app start\",\n    \"build\": \"rax-app build\",\n    \"eslint\": \"eslint --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"prettier\": \"prettier **/* --write\",\n    \"lint\": \"npm run eslint && npm run stylelint\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-http-handler\": \"^1.0.0\",\n    \"universal-env\": \"^3.2.0\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"rax\": \"^1.1.0\",\n    \"rax-document\": \"^0.1.6\",\n    \"@alilc/lowcode-components\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"rax-app\": \"^3.0.0\",\n    \"eslint\": \"^6.8.0\",\n    \"prettier\": \"^2.1.2\",\n    \"stylelint\": \"^13.7.2\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/app.js",
    "content": "import { runApp } from 'rax-app';\n\nimport './global.css';\n\nrunApp({\n  router: {\n    mode: 'hash',\n  },\n});\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/app.json",
    "content": "{\n  \"routes\": [\n    {\n      \"path\": \"\",\n      \"source\": \"pages/Example/index\"\n    }\n  ],\n  \"window\": {\n    \"title\": \"example\"\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/document/index.jsx",
    "content": "import { createElement } from 'rax';\nimport { Root, Style, Script } from 'rax-document';\n\nfunction Document() {\n  return (\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta\n          name=\"viewport\"\n          content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover\"\n        />\n        <title>example</title>\n        <Style />\n      </head>\n      <body>\n        {/* root container */}\n        <Root />\n        <Script />\n      </body>\n    </html>\n  );\n}\n\nexport default Document;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/global.css",
    "content": "body {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' && (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string' ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/pages/Example/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/pages/Example/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：rax 框架的导出名和各种组件名除外。\nimport { createElement, Component } from 'rax';\nimport { getSearchParams as __$$getSearchParams } from 'rax-app';\n\nimport { Page, Table } from '@alilc/lowcode-components';\n\nimport { createHttpHandler as __$$createHttpRequestHandler } from '@alilc/lowcode-datasource-http-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport { isMiniApp as __$$isMiniApp } from 'universal-env';\n\nimport __$$constants from '../../constants';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$projectUtils from '../../utils';\n\nimport './index.css';\n\nclass Example$$Page extends Component {\n  state = {};\n\n  _methods = this._defineMethods();\n\n  _context = this._createContext();\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this._context, {\n    runtimeConfig: true,\n    requestHandlersMap: { http: __$$createHttpRequestHandler() },\n  });\n\n  _utils = this._defineUtils();\n\n  constructor(props, context) {\n    super(props);\n\n    __$$i18n._inject2(this);\n  } /* end of constructor */\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  } /* end of componentDidMount */\n\n  componentWillUnmount() {} /* end of componentWillUnmount */\n\n  render() {\n    const __$$context = this._context;\n    const {\n      state,\n      setState,\n      dataSourceMap,\n      reloadDataSource,\n      utils,\n      constants,\n      i18n,\n      i18nFormat,\n      getLocale,\n      setLocale,\n    } = __$$context;\n\n    return (\n      <Page>\n        <Table\n          dataSource={__$$eval(() => __$$context.dataSourceMap['userList'])}\n          columns={[\n            { dataIndex: 'name', title: '姓名' },\n            { dataIndex: 'age', title: '年龄' },\n          ]}\n        />\n      </Page>\n    );\n  } /* end of render */\n\n  _createContext() {\n    const self = this;\n    const context = {\n      get state() {\n        return self.state;\n      },\n      setState(newState, callback) {\n        self.setState(newState, callback);\n      },\n      get dataSourceMap() {\n        return self._dataSourceEngine.dataSourceMap || {};\n      },\n      async reloadDataSource() {\n        await self._dataSourceEngine.reloadDataSource();\n      },\n      get utils() {\n        return self._utils;\n      },\n      get page() {\n        return context;\n      },\n      get component() {\n        return context;\n      },\n      get props() {\n        return self.props;\n      },\n      get constants() {\n        return __$$constants;\n      },\n      i18n: __$$i18n.i18n,\n      i18nFormat: __$$i18n.i18nFormat,\n      getLocale: __$$i18n.getLocale,\n      setLocale(locale) {\n        __$$i18n.setLocale(locale);\n        self.forceUpdate();\n      },\n      ...this._methods,\n    };\n\n    return context;\n  }\n\n  _defineDataSourceConfig() {\n    const __$$context = this._context;\n    return {\n      list: [\n        {\n          errorHandler: function (err) {\n            setTimeout(() => {\n              __$$context.setState({\n                __refresh: Date.now() + Math.random(),\n              });\n            }, 0);\n            throw err;\n          },\n          id: 'userList',\n          type: 'http',\n          description: '用户列表',\n          options: function () {\n            return {\n              uri: 'https://api.example.com/user/list',\n            };\n          },\n          isInit: true,\n        },\n      ],\n    };\n  }\n\n  _defineUtils() {\n    return {\n      ...__$$projectUtils,\n    };\n  }\n\n  _defineMethods() {\n    return {};\n  }\n}\n\nexport default Example$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  return Object.assign({}, oldContext, ext);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'rax';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter((insRef) => !!insRef.current);\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"preserve\",\n    \"jsxFactory\": \"createElement\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"rax-app\": [\".rax/index.ts\"]\n    }\n  },\n  \"include\": [\"src\", \".rax\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/lowcode-components',\n      version: '^1.0.0',\n      componentName: 'Page',\n      destructuring: true,\n      exportName: 'Page',\n    },\n    {\n      package: '@alilc/lowcode-components',\n      version: '^1.0.0',\n      componentName: 'Table',\n      destructuring: true,\n      exportName: 'Table',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_ockp6ci0hm1',\n      props: {},\n      fileName: 'example',\n      dataSource: {\n        list: [\n          {\n            id: 'userList',\n            type: 'http',\n            description: '用户列表',\n            options: {\n              uri: 'https://api.example.com/user/list',\n            },\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Table',\n          id: 'node_ockp6ci0hm22',\n          props: {\n            dataSource: {\n              type: 'DataSource',\n              id: 'userList',\n            },\n            columns: [\n              {\n                dataIndex: 'name',\n                title: '姓名',\n              },\n              {\n                dataIndex: 'age',\n                title: '年龄',\n              },\n            ],\n          },\n        },\n      ],\n    },\n  ],\n  meta: {\n    name: 'example',\n    description: 'Example',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-fetch-handler\": \"^1.0.0\",\n    \"@alifd/next\": \"1.19.18\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>demo应用</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Form, Input, NumberPicker, Select, Button } from '@alifd/next';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(window.location.search),\n      fetch: __$$createFetchRequestHandler(),\n    },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter' };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'urlParams',\n          type: 'urlParams',\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n          options: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'user',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'orders',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/orders',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data.result;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n      dataHandler: function (dataMap) {\n        console.info('All datasources loaded:', dataMap);\n      },\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n\n    console.log('componentDidMount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}>\n        <Form\n          labelCol={__$$eval(() => this.state.colNum)}\n          style={{}}\n          ref={this._refsManager.linkRef('testForm')}\n        >\n          <Form.Item label=\"姓名：\" name=\"name\" initValue=\"李雷\">\n            <Input placeholder=\"请输入\" size=\"medium\" style={{ width: 320 }} />\n          </Form.Item>\n          <Form.Item label=\"年龄：\" name=\"age\" initValue=\"22\">\n            <NumberPicker size=\"medium\" type=\"normal\" />\n          </Form.Item>\n          <Form.Item label=\"职业：\" name=\"profession\">\n            <Select\n              dataSource={[\n                { label: '教师', value: 't' },\n                { label: '医生', value: 'd' },\n                { label: '歌手', value: 's' },\n              ]}\n            />\n          </Form.Item>\n          <div style={{ textAlign: 'center' }}>\n            <Button.Group>\n              {__$$evalArray(() => ['a', 'b', 'c']).map((item, index) =>\n                ((__$$context) =>\n                  !!__$$eval(() => index >= 1) && (\n                    <Button type=\"primary\" style={{ margin: '0 5px 0 5px' }}>\n                      {__$$eval(() => item)}\n                    </Button>\n                  ))(__$$createChildContext(__$$context, { item, index }))\n              )}\n            </Button.Group>\n          </div>\n        </Form>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '/',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo1/schema.json5",
    "content": "{\n\t\"version\": \"1.0.0\",\n\t\"componentsMap\": [\n\t\t{\n\t\t\t\"componentName\": \"Button\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\",\n\t\t\t\"subName\": \"Group\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Input\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Input\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\",\n\t\t\t\"subName\": \"Item\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"NumberPicker\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Select\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Select\"\n\t\t}\n\t],\n\t\"componentsTree\": [\n\t\t{\n\t\t\t\"componentName\": \"Page\",\n\t\t\t\"id\": \"node$1\",\n\t\t\t\"meta\": {\n\t\t\t\t\"title\": \"测试\",\n\t\t\t\t\"router\": \"/\"\n\t\t\t},\n\t\t\t\"props\": {\n\t\t\t\t\"ref\": \"outterView\",\n\t\t\t\t\"autoLoading\": true\n\t\t\t},\n\t\t\t\"fileName\": \"test\",\n\t\t\t\"state\": {\n\t\t\t\t\"text\": \"outter\"\n\t\t\t},\n\t\t\t\"lifeCycles\": {\n\t\t\t\t\"componentDidMount\": {\n\t\t\t\t\t\"type\": \"JSFunction\",\n\t\t\t\t\t\"value\": \"function() { console.log('componentDidMount'); }\"\n\t\t\t\t}\n\t\t\t},\n\t\t\tdataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/user\n          {\n            id: 'user',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data;\\n}',\n            },\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/orders\n          {\n            id: 'orders',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: \"https://shs.xxx.com/mock/1458/demo/orders\",\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data.result;\\n}',\n            },\n          },\n        ],\n        dataHandler: {\n          type: 'JSExpression',\n          value: 'function (dataMap) {\\n  console.info(\"All datasources loaded:\", dataMap);\\n}',\n        },\n      },\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"componentName\": \"Form\",\n\t\t\t\t\t\"id\": \"node$2\",\n\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\"labelCol\": {\n\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\"value\": \"this.state.colNum\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"style\": {},\n\t\t\t\t\t\t\"ref\": \"testForm\"\n\t\t\t\t\t},\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$3\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"姓名：\",\n\t\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\t\"initValue\": \"李雷\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Input\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$4\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"placeholder\": \"请输入\",\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\"width\": 320\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$5\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"年龄：\",\n\t\t\t\t\t\t\t\t\"name\": \"age\",\n\t\t\t\t\t\t\t\t\"initValue\": \"22\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$6\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$7\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"职业：\",\n\t\t\t\t\t\t\t\t\"name\": \"profession\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Select\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$8\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"dataSource\": [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"教师\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"t\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"医生\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"d\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"歌手\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"s\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Div\",\n\t\t\t\t\t\t\t\"id\": \"node$9\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\"textAlign\": \"center\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$a\",\n\t\t\t\t\t\t\t\t\t\"props\": {},\n\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$b\",\n\t\t\t\t\t\t\t\t\t\t\t\"condition\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"this.index >= 1\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"loop\": [\"a\", \"b\", \"c\"],\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"primary\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"this.item\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"constants\": {\n\t\t\"ENV\": \"prod\",\n\t\t\"DOMAIN\": \"xxx.xxx.com\"\n\t},\n\t\"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n\t\"config\": {\n\t\t\"sdkVersion\": \"1.0.3\",\n\t\t\"historyMode\": \"hash\",\n\t\t\"targetRootID\": \"J_Container\",\n\t\t\"layout\": {\n\t\t\t\"componentName\": \"BasicLayout\",\n\t\t\t\"props\": {\n\t\t\t\t\"logo\": \"...\",\n\t\t\t\t\"name\": \"测试网站\"\n\t\t\t}\n\t\t},\n\t\t\"theme\": {\n\t\t\t\"package\": \"@alife/theme-fusion\",\n\t\t\t\"version\": \"^0.1.0\",\n\t\t\t\"primary\": \"#ff9966\"\n\t\t}\n\t},\n\t\"meta\": {\n\t\t\"name\": \"demo应用\",\n\t\t\"git_group\": \"appGroup\",\n\t\t\"project_name\": \"app_demo\",\n\t\t\"description\": \"这是一个测试应用\",\n\t\t\"spma\": \"spa23d\",\n\t\t\"creator\": \"月飞\"\n\t}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alifd/next\": \"1.19.18\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>demo应用</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'i18n-jwg27yo4': '你好',\n    'i18n-jwg27yo3': '中国',\n  },\n  'en-US': {\n    'i18n-jwg27yo4': 'Hello',\n    'i18n-jwg27yo3': 'China',\n  },\n};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Form, Input, NumberPicker, Select, Button } from '@alifd/next';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter' };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidMount() {\n    console.log('componentDidMount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}>\n        <Form\n          labelCol={__$$eval(() => this.state.colNum)}\n          style={{}}\n          ref={this._refsManager.linkRef('testForm')}\n        >\n          <Form.Item\n            label={__$$eval(() => this.i18n('i18n-jwg27yo4'))}\n            name=\"name\"\n            initValue=\"李雷\"\n          >\n            <Input placeholder=\"请输入\" size=\"medium\" style={{ width: 320 }} />\n          </Form.Item>\n          <Form.Item label=\"年龄：\" name=\"age\" initValue=\"22\">\n            <NumberPicker size=\"medium\" type=\"normal\" />\n          </Form.Item>\n          <Form.Item label=\"职业：\" name=\"profession\">\n            <Select\n              dataSource={[\n                { label: '教师', value: 't' },\n                { label: '医生', value: 'd' },\n                { label: '歌手', value: 's' },\n              ]}\n            />\n          </Form.Item>\n          <div style={{ textAlign: 'center' }}>\n            <Button.Group>\n              <Button\n                type=\"primary\"\n                style={{ margin: '0 5px 0 5px' }}\n                htmlType=\"submit\"\n              >\n                提交\n              </Button>\n              <Button\n                type=\"normal\"\n                style={{ margin: '0 5px 0 5px' }}\n                htmlType=\"reset\"\n              >\n                重置\n              </Button>\n            </Button.Group>\n          </div>\n        </Form>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '/',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2/schema.json5",
    "content": "{\n\t\"version\": \"1.0.0\",\n\t\"componentsMap\": [\n\t\t{\n\t\t\t\"componentName\": \"Button\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\",\n\t\t\t\"subName\": \"Group\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Input\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Input\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\",\n\t\t\t\"subName\": \"Item\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"NumberPicker\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Select\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Select\"\n\t\t}\n\t],\n\t\"componentsTree\": [\n\t\t{\n\t\t\t\"componentName\": \"Page\",\n\t\t\t\"id\": \"node$1\",\n\t\t\t\"meta\": {\n\t\t\t\t\"title\": \"测试\",\n\t\t\t\t\"router\": \"/\"\n\t\t\t},\n\t\t\t\"props\": {\n\t\t\t\t\"ref\": \"outterView\",\n\t\t\t\t\"autoLoading\": true\n\t\t\t},\n\t\t\t\"fileName\": \"test\",\n\t\t\t\"state\": {\n\t\t\t\t\"text\": \"outter\"\n\t\t\t},\n\t\t\t\"lifeCycles\": {\n\t\t\t\t\"componentDidMount\": {\n\t\t\t\t\t\"type\": \"JSFunction\",\n\t\t\t\t\t\"value\": \"function() { console.log('componentDidMount'); }\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"componentName\": \"Form\",\n\t\t\t\t\t\"id\": \"node$2\",\n\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\"labelCol\": {\n\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\"value\": \"this.state.colNum\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"style\": {},\n\t\t\t\t\t\t\"ref\": \"testForm\"\n\t\t\t\t\t},\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$3\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": {\n\t\t\t\t\t\t\t\t\ttype: 'JSExpression',\n\t\t\t\t\t\t\t\t\tvalue: 'this.i18n(\"i18n-jwg27yo4\")',\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\t\"initValue\": \"李雷\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Input\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$4\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"placeholder\": \"请输入\",\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\"width\": 320\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$5\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"年龄：\",\n\t\t\t\t\t\t\t\t\"name\": \"age\",\n\t\t\t\t\t\t\t\t\"initValue\": \"22\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$6\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$7\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"职业：\",\n\t\t\t\t\t\t\t\t\"name\": \"profession\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Select\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$8\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"dataSource\": [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"教师\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"t\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"医生\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"d\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"歌手\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"s\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Div\",\n\t\t\t\t\t\t\t\"id\": \"node$9\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\"textAlign\": \"center\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$a\",\n\t\t\t\t\t\t\t\t\t\"props\": {},\n\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$b\",\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"primary\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"htmlType\": \"submit\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\"提交\"\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$d\",\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"htmlType\": \"reset\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\"重置\"\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"constants\": {\n\t\t\"ENV\": \"prod\",\n\t\t\"DOMAIN\": \"xxx.xxx.com\"\n\t},\n\t\"i18n\": {\n\t\t\"zh-CN\": {\n\t\t\t\"i18n-jwg27yo4\": \"你好\",\n\t\t\t\"i18n-jwg27yo3\": \"中国\"\n\t\t},\n\t\t\"en-US\": {\n\t\t\t\"i18n-jwg27yo4\": \"Hello\",\n\t\t\t\"i18n-jwg27yo3\": \"China\"\n\t\t}\n\t},\n\t\"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n\t\"config\": {\n\t\t\"sdkVersion\": \"1.0.3\",\n\t\t\"historyMode\": \"hash\",\n\t\t\"targetRootID\": \"J_Container\",\n\t\t\"layout\": {\n\t\t\t\"componentName\": \"BasicLayout\",\n\t\t\t\"props\": {\n\t\t\t\t\"logo\": \"...\",\n\t\t\t\t\"name\": \"测试网站\"\n\t\t\t}\n\t\t},\n\t\t\"theme\": {\n\t\t\t\"package\": \"@alife/theme-fusion\",\n\t\t\t\"version\": \"^0.1.0\",\n\t\t\t\"primary\": \"#ff9966\"\n\t\t}\n\t},\n\t\"meta\": {\n\t\t\"name\": \"demo应用\",\n\t\t\"git_group\": \"appGroup\",\n\t\t\"project_name\": \"app_demo\",\n\t\t\"description\": \"这是一个测试应用\",\n\t\t\"spma\": \"spa23d\",\n\t\t\"creator\": \"月飞\"\n\t}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"@alilc/b6-page\": \"^0.1.0\",\n    \"@alilc/b6-text\": \"^0.1.0\",\n    \"@alilc/b6-compact-legao-builtin\": \"1.x\",\n    \"antd\": \"3.x\",\n    \"@alilc/b6-util-mocks\": \"1.x\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>jinyuan-test2</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Page } from '@alilc/b6-page';\n\nimport { Text } from '@alilc/b6-text';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Aaaa$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(window.location.search),\n    },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'urlParams',\n          type: 'urlParams',\n          description: 'URL参数',\n          options: function () {\n            return {\n              uri: '',\n            };\n          }.bind(_this),\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div title=\"\" backgroundColor=\"#fff\" textColor=\"#333\" style={{}}>\n        <Text\n          content=\"欢迎使用 BuildSuccess！sadsad\"\n          style={{}}\n          fieldId=\"text_kp6ci11t\"\n        />\n      </div>\n    );\n  }\n}\n\nexport default Aaaa$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/routes.js",
    "content": "import Aaaa from '@/pages/Aaaa';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '/aaaa',\n        component: Aaaa,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/utils.js",
    "content": "import legaoBuiltin from '@alilc/b6-compact-legao-builtin';\n\nimport { message, Modal as modal } from 'antd';\n\nimport { mocks } from '@alilc/b6-util-mocks';\n\nimport { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {\n  legaoBuiltin,\n\n  message,\n\n  mocks,\n\n  modal,\n};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/b6-page',\n      version: '^0.1.0',\n      componentName: 'Page',\n      destructuring: true,\n      exportName: 'Page',\n    },\n    {\n      package: '@alilc/b6-text',\n      version: '^0.1.0',\n      componentName: 'Text',\n      destructuring: true,\n      exportName: 'Text',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_ockp6ci0hm1',\n      props: {\n        title: '',\n        backgroundColor: '#fff',\n        textColor: '#333',\n        style: {},\n      },\n      fileName: 'aaaa',\n      dataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n            description: 'URL参数',\n            options: {\n              uri: '',\n            },\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Text',\n          id: 'node_ockp6ci0hm2',\n          props: {\n            content: '欢迎使用 BuildSuccess！sadsad',\n            style: {},\n            fieldId: 'text_kp6ci11t',\n          },\n        },\n      ],\n      meta: {\n        router: '/aaaa',\n      },\n      methodsModule: {\n        type: 'JSModule',\n        compiled: '\"use strict\";\\n\\nObject.defineProperty(exports, \"__esModule\", {\\n  value: true\\n});\\nexports.helloPage = helloPage;\\n\\n/**\\n * Private, and can be re-used functions\\n * Actions panel help documentation：\\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\\n */\\nfunction printLog(obj) {\\n  console.info(obj);\\n}\\n/**\\n * page function\\n */\\n\\n\\nfunction helloPage() {\\n  console.log(\\'hello page\\');\\n}',\n        source: \"/**\\n * Private, and can be re-used functions\\n * Actions panel help documentation：\\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\\n */\\nfunction printLog(obj) {\\n  console.info(obj);\\n}\\n\\n/**\\n * page function\\n */\\nexport function helloPage() {\\n  console.log('hello page');\\n}\",\n      },\n    },\n  ],\n  i18n: {},\n  utils: [\n    {\n      name: 'legaoBuiltin',\n      type: 'npm',\n      content: {\n        exportName: 'legaoBuiltin',\n        package: '@alilc/b6-compact-legao-builtin',\n        version: '1.x',\n      },\n    },\n    {\n      name: 'message',\n      type: 'npm',\n      content: {\n        package: 'antd',\n        version: '3.x',\n        destructuring: true,\n        exportName: 'message',\n      },\n    },\n    {\n      name: 'mocks',\n      type: 'npm',\n      content: {\n        package: '@alilc/b6-util-mocks',\n        version: '1.x',\n        exportName: 'mocks',\n        destructuring: true,\n      },\n    },\n    {\n      name: 'modal',\n      type: 'npm',\n      content: {\n        package: 'antd',\n        version: '3.x',\n        destructuring: true,\n        exportName: 'Modal',\n      },\n    },\n  ],\n  constants: {},\n  dataSource: {\n    list: [],\n  },\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'root',\n    miniAppBuildType: 'runtime',\n  },\n  meta: {\n    name: 'jinyuan-test2',\n    git_group: 'b6',\n    project_name: 'jinyuan-test2',\n    description: '瑾源测试',\n    spma: 'spmademo',\n    creator: '张三',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alifd/next\": \"1.19.18\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>demo应用</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {\n  'zh-CN': {\n    'i18n-jwg27yo4': '你好',\n    'i18n-jwg27yo3': '中国',\n  },\n  'en-US': {\n    'i18n-jwg27yo4': 'Hello',\n    'i18n-jwg27yo3': 'China',\n  },\n};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport Super, {\n  Button,\n  Input as CustomInput,\n  Form,\n  NumberPicker,\n  Select,\n  SearchTable as SearchTableExport,\n} from '@alifd/next';\n\nimport SuperOther from '@alifd/next';\n\nimport '@alifd/next/lib/super/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/search-table/style';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst SuperSub = Super.Sub;\n\nconst SelectOption = Select.Option;\n\nconst SearchTable = SearchTableExport.default;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  componentDidMount() {}\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div>\n        <Super title={__$$eval(() => this.state.title)} />\n        <SuperSub />\n        <SuperOther />\n        <Button />\n        <Button.Group />\n        <CustomInput />\n        <Form.Item />\n        <NumberPicker />\n        <SelectOption />\n        <SearchTable />\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '/',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo3/schema.json5",
    "content": "{\n\t\"version\": \"1.0.0\",\n\t\"componentsMap\": [\n\t\t{\n\t\t\t\"componentName\": \"Super\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": false,\n\t\t\t\"exportName\": \"Super\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SuperOther\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": false,\n\t\t\t\"exportName\": \"Super\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SuperSub\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": false,\n\t\t\t\"exportName\": \"Super\",\n\t\t\t\"subName\": \"Sub\",\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SearchTable\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"SearchTable\",\n\t\t\t\"subName\": \"default\",\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\",\n\t\t\t\"subName\": \"Group\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"CustomInput\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Input\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\",\n\t\t\t\"subName\": \"Item\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"NumberPicker\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"SelectOption\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Select\",\n\t\t\t\"subName\": \"Option\"\n\t\t}\n\t],\n\t\"componentsTree\": [\n\t\t{\n\t\t\t\"componentName\": \"Page\",\n\t\t\t\"id\": \"node$1\",\n\t\t\t\"meta\": {\n\t\t\t\t\"title\": \"测试\",\n\t\t\t\t\"router\": \"/\"\n\t\t\t},\n\t\t\t\"fileName\": \"test\",\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"componentName\": \"Super\",\n\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\"title\": {\n\t\t\t\t\t\t\t\"type\":\"variable\",\n\t\t\t\t\t\t\t\"value\":\"标题\",\n\t\t\t\t\t\t\t\"variable\":\"this.state.title\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ \"componentName\": \"SuperSub\" },\n\t\t\t\t{ \"componentName\": \"SuperOther\" },\n\t\t\t\t{ \"componentName\": \"Button\" },\n\t\t\t\t{ \"componentName\": \"Button.Group\" },\n\t\t\t\t{ \"componentName\": \"CustomInput\" },\n\t\t\t\t{ \"componentName\": \"Form.Item\" },\n\t\t\t\t{ \"componentName\": \"NumberPicker\" },\n\t\t\t\t{ \"componentName\": \"SelectOption\" },\n\t\t\t\t{ \"componentName\": \"SearchTable\" },\n\t\t\t]\n\t\t}\n\t],\n\t\"constants\": {\n\t\t\"ENV\": \"prod\",\n\t\t\"DOMAIN\": \"xxx.xxx.com\"\n\t},\n\t\"i18n\": {\n\t\t\"zh-CN\": {\n\t\t\t\"i18n-jwg27yo4\": \"你好\",\n\t\t\t\"i18n-jwg27yo3\": \"中国\"\n\t\t},\n\t\t\"en-US\": {\n\t\t\t\"i18n-jwg27yo4\": \"Hello\",\n\t\t\t\"i18n-jwg27yo3\": \"China\"\n\t\t}\n\t},\n\t\"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n\t\"config\": {\n\t\t\"sdkVersion\": \"1.0.3\",\n\t\t\"historyMode\": \"hash\",\n\t\t\"targetRootID\": \"J_Container\",\n\t\t\"layout\": {\n\t\t\t\"componentName\": \"BasicLayout\",\n\t\t\t\"props\": {\n\t\t\t\t\"logo\": \"...\",\n\t\t\t\t\"name\": \"测试网站\"\n\t\t\t}\n\t\t},\n\t\t\"theme\": {\n\t\t\t\"package\": \"@alife/theme-fusion\",\n\t\t\t\"version\": \"^0.1.0\",\n\t\t\t\"primary\": \"#ff9966\"\n\t\t}\n\t},\n\t\"meta\": {\n\t\t\"name\": \"demo应用\",\n\t\t\"git_group\": \"appGroup\",\n\t\t\"project_name\": \"app_demo\",\n\t\t\"description\": \"这是一个测试应用\",\n\t\t\"spma\": \"spa23d\",\n\t\t\"creator\": \"月飞\"\n\t}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-fetch-handler\": \"^1.0.0\",\n    \"@alife/container\": \"^1.0.0\",\n    \"@alife/mc-assets-1935\": \"0.1.9\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>Ice App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n  Text as NextText,\n} from '@alife/container/lib/index.js';\n\nimport { AliSearchTable as AliSearchTableExport } from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst NextBlockCell = NextBlock.Cell;\n\nconst AliSearchTable = AliSearchTableExport.default;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: { fetch: __$$createFetchRequestHandler() },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter', isShowDialog: false };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          type: 'fetch',\n          isInit: function () {\n            return true;\n          }.bind(_this),\n          options: function () {\n            return {\n              params: {},\n              method: 'GET',\n              isCors: true,\n              timeout: 5000,\n              headers: {},\n              uri: 'https://mocks.xxx.com/mock/jjpin/user/list',\n            };\n          }.bind(_this),\n          id: 'users',\n        },\n      ],\n    };\n  }\n\n  componentWillUnmount() {\n    console.log('will umount');\n  }\n\n  componentDidUpdate(prevProps, prevState, snapshot) {\n    console.log(this.state);\n  }\n\n  testFunc() {\n    console.log('test func');\n  }\n\n  onClick() {\n    this.setState({\n      isShowDialog: true,\n    });\n  }\n\n  closeDialog() {\n    this.setState({\n      isShowDialog: false,\n    });\n  }\n\n  onSearch(values) {\n    console.log('search form:', values);\n    console.log(this.dataSourceMap);\n    this.dataSourceMap['users'].load(values);\n  }\n\n  onClear() {\n    console.log('form reset');\n    this.setState({\n      isShowDialog: true,\n    });\n  }\n\n  onPageChange(page, pageSize) {\n    console.log(`page: ${page}, pageSize: ${pageSize}`);\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n\n    console.log('did mount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <NextPage\n          columns={12}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={\n            <NextP\n              wrap={true}\n              type=\"body2\"\n              verAlign=\"middle\"\n              textSpacing={true}\n              align=\"left\"\n              flex={true}\n            >\n              <NextText type=\"h5\">员工列表</NextText>\n            </NextP>\n          }\n          headerTest={[]}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns=\"1fr\"\n          >\n            <NextBlockCell\n              title=\"\"\n              primaryKey=\"732\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              colSpan={1}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={true}\n                type=\"body2\"\n                textSpacing={true}\n                verAlign=\"center\"\n                align=\"flex-start\"\n                flex={true}\n              >\n                <AliSearchTable\n                  dataSource={__$$eval(() => this.state.users.data)}\n                  rowKey=\"workid\"\n                  columns={[\n                    { title: '花名', dataIndex: 'cname' },\n                    { title: 'user_id', dataIndex: 'workid' },\n                    { title: '部门', dataIndex: 'dep' },\n                  ]}\n                  searchItems={[\n                    { label: '姓名', name: 'cname' },\n                    { label: '部门', name: 'dep' },\n                  ]}\n                  onSearch={function () {\n                    return this.onSearch.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                  onClear={function () {\n                    return this.onClear.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                  pagination={{\n                    defaultPageSize: '',\n                    onPageChange: function () {\n                      return this.onPageChange.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this),\n                    showSizeChanger: true,\n                  }}\n                />\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={1}\n          >\n            <NextBlockCell\n              title=\"\"\n              primaryKey=\"472\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              colSpan={1}\n              rowSpan={1}\n            />\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo4/schema.json5",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.9\",\n      \"exportName\": \"AliSearchTable\",\n      \"main\": \"build/lowcode/index.js\",\n      \"subName\": \"default\",\n      \"destructuring\": true,\n      \"componentName\": \"AliSearchTable\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextP\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"Cell\",\n      \"componentName\": \"NextBlockCell\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlock\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Text\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextText\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"^1.0.0\",\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextPage\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"style\": {\n          \"height\": \"100%\"\n        }\n      },\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": [\n          {\n            \"type\": \"fetch\",\n            \"isInit\": true,\n            \"options\": {\n              \"params\": {},\n              \"method\": \"GET\",\n              \"isCors\": true,\n              \"timeout\": 5000,\n              \"headers\": {},\n              \"uri\": \"https://mocks.xxx.com/mock/jjpin/user/list\"\n            },\n            \"id\": \"users\"\n          }\n        ]\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}\",\n      \"lifeCycles\": {\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('did mount');\\n  }\"\n        },\n        \"componentWillUnmount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('will umount');\\n  }\"\n        },\n        \"componentDidUpdate\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(prevProps, prevState, snapshot) {\\n    console.log(this.state);\\n  }\"\n        }\n      },\n      \"methods\": {\n        \"testFunc\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('test func');\\n  }\"\n        },\n        \"onClick\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      isShowDialog: true\\n    })\\n  }\"\n        },\n        \"closeDialog\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    this.setState({\\n      isShowDialog: false\\n    })\\n  }\"\n        },\n        \"onSearch\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(values) {\\n    console.log('search form:', values)\\n    console.log(this.dataSourceMap);\\n    this.dataSourceMap['users'].load(values)\\n  }\"\n        },\n        \"onClear\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {\\n    console.log('form reset')\\n    this.setState({\\n      isShowDialog: true\\n    })\\n  }\"\n        },\n        \"onPageChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(page, pageSize) {\\n    console.log(`page: ${page}, pageSize: ${pageSize}`)\\n  }\"\n        }\n      },\n      \"state\": {\n        \"text\": \"outter\",\n        \"isShowDialog\": false\n      },\n      \"children\": [\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ockkgjwi8z1\",\n          \"props\": {\n            \"columns\": 12,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": {\n              \"type\": \"JSSlot\",\n              \"value\": [\n                {\n                  \"componentName\": \"NextP\",\n                  \"id\": \"node_ockkgjwi8zn\",\n                  \"props\": {\n                    \"wrap\": true,\n                    \"type\": \"body2\",\n                    \"verAlign\": \"middle\",\n                    \"textSpacing\": true,\n                    \"align\": \"left\",\n                    \"flex\": true\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextText\",\n                      \"id\": \"node_ockkgjwi8zo\",\n                      \"props\": {\n                        \"type\": \"h5\",\n                        \"children\": \"员工列表\"\n                      }\n                    }\n                  ]\n                }\n              ],\n              \"title\": \"header\"\n            },\n            \"headerTest\": {\n              \"type\": \"JSSlot\",\n              \"value\": [],\n              \"title\": \"header\"\n            },\n            \"headerProps\": {\n              \"background\": \"surface\"\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"footer\"\n            },\n            \"minHeight\": \"100vh\"\n          },\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockkgjwi8z2\",\n              \"props\": {\n                \"prefix\": \"next-\",\n                \"placeholderStyle\": {\n                  \"height\": \"100%\"\n                },\n                \"noPadding\": false,\n                \"noBorder\": false,\n                \"background\": \"surface\",\n                \"colSpan\": 12,\n                \"rowSpan\": 1,\n                \"childTotalColumns\": \"1fr\"\n              },\n              \"title\": \"分区\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockkgjwi8z3\",\n                  \"props\": {\n                    \"title\": \"\",\n                    \"primaryKey\": \"732\",\n                    \"prefix\": \"next-\",\n                    \"placeholderStyle\": {\n                      \"height\": \"100%\"\n                    },\n                    \"colSpan\": 1,\n                    \"rowSpan\": 1\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ockkgjwi8zu\",\n                      \"props\": {\n                        \"wrap\": true,\n                        \"type\": \"body2\",\n                        \"textSpacing\": true,\n                        \"verAlign\": \"center\",\n                        \"align\": \"flex-start\",\n                        \"flex\": true\n                      },\n                      \"children\": [\n                        {\n                          \"componentName\": \"AliSearchTable\",\n                          \"id\": \"node_ockkgjwi8zv\",\n                          \"props\": {\n                            \"dataSource\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.state.users.data\"\n                            },\n                            \"rowKey\": \"workid\",\n                            \"columns\": [\n                              {\n                                \"title\": \"花名\",\n                                \"dataIndex\": \"cname\"\n                              },\n                              {\n                                \"title\": \"user_id\",\n                                \"dataIndex\": \"workid\"\n                              },\n                              {\n                                \"title\": \"部门\",\n                                \"dataIndex\": \"dep\"\n                              }\n                            ],\n                            \"searchItems\": [\n                              {\n                                \"label\": \"姓名\",\n                                \"name\": \"cname\"\n                              },\n                              {\n                                \"label\": \"部门\",\n                                \"name\": \"dep\"\n                              }\n                            ],\n                            \"onSearch\": {\n                              \"type\": \"JSFunction\",\n                              \"value\": \"function(){ return this.onSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                            },\n                            \"onClear\": {\n                              \"type\": \"JSFunction\",\n                              \"value\": \"function(){ return this.onClear.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                            },\n                            \"pagination\": {\n                              \"defaultPageSize\": \"\",\n                              \"onPageChange\": {\n                                \"type\": \"JSFunction\",\n                                \"value\": \"function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                              },\n                              \"showSizeChanger\": true\n                            }\n                          }\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ockm4jxd6313\",\n          \"props\": {\n            \"columns\": 12,\n            \"headerDivider\": true,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"header\"\n            },\n            \"headerProps\": {\n              \"background\": \"surface\"\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"footer\"\n            },\n            \"minHeight\": \"100vh\"\n          },\n          \"title\": \"页面\",\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockm4jxd6314\",\n              \"props\": {\n                \"prefix\": \"next-\",\n                \"placeholderStyle\": {\n                  \"height\": \"100%\"\n                },\n                \"noPadding\": false,\n                \"noBorder\": false,\n                \"background\": \"surface\",\n                \"colSpan\": 12,\n                \"rowSpan\": 1,\n                \"childTotalColumns\": 1\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockm4jxd6315\",\n                  \"props\": {\n                    \"title\": \"\",\n                    \"primaryKey\": \"472\",\n                    \"prefix\": \"next-\",\n                    \"placeholderStyle\": {\n                      \"height\": \"100%\"\n                    },\n                    \"colSpan\": 1,\n                    \"rowSpan\": 1\n                  }\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alife/container\": \"0.3.7\",\n    \"@alilc/antd-lowcode\": \"0.5.4\",\n    \"@alife/mc-assets-1935\": \"0.1.16\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>Ice App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport {\n  Card,\n  Space,\n  Typography,\n  Select,\n  Button,\n  Modal,\n  Form,\n  InputNumber,\n  Input,\n} from '@alilc/antd-lowcode/dist/antd-lowcode.esm.js';\n\nimport { AliAutoSearchTable } from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst NextBlockCell = NextBlock.Cell;\n\nconst AliAutoSearchTableDefault = AliAutoSearchTable.default;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      name: 'nongzhou',\n      gateways: [],\n      selectedGateway: null,\n      records: [],\n      modalVisible: false,\n    };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentWillUnmount() {\n    /* ... */\n  }\n\n  componentDidUpdate() {\n    /* ... */\n  }\n\n  onChange() {\n    /* ... */\n  }\n\n  getActions() {\n    /* ... */\n  }\n\n  onCreateOrder() {\n    /* ... */\n  }\n\n  onCancelModal() {\n    /* ... */\n  }\n\n  onConfirmCreateOrder() {\n    /* ... */\n  }\n\n  componentDidMount() {}\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n          style={{ cursor: 'pointer' }}\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            layoutmode=\"O\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={12}\n          >\n            <NextBlockCell\n              title=\"\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              layoutmode=\"O\"\n              childTotalColumns={12}\n              isAutoContainer={true}\n              colSpan={12}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                full={true}\n                flex={true}\n              >\n                <Card title=\"\">\n                  <Space size={0} align=\"center\" direction=\"horizontal\">\n                    <Typography.Text>所在网关：</Typography.Text>\n                    <Select\n                      style={{\n                        marginTop: '16px',\n                        marginRight: '16px',\n                        marginBottom: '16px',\n                        marginLeft: '16px',\n                        width: '400px',\n                        display: 'inline-block',\n                      }}\n                      options={__$$eval(() => this.state.gateways)}\n                      mode=\"single\"\n                      defaultValue={['auto-edd-uniproxy']}\n                      labelInValue={true}\n                      showSearch={true}\n                      allowClear={false}\n                      placeholder=\"请选取网关\"\n                      showArrow={true}\n                      loading={false}\n                      tokenSeparators={[]}\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onChange',\n                            relatedEventName: 'onChange',\n                          },\n                        ],\n                        eventList: [\n                          { name: 'onBlur', disabled: false },\n                          { name: 'onChange', disabled: true },\n                          { name: 'onDeselect', disabled: false },\n                          { name: 'onFocus', disabled: false },\n                          { name: 'onInputKeyDown', disabled: false },\n                          { name: 'onMouseEnter', disabled: false },\n                          { name: 'onMouseLeave', disabled: false },\n                          { name: 'onPopupScroll', disabled: false },\n                          { name: 'onSearch', disabled: false },\n                          { name: 'onSelect', disabled: false },\n                          { name: 'onDropdownVisibleChange', disabled: false },\n                        ],\n                      }}\n                      onChange={function () {\n                        this.onChange.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this)}\n                    />\n                  </Space>\n                  <Button\n                    type=\"primary\"\n                    style={{\n                      display: 'block',\n                      marginTop: '20px',\n                      marginBottom: '20px',\n                    }}\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onClick',\n                          relatedEventName: 'onCreateOrder',\n                        },\n                      ],\n                      eventList: [{ name: 'onClick', disabled: true }],\n                    }}\n                    onClick={function () {\n                      this.onCreateOrder.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  >\n                    创建发布单\n                  </Button>\n                  <Modal\n                    title=\"创建发布单\"\n                    visible={__$$eval(() => this.state.modalVisible)}\n                    footer=\"\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onCancel',\n                          relatedEventName: 'onCancelModal',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onCancel', disabled: true },\n                        { name: 'onOk', disabled: false },\n                      ],\n                    }}\n                    onCancel={function () {\n                      this.onCancelModal.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    zIndex={2000}\n                  >\n                    <Form\n                      labelCol={{ span: 6 }}\n                      wrapperCol={{ span: 14 }}\n                      onFinish={function () {\n                        this.onConfirmCreateOrder.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this)}\n                      name=\"basic\"\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onFinish',\n                            relatedEventName: 'onConfirmCreateOrder',\n                          },\n                        ],\n                        eventList: [\n                          { name: 'onFinish', disabled: true },\n                          { name: 'onFinishFailed', disabled: false },\n                          { name: 'onFieldsChange', disabled: false },\n                          { name: 'onValuesChange', disabled: false },\n                        ],\n                      }}\n                    >\n                      <Form.Item label=\"发布批次\">\n                        <InputNumber value={3} min={1} />\n                      </Form.Item>\n                      <Form.Item label=\"批次间隔时间\">\n                        <InputNumber value={3} />\n                      </Form.Item>\n                      <Form.Item label=\"备注 \">\n                        <Input.TextArea rows={3} placeholder=\"请输入\" />\n                      </Form.Item>\n                      <Form.Item\n                        wrapperCol={{ offset: 6 }}\n                        style={{\n                          flexDirection: 'row',\n                          alignItems: 'flex-end',\n                          justifyContent: 'center',\n                          display: 'flex',\n                        }}\n                        labelAlign=\"right\"\n                      >\n                        <Button type=\"primary\" htmlType=\"submit\">\n                          提交\n                        </Button>\n                        <Button\n                          style={{ marginLeft: 20 }}\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onClick',\n                                relatedEventName: 'onCancelModal',\n                              },\n                            ],\n                            eventList: [{ name: 'onClick', disabled: true }],\n                          }}\n                          onClick={function () {\n                            this.onCancelModal.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                        >\n                          取消\n                        </Button>\n                      </Form.Item>\n                    </Form>\n                  </Modal>\n                  <AliAutoSearchTableDefault\n                    rowKey=\"key\"\n                    dataSource={__$$eval(() => this.state.records)}\n                    columns={[\n                      {\n                        title: '发布名称',\n                        dataIndex: 'order_name',\n                        key: 'name',\n                      },\n                      {\n                        title: '类型',\n                        dataIndex: 'order_type_desc',\n                        key: 'age',\n                      },\n                      {\n                        title: '发布状态',\n                        dataIndex: 'order_status_desc',\n                        key: 'address',\n                      },\n                      { title: '发布人', dataIndex: 'creator_name' },\n                      { title: '当前批次/总批次', dataIndex: 'cur_batch_no' },\n                      {\n                        title: '发布机器/总机器',\n                        dataIndex: 'pubblish_ip_finish_num',\n                      },\n                      { title: '发布时间', dataIndex: 'publish_id' },\n                    ]}\n                    actions={__$$eval(() => this.actions || [])}\n                    getActions={function () {\n                      return this.getActions.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  />\n                </Card>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo5/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Text',\n      componentName: 'Typography.Text',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Space',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Space',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'InputNumber',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'InputNumber',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'TextArea',\n      componentName: 'Input.TextArea',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.16',\n      exportName: 'AliAutoSearchTable',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoSearchTableDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.5.4',\n      exportName: 'Card',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Card',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        componentDidMount: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n      },\n      methods: {\n        onChange: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        getActions: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        onCreateOrder: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        onCancelModal: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n        onConfirmCreateOrder: {\n          type: 'JSFunction',\n          value: 'function() { /* ... */ }',\n        },\n      },\n      state: {\n        name: 'nongzhou',\n        gateways: [],\n        selectedGateway: null,\n        records: [],\n        modalVisible: false,\n      },\n      children: [\n        {\n          componentName: 'NextPage',\n          id: 'node_ocknqx3esma',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n            style: {\n              cursor: 'pointer',\n            },\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocknqx3esmb',\n              props: {\n                prefix: 'next-',\n                placeholderStyle: {\n                  height: '100%',\n                },\n                noPadding: false,\n                noBorder: false,\n                background: 'surface',\n                layoutmode: 'O',\n                colSpan: 12,\n                rowSpan: 1,\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocknqx3esmc',\n                  props: {\n                    title: '',\n                    prefix: 'next-',\n                    placeholderStyle: {\n                      height: '100%',\n                    },\n                    layoutmode: 'O',\n                    childTotalColumns: 12,\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocknqx3esm1j',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Card',\n                          id: 'node_ocknqx3esm1k',\n                          props: {\n                            title: '',\n                          },\n                          children: [\n                            {\n                              componentName: 'Space',\n                              id: 'node_ocknqx3esm1n',\n                              props: {\n                                size: 0,\n                                align: 'center',\n                                direction: 'horizontal',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Typography.Text',\n                                  id: 'node_ocknqx3esm1l',\n                                  props: {\n                                    children: '所在网关：',\n                                  },\n                                },\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ocknqx3esm1m',\n                                  props: {\n                                    style: {\n                                      marginTop: '16px',\n                                      marginRight: '16px',\n                                      marginBottom: '16px',\n                                      marginLeft: '16px',\n                                      width: '400px',\n                                      display: 'inline-block',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.gateways',\n                                    },\n                                    mode: 'single',\n                                    defaultValue: ['auto-edd-uniproxy'],\n                                    labelInValue: true,\n                                    showSearch: true,\n                                    allowClear: false,\n                                    placeholder: '请选取网关',\n                                    showArrow: true,\n                                    loading: false,\n                                    tokenSeparators: [],\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onChange',\n                                          relatedEventName: 'onChange',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onBlur',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onChange',\n                                          disabled: true,\n                                        },\n                                        {\n                                          name: 'onDeselect',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onFocus',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onInputKeyDown',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onMouseEnter',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onMouseLeave',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onPopupScroll',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onSearch',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onSelect',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onDropdownVisibleChange',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                    onChange: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Button',\n                              id: 'node_ockntwgdsn7',\n                              props: {\n                                type: 'primary',\n                                children: '创建发布单',\n                                style: {\n                                  display: 'block',\n                                  marginTop: '20px',\n                                  marginBottom: '20px',\n                                },\n                                __events: {\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'onCreateOrder',\n                                    },\n                                  ],\n                                  eventList: [\n                                    {\n                                      name: 'onClick',\n                                      disabled: true,\n                                    },\n                                  ],\n                                },\n                                onClick: {\n                                  type: 'JSFunction',\n                                  value: 'function(){this.onCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                              },\n                            },\n                            {\n                              componentName: 'Modal',\n                              id: 'node_ockntx4eo9p',\n                              props: {\n                                title: '创建发布单',\n                                visible: {\n                                  type: 'JSExpression',\n                                  value: 'this.state.modalVisible',\n                                },\n                                footer: '',\n                                __events: {\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onCancel',\n                                      relatedEventName: 'onCancelModal',\n                                    },\n                                  ],\n                                  eventList: [\n                                    {\n                                      name: 'onCancel',\n                                      disabled: true,\n                                    },\n                                    {\n                                      name: 'onOk',\n                                      disabled: false,\n                                    },\n                                  ],\n                                },\n                                onCancel: {\n                                  type: 'JSFunction',\n                                  value: 'function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                                zIndex: 2000,\n                              },\n                              hidden: true,\n                              children: [\n                                {\n                                  componentName: 'Form',\n                                  id: 'node_ockntx4eo9s',\n                                  props: {\n                                    labelCol: {\n                                      span: 6,\n                                    },\n                                    wrapperCol: {\n                                      span: 14,\n                                    },\n                                    onFinish: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onConfirmCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    name: 'basic',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onFinish',\n                                          relatedEventName: 'onConfirmCreateOrder',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onFinish',\n                                          disabled: true,\n                                        },\n                                        {\n                                          name: 'onFinishFailed',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onFieldsChange',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onValuesChange',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                  },\n                                  children: [\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo91k',\n                                      props: {\n                                        label: '发布批次',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'InputNumber',\n                                          id: 'node_ockntx4eo91l',\n                                          props: {\n                                            value: 3,\n                                            min: 1,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo91r',\n                                      props: {\n                                        label: '批次间隔时间',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'InputNumber',\n                                          id: 'node_ockntx4eo91s',\n                                          props: {\n                                            value: 3,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo91y',\n                                      props: {\n                                        label: '备注 ',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Input.TextArea',\n                                          id: 'node_ockntx4eo91z',\n                                          props: {\n                                            rows: 3,\n                                            placeholder: '请输入',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ockntx4eo9v',\n                                      props: {\n                                        wrapperCol: {\n                                          offset: 6,\n                                        },\n                                        style: {\n                                          flexDirection: 'row',\n                                          alignItems: 'flex-end',\n                                          justifyContent: 'center',\n                                          display: 'flex',\n                                        },\n                                        labelAlign: 'right',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ockntx4eo9w',\n                                          props: {\n                                            type: 'primary',\n                                            children: '提交',\n                                            htmlType: 'submit',\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ockntx4eo9x',\n                                          props: {\n                                            style: {\n                                              marginLeft: 20,\n                                            },\n                                            children: '取消',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'onCancelModal',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  ],\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'AliAutoSearchTableDefault',\n                              id: 'node_ocknqx3esm1q',\n                              props: {\n                                rowKey: 'key',\n                                dataSource: {\n                                  type: 'JSExpression',\n                                  value: 'this.state.records',\n                                },\n                                columns: [\n                                  {\n                                    title: '发布名称',\n                                    dataIndex: 'order_name',\n                                    key: 'name',\n                                  },\n                                  {\n                                    title: '类型',\n                                    dataIndex: 'order_type_desc',\n                                    key: 'age',\n                                  },\n                                  {\n                                    title: '发布状态',\n                                    dataIndex: 'order_status_desc',\n                                    key: 'address',\n                                  },\n                                  {\n                                    title: '发布人',\n                                    dataIndex: 'creator_name',\n                                  },\n                                  {\n                                    title: '当前批次/总批次',\n                                    dataIndex: 'cur_batch_no',\n                                  },\n                                  {\n                                    title: '发布机器/总机器',\n                                    dataIndex: 'pubblish_ip_finish_num',\n                                  },\n                                  {\n                                    title: '发布时间',\n                                    dataIndex: 'publish_id',\n                                  },\n                                ],\n                                actions: {\n                                  type: 'JSExpression',\n                                  value: 'this.actions || []',\n                                },\n                                getActions: {\n                                  type: 'JSFunction',\n                                  value: 'function(){ return this.getActions.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                              },\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-url-params-handler\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-fetch-handler\": \"^1.0.0\",\n    \"@alifd/next\": \"1.19.18\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>demo应用</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Form, Input, NumberPicker, Select, Button } from '@alifd/next';\n\nimport { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';\n\nimport { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport '@alifd/next/lib/form/style';\n\nimport '@alifd/next/lib/input/style';\n\nimport '@alifd/next/lib/number-picker/style';\n\nimport '@alifd/next/lib/select/style';\n\nimport '@alifd/next/lib/button/style';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: {\n      urlParams: __$$createUrlParamsRequestHandler(window.location.search),\n      fetch: __$$createFetchRequestHandler(),\n    },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = { text: 'outter' };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'urlParams',\n          type: 'urlParams',\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n          options: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'user',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n        {\n          id: 'orders',\n          type: 'fetch',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/orders',\n              isSync: true,\n            };\n          }.bind(_this),\n          dataHandler: function (response) {\n            if (!response.data.success) {\n              throw new Error(response.data.message);\n            }\n            return response.data.data.result;\n          },\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n      dataHandler: function (dataMap) {\n        console.info('All datasources loaded:', dataMap);\n      },\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n\n    console.log('componentDidMount');\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}>\n        <Form\n          labelCol={__$$eval(() => this.state.colNum)}\n          style={{}}\n          ref={this._refsManager.linkRef('testForm')}\n        >\n          <Form.Item label=\"姓名：\" name=\"name\" initValue=\"李雷\">\n            <Input placeholder=\"请输入\" size=\"medium\" style={{ width: 320 }} />\n          </Form.Item>\n          <Form.Item label=\"年龄：\" name=\"age\" initValue=\"22\">\n            <NumberPicker size=\"medium\" type=\"normal\" />\n          </Form.Item>\n          <Form.Item label=\"职业：\" name=\"profession\">\n            <Select\n              dataSource={[\n                { label: '教师', value: 't' },\n                { label: '医生', value: 'd' },\n                { label: '歌手', value: 's' },\n              ]}\n            />\n          </Form.Item>\n          <div style={{ textAlign: 'center' }}>\n            <Button.Group>\n              {__$$evalArray(() => ['a', 'b', 'c']).map((item, index) =>\n                ((__$$context) =>\n                  !!false && (\n                    <Button type=\"primary\" style={{ margin: '0 5px 0 5px' }}>\n                      {__$$eval(() => item)}\n                    </Button>\n                  ))(__$$createChildContext(__$$context, { item, index }))\n              )}\n            </Button.Group>\n          </div>\n        </Form>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '/',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Button',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Button',\n    },\n    {\n      componentName: 'Button.Group',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Button',\n      subName: 'Group',\n    },\n    {\n      componentName: 'Input',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Input',\n    },\n    {\n      componentName: 'Form',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Form',\n    },\n    {\n      componentName: 'Form.Item',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Form',\n      subName: 'Item',\n    },\n    {\n      componentName: 'NumberPicker',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'NumberPicker',\n    },\n    {\n      componentName: 'Select',\n      package: '@alifd/next',\n      version: '1.19.18',\n      destructuring: true,\n      exportName: 'Select',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node$1',\n      meta: {\n        title: '测试',\n        router: '/',\n      },\n      props: {\n        ref: 'outterView',\n        autoLoading: true,\n      },\n      fileName: 'test',\n      state: {\n        text: 'outter',\n      },\n      lifeCycles: {\n        componentDidMount: {\n          type: 'JSFunction',\n          value: \"function() { console.log('componentDidMount'); }\",\n        },\n      },\n      dataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/user\n          {\n            id: 'user',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data;\\n}',\n            },\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/orders\n          {\n            id: 'orders',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/orders',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function (response) {\\nif (!response.data.success){\\n    throw new Error(response.data.message);\\n  }\\n  return response.data.data.result;\\n}',\n            },\n          },\n        ],\n        dataHandler: {\n          type: 'JSFunction',\n          value: 'function (dataMap) {\\n  console.info(\"All datasources loaded:\", dataMap);\\n}',\n        },\n      },\n      children: [\n        {\n          componentName: 'Form',\n          id: 'node$2',\n          props: {\n            labelCol: {\n              type: 'JSExpression',\n              value: 'this.state.colNum',\n            },\n            style: {},\n            ref: 'testForm',\n          },\n          children: [\n            {\n              componentName: 'Form.Item',\n              id: 'node$3',\n              props: {\n                label: '姓名：',\n                name: 'name',\n                initValue: '李雷',\n              },\n              children: [\n                {\n                  componentName: 'Input',\n                  id: 'node$4',\n                  props: {\n                    placeholder: '请输入',\n                    size: 'medium',\n                    style: {\n                      width: 320,\n                    },\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node$5',\n              props: {\n                label: '年龄：',\n                name: 'age',\n                initValue: '22',\n              },\n              children: [\n                {\n                  componentName: 'NumberPicker',\n                  id: 'node$6',\n                  props: {\n                    size: 'medium',\n                    type: 'normal',\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node$7',\n              props: {\n                label: '职业：',\n                name: 'profession',\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node$8',\n                  props: {\n                    dataSource: [\n                      {\n                        label: '教师',\n                        value: 't',\n                      },\n                      {\n                        label: '医生',\n                        value: 'd',\n                      },\n                      {\n                        label: '歌手',\n                        value: 's',\n                      },\n                    ],\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Div',\n              id: 'node$9',\n              props: {\n                style: {\n                  textAlign: 'center',\n                },\n              },\n              children: [\n                {\n                  componentName: 'Button.Group',\n                  id: 'node$a',\n                  props: {},\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node$b',\n                      condition: false,\n                      loop: ['a', 'b', 'c'],\n                      props: {\n                        type: 'primary',\n                        style: {\n                          margin: '0 5px 0 5px',\n                        },\n                      },\n                      children: [\n                        {\n                          type: 'JSExpression',\n                          value: 'this.item',\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  constants: {\n    ENV: 'prod',\n    DOMAIN: 'xxx.xxx.com',\n  },\n  css: 'body {font-size: 12px;} .table { width: 100px;}',\n  config: {\n    sdkVersion: '1.0.3',\n    historyMode: 'hash',\n    targetRootID: 'J_Container',\n    layout: {\n      componentName: 'BasicLayout',\n      props: {\n        logo: '...',\n        name: '测试网站',\n      },\n    },\n    theme: {\n      package: '@alife/theme-fusion',\n      version: '^0.1.0',\n      primary: '#ff9966',\n    },\n  },\n  meta: {\n    name: 'demo应用',\n    git_group: 'appGroup',\n    project_name: 'app_demo',\n    description: '这是一个测试应用',\n    spma: 'spa23d',\n    creator: '月飞',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alilc/antd-lowcode\": \"0.8.0\",\n    \"@alife/container\": \"0.3.7\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>Ice App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Modal,\n  Steps,\n  Form,\n  Input,\n  Checkbox,\n  Select,\n  DatePicker,\n  InputNumber,\n  Button,\n} from '@alilc/antd-lowcode/dist/antd-lowcode.esm.js';\n\nimport {\n  Text as NextText,\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst NextBlockCell = NextBlock.Cell;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      books: [],\n      currentStep: 0,\n      isModifyDialogVisible: false,\n      isModifyStatus: false,\n      secondCommitText: '完成并提交',\n      thirdAuditText: '审核中',\n      thirdButtonText: '修改',\n      customerProjectInfo: {\n        id: null,\n        systemProjectName: null,\n        projectVersionTypeArray: null,\n        projectVersionType: null,\n        versionLine: 2,\n        expectedTime: null,\n        expectedNum: null,\n        projectModal: null,\n        displayWidth: null,\n        displayHeight: null,\n        displayInch: null,\n        displayDpi: null,\n        mainSoc: null,\n        cpuCoreNum: null,\n        instructions: null,\n        osVersion: null,\n        status: null,\n      },\n      versionLinesArray: [\n        { label: 'AmapAuto 485', value: 1 },\n        { label: 'AmapAuto 505', value: 2 },\n      ],\n      projectModalsArray: [\n        { label: '车机', value: 1 },\n        { label: '车镜', value: 2 },\n        { label: '记录仪', value: 3 },\n        { label: '其他', value: 4 },\n      ],\n      osVersionsArray: [\n        { label: '安卓5', value: 1 },\n        { label: '安卓6', value: 2 },\n        { label: '安卓7', value: 3 },\n        { label: '安卓8', value: 4 },\n        { label: '安卓9', value: 5 },\n        { label: '安卓10', value: 6 },\n      ],\n      instructionsArray: [\n        { label: 'ARM64-V8', value: 'ARM64-V8' },\n        { label: 'ARM32-V7', value: 'ARM32-V7' },\n        { label: 'X86', value: 'X86' },\n        { label: 'X64', value: 'X64' },\n      ],\n    };\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidUpdate(prevProps, prevState, snapshot) {}\n\n  componentWillUnmount() {}\n\n  __jp__init() {\n    /*...*/\n  }\n\n  __jp__initRouter() {\n    /*...*/\n  }\n\n  __jp__initDataSource() {\n    /*...*/\n  }\n\n  __jp__initEnv() {\n    /*...*/\n  }\n\n  __jp__initUtils() {\n    /*...*/\n  }\n\n  onFinishFirst() {\n    /*...*/\n  }\n\n  onClickPreSecond() {\n    /*...*/\n  }\n\n  onFinishSecond() {\n    /*...*/\n  }\n\n  onClickModifyThird() {\n    /*...*/\n  }\n\n  onOkModifyDialogThird() {\n    //第三步 修改 对话框 确定\n\n    this.setState({\n      currentStep: 0,\n      isModifyDialogVisible: false,\n    });\n  }\n\n  onCancelModifyDialogThird() {\n    //第三步 修改 对话框 取消\n\n    this.setState({\n      isModifyDialogVisible: false,\n    });\n  }\n\n  onFinishFailed() {}\n\n  onClickPreThird() {\n    // 第三步 上一步\n    this.setState({\n      currentStep: 1,\n    });\n  }\n\n  onClickFirstBack() {\n    // 第一步 返回按钮\n    this.$router.push('/myProjectList');\n  }\n\n  onClickSecondBack() {\n    // 第二步 返回按钮\n    this.$router.push('/myProjectList');\n  }\n\n  onClickThirdBack() {\n    // 第三步 返回按钮\n    this.$router.push('/myProjectList');\n  }\n\n  onValuesChange(_, values) {\n    this.setState({\n      customerProjectInfo: {\n        ...this.state.customerProjectInfo,\n        ...values,\n      },\n    });\n  }\n\n  componentDidMount() {}\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <Modal\n          title=\"是否修改\"\n          visible={__$$eval(() => this.state.isModifyDialogVisible)}\n          okText=\"确认\"\n          okType=\"\"\n          forceRender={false}\n          cancelText=\"取消\"\n          zIndex={2000}\n          destroyOnClose={false}\n          confirmLoading={false}\n          __events={{\n            eventDataList: [\n              {\n                type: 'componentEvent',\n                name: 'onOk',\n                relatedEventName: 'onOkModifyDialogThird',\n              },\n              {\n                type: 'componentEvent',\n                name: 'onCancel',\n                relatedEventName: 'onCancelModifyDialogThird',\n              },\n            ],\n            eventList: [\n              { name: 'onCancel', disabled: true },\n              { name: 'onOk', disabled: true },\n            ],\n          }}\n          onOk={function () {\n            this.onOkModifyDialogThird.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n          onCancel={function () {\n            this.onCancelModifyDialogThird.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n        >\n          <NextText\n            type=\"inherit\"\n            style={{\n              fontStyle: 'normal',\n              textAlign: 'left',\n              display: 'block',\n              fontFamily: 'arial, helvetica, microsoft yahei',\n              fontWeight: 'normal',\n            }}\n          >\n            修改将撤回此前填写的信息\n          </NextText>\n        </Modal>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n          style={{}}\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            layoutmode=\"O\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={12}\n          >\n            <NextBlockCell\n              title=\"\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              layoutmode=\"O\"\n              childTotalColumns={12}\n              isAutoContainer={true}\n              colSpan={12}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n                style={{ marginBottom: '24px' }}\n              >\n                <Steps current={__$$eval(() => this.state.currentStep)}>\n                  <Steps.Step title=\"版本申请\" description=\"\" />\n                  <Steps.Step title=\"机器配置\" subTitle=\"\" description=\"\" />\n                  <Steps.Step title=\"项目审批\" description=\"\" />\n                </Steps>\n              </NextP>\n              {!!__$$eval(() => this.state.currentStep === 0) && (\n                <NextP\n                  wrap={false}\n                  type=\"body2\"\n                  verAlign=\"middle\"\n                  textSpacing={true}\n                  align=\"left\"\n                  full={true}\n                  flex={true}\n                  style={{ display: 'flex', justifyContent: 'center' }}\n                >\n                  <Form\n                    labelCol={{ span: 10 }}\n                    wrapperCol={{ span: 10 }}\n                    onFinish={function () {\n                      this.onFinishFirst.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    name=\"basic\"\n                    style={{\n                      display: 'flex',\n                      flexDirection: 'column',\n                      width: '600px',\n                      justifyContent: 'center',\n                    }}\n                    layout=\"vertical\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onFinish',\n                          relatedEventName: 'onFinishFirst',\n                        },\n                        {\n                          type: 'componentEvent',\n                          name: 'onValuesChange',\n                          relatedEventName: 'onValuesChange',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onFinish', disabled: true },\n                        { name: 'onFinishFailed', disabled: false },\n                        { name: 'onFieldsChange', disabled: false },\n                        { name: 'onValuesChange', disabled: true },\n                      ],\n                    }}\n                    initialValues={__$$eval(\n                      () => this.state.customerProjectInfo\n                    )}\n                    onValuesChange={function () {\n                      this.onValuesChange.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  >\n                    {!!false && (\n                      <Form.Item\n                        label=\"\"\n                        style={{ width: '600px' }}\n                        colon={false}\n                        name=\"id\"\n                      >\n                        <Input\n                          placeholder=\"\"\n                          style={{ width: '600px' }}\n                          bordered={false}\n                          disabled={true}\n                        />\n                      </Form.Item>\n                    )}\n                    <Form.Item\n                      label=\"版本类型选择\"\n                      name=\"projectVersionTypeArray\"\n                      initialValue=\"\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ flexDirection: 'column', width: '600px' }}\n                      requiredobj={{\n                        required: true,\n                        message: '请选择版本类型',\n                      }}\n                    >\n                      <Checkbox.Group\n                        options={[\n                          { label: '基础版本', value: '3' },\n                          { label: 'AR导航', value: '1' },\n                          { label: '货车导航', value: '2' },\n                          { label: 'UI定制', value: '4', disabled: false },\n                        ]}\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"版本线选择\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ width: '600px' }}\n                      name=\"versionLine\"\n                      requiredobj={{ required: true, message: '请选择版本线' }}\n                      extra=\"\"\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.versionLinesArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        placeholder=\"请选择版本线\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"项目名称\"\n                      colon={false}\n                      required={true}\n                      style={{ display: 'flex' }}\n                      labelAlign=\"left\"\n                      extra=\"\"\n                      name=\"systemProjectName\"\n                      requiredobj={{\n                        required: true,\n                        message: '请按格式填写项目名称',\n                      }}\n                      typeobj={{\n                        type: 'string',\n                        message:\n                          '请输入项目名称，格式：公司简称-产品名称-版本类型',\n                      }}\n                      lenobj={{\n                        max: 100,\n                        message: '项目名称不能超过100个字符',\n                      }}\n                    >\n                      <Input\n                        placeholder=\"公司简称-产品名称-版本类型\"\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"预期交付时间\"\n                      style={{ width: '600px' }}\n                      colon={false}\n                      required={true}\n                      name=\"expectedTime\"\n                      labelAlign=\"left\"\n                      requiredobj={{\n                        required: true,\n                        message: '请填写预期交付时间',\n                      }}\n                    >\n                      <DatePicker\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"预期出货量\"\n                      style={{ width: '600px' }}\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请填写预期出货量',\n                      }}\n                      name=\"expectedNum\"\n                      labelAlign=\"left\"\n                      colon={false}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"单位（台）使用该版本的机器数量+预计出货量，请如实填写\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                        size=\"middle\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      wrapperCol={{ offset: '' }}\n                      style={{\n                        flexDirection: 'row',\n                        alignItems: 'baseline',\n                        justifyContent: 'space-between',\n                        width: '600px',\n                        display: 'block',\n                      }}\n                      labelAlign=\"left\"\n                      colon={false}\n                    >\n                      <Button\n                        style={{ margin: '0px' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickFirstBack',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickFirstBack.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        返回\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{\n                          boxShadow: 'rgba(31, 56, 88, 0.2) 0px 0px 0px 0px',\n                          float: 'right',\n                        }}\n                        __events={{\n                          eventDataList: [],\n                          eventList: [{ name: 'onClick', disabled: false }],\n                        }}\n                      >\n                        下一步\n                      </Button>\n                    </Form.Item>\n                  </Form>\n                </NextP>\n              )}\n              {!!__$$eval(() => this.state.currentStep === 1) && (\n                <NextP\n                  wrap={false}\n                  type=\"body2\"\n                  verAlign=\"middle\"\n                  textSpacing={true}\n                  align=\"left\"\n                  full={true}\n                  flex={true}\n                  style={{ display: 'flex', justifyContent: 'center' }}\n                >\n                  <Form\n                    labelCol={{ span: 10 }}\n                    wrapperCol={{ span: 10 }}\n                    onFinish={function () {\n                      this.onFinishSecond.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    name=\"basic\"\n                    style={{\n                      display: 'flex',\n                      flexDirection: 'column',\n                      width: '600px',\n                      justifyContent: 'center',\n                      height: '800px',\n                    }}\n                    layout=\"vertical\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onFinish',\n                          relatedEventName: 'onFinishSecond',\n                        },\n                        {\n                          type: 'componentEvent',\n                          name: 'onValuesChange',\n                          relatedEventName: 'onValuesChange',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onFinish', disabled: true },\n                        { name: 'onFinishFailed', disabled: false },\n                        { name: 'onFieldsChange', disabled: false },\n                        { name: 'onValuesChange', disabled: true },\n                      ],\n                    }}\n                    initialValues={__$$eval(\n                      () => this.state.customerProjectInfo\n                    )}\n                    onValuesChange={function () {\n                      this.onValuesChange.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                  >\n                    <Form.Item\n                      label=\"设备类型选择\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ width: '600px' }}\n                      name=\"projectModal\"\n                      requiredobj={{\n                        required: true,\n                        message: '请选择设备类型',\n                      }}\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.projectModalsArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        placeholder=\"请选择设备类型\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕分辨率宽\"\n                      style={{ width: '600px' }}\n                      name=\"displayWidth\"\n                      colon={false}\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入屏幕分辨率宽',\n                      }}\n                      labelAlign=\"left\"\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"例如1280\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕分辨率高\"\n                      style={{ width: '600px' }}\n                      labelAlign=\"left\"\n                      colon={false}\n                      name=\"displayHeight\"\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入屏幕分辨率高',\n                      }}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"例如720\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕尺寸（inch）\"\n                      style={{ width: '600px' }}\n                      name=\"displayInch\"\n                      labelAlign=\"left\"\n                      required={true}\n                      colon={false}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入屏幕尺寸',\n                      }}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"请输入尺寸\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"屏幕DPI\"\n                      style={{ width: '600px' }}\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={false}\n                      name=\"displayDpi\"\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"UI定制项目必填\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"芯片名称\"\n                      colon={false}\n                      required={true}\n                      style={{ display: 'flex' }}\n                      labelAlign=\"left\"\n                      extra=\"\"\n                      name=\"mainSoc\"\n                      requiredobj={{\n                        required: true,\n                        message: '请输入芯片名称',\n                      }}\n                      lenobj={{ max: 50, message: '芯片名称不能超过50个字符' }}\n                    >\n                      <Input\n                        placeholder=\"请输入芯片名称\"\n                        style={{ width: '600px' }}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"芯片核数\"\n                      style={{ width: '600px' }}\n                      required={true}\n                      requiredobj={{\n                        required: true,\n                        message: '请输入芯片核数',\n                      }}\n                      name=\"cpuCoreNum\"\n                      labelAlign=\"left\"\n                      colon={false}\n                    >\n                      <InputNumber\n                        value={3}\n                        style={{ width: '600px' }}\n                        placeholder=\"请输入芯片核数\"\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        defaultValue=\"\"\n                        min={0}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"指令集\"\n                      style={{ width: '600px' }}\n                      required={true}\n                      requiredobj={{ required: true, message: '请选择指令集' }}\n                      name=\"instructions\"\n                      colon={false}\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.instructionsArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      label=\"系统版本\"\n                      labelAlign=\"left\"\n                      colon={false}\n                      required={true}\n                      style={{ width: '600px' }}\n                      name=\"osVersion\"\n                      requiredobj={{\n                        required: true,\n                        message: '请选择系统版本',\n                      }}\n                    >\n                      <Select\n                        style={{ width: '600px' }}\n                        options={__$$eval(() => this.state.osVersionsArray)}\n                        disabled={__$$eval(\n                          () =>\n                            this.state.customerProjectInfo.id > 0 &&\n                            !this.state.isModifyStatus\n                        )}\n                        placeholder=\"请选择系统版本\"\n                      />\n                    </Form.Item>\n                    <Form.Item\n                      wrapperCol={{ offset: '' }}\n                      style={{\n                        flexDirection: 'row',\n                        width: '600px',\n                        display: 'flex',\n                      }}\n                    >\n                      <Button\n                        style={{ marginLeft: '0' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickSecondBack',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickSecondBack.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        返回\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{ float: 'right', marginLeft: '20px' }}\n                        loading={__$$eval(\n                          () =>\n                            this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT\n                        )}\n                      >\n                        {__$$eval(() => this.state.secondCommitText)}\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{ marginLeft: '0px', float: 'right' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickPreSecond',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickPreSecond.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        上一步\n                      </Button>\n                    </Form.Item>\n                  </Form>\n                </NextP>\n              )}\n              {!!__$$eval(() => this.state.currentStep === 2) && (\n                <NextP\n                  wrap={false}\n                  type=\"body2\"\n                  verAlign=\"middle\"\n                  textSpacing={true}\n                  align=\"left\"\n                  full={true}\n                  flex={true}\n                  style={{ display: 'flex', justifyContent: 'center' }}\n                >\n                  <Form\n                    labelCol={{ span: 10 }}\n                    wrapperCol={{ span: 10 }}\n                    onFinishFailed={function () {\n                      this.onFinishFailed.apply(\n                        this,\n                        Array.prototype.slice.call(arguments).concat([])\n                      );\n                    }.bind(this)}\n                    name=\"basic\"\n                    style={{\n                      display: 'flex',\n                      flexDirection: 'column',\n                      width: '600px',\n                      justifyContent: 'center',\n                    }}\n                    layout=\"vertical\"\n                    __events={{\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onFinishFailed',\n                          relatedEventName: 'onFinishFailed',\n                        },\n                      ],\n                      eventList: [\n                        { name: 'onFinish', disabled: false },\n                        { name: 'onFinishFailed', disabled: true },\n                        { name: 'onFieldsChange', disabled: false },\n                        { name: 'onValuesChange', disabled: false },\n                      ],\n                    }}\n                  >\n                    <Form.Item label=\"\">\n                      <Steps\n                        current={1}\n                        style={{\n                          width: '600px',\n                          display: 'flex',\n                          justifyContent: 'space-around',\n                          alignItems: 'center',\n                          height: '300px',\n                        }}\n                        labelPlacement=\"horizontal\"\n                        direction=\"vertical\"\n                      >\n                        <Steps.Step\n                          title=\"提交完成\"\n                          description=\"\"\n                          style={{ width: '200px' }}\n                        />\n                        <Steps.Step\n                          title={__$$eval(() => this.state.thirdAuditText)}\n                          subTitle=\"\"\n                          description=\"\"\n                          style={{ width: '200px' }}\n                        />\n                      </Steps>\n                    </Form.Item>\n                    <Form.Item\n                      wrapperCol={{ offset: '' }}\n                      style={{\n                        flexDirection: 'row',\n                        width: '600px',\n                        display: 'flex',\n                      }}\n                    >\n                      <Button\n                        style={{ marginLeft: '0' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickThirdBack',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickThirdBack.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        返回\n                      </Button>\n                      <Button\n                        type=\"primary\"\n                        htmlType=\"submit\"\n                        style={{ float: 'right', marginLeft: '20px' }}\n                        __events={{\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'onClickModifyThird',\n                            },\n                          ],\n                          eventList: [{ name: 'onClick', disabled: true }],\n                        }}\n                        onClick={function () {\n                          this.onClickModifyThird.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this)}\n                      >\n                        {__$$eval(() => this.state.thirdButtonText)}\n                      </Button>\n                      {!!__$$eval(\n                        () => this.state.customerProjectInfo.status > 2\n                      ) && (\n                        <Button\n                          type=\"primary\"\n                          htmlType=\"submit\"\n                          style={{ marginLeft: '0px', float: 'right' }}\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onClick',\n                                relatedEventName: 'onClickPreThird',\n                              },\n                            ],\n                            eventList: [{ name: 'onClick', disabled: true }],\n                          }}\n                          onClick={function () {\n                            this.onClickPreThird.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                        >\n                          上一步\n                        </Button>\n                      )}\n                    </Form.Item>\n                  </Form>\n                </NextP>\n              )}\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Text',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextText',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Steps',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Step',\n      componentName: 'Steps.Step',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Steps',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Steps',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Input',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Checkbox',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Group',\n      componentName: 'Checkbox.Group',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'DatePicker',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'DatePicker',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'InputNumber',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'InputNumber',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alilc/antd-lowcode',\n      version: '0.8.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        constructor: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        componentDidMount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function(prevProps, prevState, snapshot) {}',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n      },\n      methods: {\n        __jp__init: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initRouter: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initDataSource: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initEnv: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        __jp__initUtils: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onFinishFirst: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onClickPreSecond: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onFinishSecond: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onClickModifyThird: {\n          type: 'JSFunction',\n          value: \"function() { /*...*/ }\",\n        },\n        onOkModifyDialogThird: {\n          type: 'JSFunction',\n          value: 'function() {\\n    //第三步 修改 对话框 确定\\n\\n    this.setState({\\n      currentStep: 0,\\n      isModifyDialogVisible: false,\\n    });\\n  }',\n        },\n        onCancelModifyDialogThird: {\n          type: 'JSFunction',\n          value: 'function() {\\n    //第三步 修改 对话框 取消\\n\\n    this.setState({\\n      isModifyDialogVisible: false,\\n    });\\n  }',\n        },\n        onFinishFailed: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n        onClickPreThird: {\n          type: 'JSFunction',\n          value: 'function() {\\n    // 第三步 上一步\\n    this.setState({\\n      currentStep: 1,\\n    });\\n  }',\n        },\n        onClickFirstBack: {\n          type: 'JSFunction',\n          value: \"function() {\\n    // 第一步 返回按钮\\n    this.$router.push('/myProjectList');\\n  }\",\n        },\n        onClickSecondBack: {\n          type: 'JSFunction',\n          value: \"function() {\\n    // 第二步 返回按钮\\n    this.$router.push('/myProjectList');\\n  }\",\n        },\n        onClickThirdBack: {\n          type: 'JSFunction',\n          value: \"function() {\\n    // 第三步 返回按钮\\n    this.$router.push('/myProjectList');\\n  }\",\n        },\n        onValuesChange: {\n          type: 'JSFunction',\n          value: 'function(_, values) {\\n    this.setState({\\n      customerProjectInfo: {\\n        ...this.state.customerProjectInfo,\\n        ...values,\\n      },\\n    });\\n  }',\n        },\n      },\n      state: {\n        books: [],\n        currentStep: 0,\n        isModifyDialogVisible: false,\n        isModifyStatus: false,\n        secondCommitText: '完成并提交',\n        thirdAuditText: '审核中',\n        thirdButtonText: '修改',\n        customerProjectInfo: {\n          id: null,\n          systemProjectName: null,\n          projectVersionTypeArray: null,\n          projectVersionType: null,\n          versionLine: 2,\n          expectedTime: null,\n          expectedNum: null,\n          projectModal: null,\n          displayWidth: null,\n          displayHeight: null,\n          displayInch: null,\n          displayDpi: null,\n          mainSoc: null,\n          cpuCoreNum: null,\n          instructions: null,\n          osVersion: null,\n          status: null,\n        },\n        versionLinesArray: [\n          {\n            label: 'AmapAuto 485',\n            value: 1,\n          },\n          {\n            label: 'AmapAuto 505',\n            value: 2,\n          },\n        ],\n        projectModalsArray: [\n          {\n            label: '车机',\n            value: 1,\n          },\n          {\n            label: '车镜',\n            value: 2,\n          },\n          {\n            label: '记录仪',\n            value: 3,\n          },\n          {\n            label: '其他',\n            value: 4,\n          },\n        ],\n        osVersionsArray: [\n          {\n            label: '安卓5',\n            value: 1,\n          },\n          {\n            label: '安卓6',\n            value: 2,\n          },\n          {\n            label: '安卓7',\n            value: 3,\n          },\n          {\n            label: '安卓8',\n            value: 4,\n          },\n          {\n            label: '安卓9',\n            value: 5,\n          },\n          {\n            label: '安卓10',\n            value: 6,\n          },\n        ],\n        instructionsArray: [\n          {\n            label: 'ARM64-V8',\n            value: 'ARM64-V8',\n          },\n          {\n            label: 'ARM32-V7',\n            value: 'ARM32-V7',\n          },\n          {\n            label: 'X86',\n            value: 'X86',\n          },\n          {\n            label: 'X64',\n            value: 'X64',\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Modal',\n          id: 'node_ockodngwu940',\n          props: {\n            title: '是否修改',\n            visible: {\n              type: 'JSExpression',\n              value: 'this.state.isModifyDialogVisible',\n            },\n            okText: '确认',\n            okType: '',\n            forceRender: false,\n            cancelText: '取消',\n            zIndex: 2000,\n            destroyOnClose: false,\n            confirmLoading: false,\n            __events: {\n              eventDataList: [\n                {\n                  type: 'componentEvent',\n                  name: 'onOk',\n                  relatedEventName: 'onOkModifyDialogThird',\n                },\n                {\n                  type: 'componentEvent',\n                  name: 'onCancel',\n                  relatedEventName: 'onCancelModifyDialogThird',\n                },\n              ],\n              eventList: [\n                {\n                  name: 'onCancel',\n                  disabled: true,\n                },\n                {\n                  name: 'onOk',\n                  disabled: true,\n                },\n              ],\n            },\n            onOk: {\n              type: 'JSFunction',\n              value: 'function(){this.onOkModifyDialogThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n            onCancel: {\n              type: 'JSFunction',\n              value: 'function(){this.onCancelModifyDialogThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n          },\n          hidden: true,\n          children: [\n            {\n              componentName: 'NextText',\n              id: 'node_ockodngwu946',\n              props: {\n                type: 'inherit',\n                children: '修改将撤回此前填写的信息',\n                style: {\n                  fontStyle: 'normal',\n                  textAlign: 'left',\n                  display: 'block',\n                  fontFamily: 'arial, helvetica, microsoft yahei',\n                  fontWeight: 'normal',\n                },\n              },\n            },\n          ],\n        },\n        {\n          componentName: 'NextPage',\n          id: 'node_ocko19zplh1',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n            style: {},\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocko19zplh2',\n              props: {\n                prefix: 'next-',\n                placeholderStyle: {\n                  height: '100%',\n                },\n                noPadding: false,\n                noBorder: false,\n                background: 'surface',\n                layoutmode: 'O',\n                colSpan: 12,\n                rowSpan: 1,\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocko19zplh3',\n                  props: {\n                    title: '',\n                    prefix: 'next-',\n                    placeholderStyle: {\n                      height: '100%',\n                    },\n                    layoutmode: 'O',\n                    childTotalColumns: 12,\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockoco6icv1w',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                        style: {\n                          marginBottom: '24px',\n                        },\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Steps',\n                          id: 'node_ockoco6icv1x',\n                          props: {\n                            current: {\n                              type: 'JSExpression',\n                              value: 'this.state.currentStep',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Steps.Step',\n                              id: 'node_ockoco6icv1y',\n                              props: {\n                                title: '版本申请',\n                                description: '',\n                              },\n                            },\n                            {\n                              componentName: 'Steps.Step',\n                              id: 'node_ockoco6icv1z',\n                              props: {\n                                title: '机器配置',\n                                subTitle: '',\n                                description: '',\n                              },\n                            },\n                            {\n                              componentName: 'Steps.Step',\n                              id: 'node_ockoco6icv20',\n                              props: {\n                                title: '项目审批',\n                                description: '',\n                              },\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockoco6icv12w',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                        style: {\n                          display: 'flex',\n                          justifyContent: 'center',\n                        },\n                      },\n                      title: '段落',\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.state.currentStep === 0',\n                      },\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ockoco6icv12x',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 10,\n                            },\n                            onFinish: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinishFirst.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            style: {\n                              display: 'flex',\n                              flexDirection: 'column',\n                              width: '600px',\n                              justifyContent: 'center',\n                            },\n                            layout: 'vertical',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinish',\n                                  relatedEventName: 'onFinishFirst',\n                                },\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onValuesChange',\n                                  relatedEventName: 'onValuesChange',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: true,\n                                },\n                              ],\n                            },\n                            initialValues: {\n                              type: 'JSExpression',\n                              value: 'this.state.customerProjectInfo',\n                            },\n                            onValuesChange: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onValuesChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockojhvrkn2u',\n                              props: {\n                                label: '',\n                                style: {\n                                  width: '600px',\n                                },\n                                colon: false,\n                                name: 'id',\n                              },\n                              condition: false,\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ockojhvrkn2v',\n                                  props: {\n                                    placeholder: '',\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    bordered: false,\n                                    disabled: true,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv12y',\n                              props: {\n                                label: '版本类型选择',\n                                name: 'projectVersionTypeArray',\n                                initialValue: '',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  flexDirection: 'column',\n                                  width: '600px',\n                                },\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择版本类型',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Checkbox.Group',\n                                  id: 'node_ockoco6icv12z',\n                                  props: {\n                                    options: [\n                                      {\n                                        label: '基础版本',\n                                        value: '3',\n                                      },\n                                      {\n                                        label: 'AR导航',\n                                        value: '1',\n                                      },\n                                      {\n                                        label: '货车导航',\n                                        value: '2',\n                                      },\n                                      {\n                                        label: 'UI定制',\n                                        value: '4',\n                                        disabled: false,\n                                      },\n                                    ],\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv13a',\n                              props: {\n                                label: '版本线选择',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'versionLine',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择版本线',\n                                },\n                                extra: '',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockoco6icv13b',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.versionLinesArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    placeholder: '请选择版本线',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv13o',\n                              props: {\n                                label: '项目名称',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  display: 'flex',\n                                },\n                                labelAlign: 'left',\n                                extra: '',\n                                name: 'systemProjectName',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请按格式填写项目名称',\n                                },\n                                typeobj: {\n                                  type: 'string',\n                                  message: '请输入项目名称，格式：公司简称-产品名称-版本类型',\n                                },\n                                lenobj: {\n                                  max: 100,\n                                  message: '项目名称不能超过100个字符',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ockoco6icv13p',\n                                  props: {\n                                    placeholder: '公司简称-产品名称-版本类型',\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv13v',\n                              props: {\n                                label: '预期交付时间',\n                                style: {\n                                  width: '600px',\n                                },\n                                colon: false,\n                                required: true,\n                                name: 'expectedTime',\n                                labelAlign: 'left',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请填写预期交付时间',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'DatePicker',\n                                  id: 'node_ockoco6icv13w',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bv8',\n                              props: {\n                                label: '预期出货量',\n                                style: {\n                                  width: '600px',\n                                },\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请填写预期出货量',\n                                },\n                                name: 'expectedNum',\n                                labelAlign: 'left',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bv9',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '单位（台）使用该版本的机器数量+预计出货量，请如实填写',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                    size: 'middle',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv130',\n                              props: {\n                                wrapperCol: {\n                                  offset: '',\n                                },\n                                style: {\n                                  flexDirection: 'row',\n                                  alignItems: 'baseline',\n                                  justifyContent: 'space-between',\n                                  width: '600px',\n                                  display: 'block',\n                                },\n                                labelAlign: 'left',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv132',\n                                  props: {\n                                    style: {\n                                      margin: '0px',\n                                    },\n                                    children: '返回',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickFirstBack',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickFirstBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv131',\n                                  props: {\n                                    type: 'primary',\n                                    children: '下一步',\n                                    htmlType: 'submit',\n                                    style: {\n                                      boxShadow: 'rgba(31, 56, 88, 0.2) 0px 0px 0px 0px',\n                                      float: 'right',\n                                    },\n                                    __events: {\n                                      eventDataList: [],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockoco6icv1ue',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                        style: {\n                          display: 'flex',\n                          justifyContent: 'center',\n                        },\n                      },\n                      title: '段落',\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.state.currentStep === 1',\n                      },\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ockoco6icv1uf',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 10,\n                            },\n                            onFinish: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinishSecond.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            style: {\n                              display: 'flex',\n                              flexDirection: 'column',\n                              width: '600px',\n                              justifyContent: 'center',\n                              height: '800px',\n                            },\n                            layout: 'vertical',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinish',\n                                  relatedEventName: 'onFinishSecond',\n                                },\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onValuesChange',\n                                  relatedEventName: 'onValuesChange',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: true,\n                                },\n                              ],\n                            },\n                            initialValues: {\n                              type: 'JSExpression',\n                              value: 'this.state.customerProjectInfo',\n                            },\n                            onValuesChange: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onValuesChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv1ui',\n                              props: {\n                                label: '设备类型选择',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'projectModal',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择设备类型',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockoco6icv1uj',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.projectModalsArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    placeholder: '请选择设备类型',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bv17',\n                              props: {\n                                label: '屏幕分辨率宽',\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'displayWidth',\n                                colon: false,\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入屏幕分辨率宽',\n                                },\n                                labelAlign: 'left',\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bv18',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '例如1280',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bv10',\n                              props: {\n                                label: '屏幕分辨率高',\n                                style: {\n                                  width: '600px',\n                                },\n                                labelAlign: 'left',\n                                colon: false,\n                                name: 'displayHeight',\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入屏幕分辨率高',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bv11',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '例如720',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bvt',\n                              props: {\n                                label: '屏幕尺寸（inch）',\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'displayInch',\n                                labelAlign: 'left',\n                                required: true,\n                                colon: false,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入屏幕尺寸',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bvu',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '请输入尺寸',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bvm',\n                              props: {\n                                label: '屏幕DPI',\n                                style: {\n                                  width: '600px',\n                                },\n                                labelAlign: 'left',\n                                colon: false,\n                                required: false,\n                                name: 'displayDpi',\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bvn',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: 'UI定制项目必填',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv1v3',\n                              props: {\n                                label: '芯片名称',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  display: 'flex',\n                                },\n                                labelAlign: 'left',\n                                extra: '',\n                                name: 'mainSoc',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入芯片名称',\n                                },\n                                lenobj: {\n                                  max: 50,\n                                  message: '芯片名称不能超过50个字符',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ockoco6icv1v4',\n                                  props: {\n                                    placeholder: '请输入芯片名称',\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpmbs0bvf',\n                              props: {\n                                label: '芯片核数',\n                                style: {\n                                  width: '600px',\n                                },\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请输入芯片核数',\n                                },\n                                name: 'cpuCoreNum',\n                                labelAlign: 'left',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'InputNumber',\n                                  id: 'node_ockpmbs0bvg',\n                                  props: {\n                                    value: 3,\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    placeholder: '请输入芯片核数',\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    defaultValue: '',\n                                    min: 0,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockpxba11aa',\n                              props: {\n                                label: '指令集',\n                                style: {\n                                  width: '600px',\n                                },\n                                required: true,\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择指令集',\n                                },\n                                name: 'instructions',\n                                colon: false,\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockpxba11ab',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.instructionsArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockodz1kiqh',\n                              props: {\n                                label: '系统版本',\n                                labelAlign: 'left',\n                                colon: false,\n                                required: true,\n                                style: {\n                                  width: '600px',\n                                },\n                                name: 'osVersion',\n                                requiredobj: {\n                                  required: true,\n                                  message: '请选择系统版本',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ockodz1kiqi',\n                                  props: {\n                                    style: {\n                                      width: '600px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.osVersionsArray',\n                                    },\n                                    disabled: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus',\n                                    },\n                                    placeholder: '请选择系统版本',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockoco6icv1uq',\n                              props: {\n                                wrapperCol: {\n                                  offset: '',\n                                },\n                                style: {\n                                  flexDirection: 'row',\n                                  width: '600px',\n                                  display: 'flex',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv1ur',\n                                  props: {\n                                    style: {\n                                      marginLeft: '0',\n                                    },\n                                    children: '返回',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickSecondBack',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickSecondBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv1vb',\n                                  props: {\n                                    type: 'primary',\n                                    children: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.secondCommitText',\n                                    },\n                                    htmlType: 'submit',\n                                    style: {\n                                      float: 'right',\n                                      marginLeft: '20px',\n                                    },\n                                    loading: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockoco6icv1us',\n                                  props: {\n                                    type: 'primary',\n                                    children: '上一步',\n                                    htmlType: 'submit',\n                                    style: {\n                                      marginLeft: '0px',\n                                      float: 'right',\n                                    },\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickPreSecond',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickPreSecond.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockodngwu9m',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                        style: {\n                          display: 'flex',\n                          justifyContent: 'center',\n                        },\n                      },\n                      title: '段落',\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.state.currentStep === 2',\n                      },\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ockodngwu9n',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 10,\n                            },\n                            onFinishFailed: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinishFailed.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            style: {\n                              display: 'flex',\n                              flexDirection: 'column',\n                              width: '600px',\n                              justifyContent: 'center',\n                            },\n                            layout: 'vertical',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinishFailed',\n                                  relatedEventName: 'onFinishFailed',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: false,\n                                },\n                              ],\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockodngwu91m',\n                              props: {\n                                label: '',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Steps',\n                                  id: 'node_ockodngwu91n',\n                                  props: {\n                                    current: 1,\n                                    style: {\n                                      width: '600px',\n                                      display: 'flex',\n                                      justifyContent: 'space-around',\n                                      alignItems: 'center',\n                                      height: '300px',\n                                    },\n                                    labelPlacement: 'horizontal',\n                                    direction: 'vertical',\n                                  },\n                                  children: [\n                                    {\n                                      componentName: 'Steps.Step',\n                                      id: 'node_ockodngwu91o',\n                                      props: {\n                                        title: '提交完成',\n                                        description: '',\n                                        style: {\n                                          width: '200px',\n                                        },\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Steps.Step',\n                                      id: 'node_ockodngwu91p',\n                                      props: {\n                                        title: {\n                                          type: 'JSExpression',\n                                          value: 'this.state.thirdAuditText',\n                                        },\n                                        subTitle: '',\n                                        description: '',\n                                        style: {\n                                          width: '200px',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ockodngwu914',\n                              props: {\n                                wrapperCol: {\n                                  offset: '',\n                                },\n                                style: {\n                                  flexDirection: 'row',\n                                  width: '600px',\n                                  display: 'flex',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockodngwu915',\n                                  props: {\n                                    style: {\n                                      marginLeft: '0',\n                                    },\n                                    children: '返回',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickThirdBack',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickThirdBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockodngwu916',\n                                  props: {\n                                    type: 'primary',\n                                    children: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.thirdButtonText',\n                                    },\n                                    htmlType: 'submit',\n                                    style: {\n                                      float: 'right',\n                                      marginLeft: '20px',\n                                    },\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickModifyThird',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickModifyThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                },\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockosjrkvr1d',\n                                  props: {\n                                    type: 'primary',\n                                    children: '上一步',\n                                    htmlType: 'submit',\n                                    style: {\n                                      marginLeft: '0px',\n                                      float: 'right',\n                                    },\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onClick',\n                                          relatedEventName: 'onClickPreThird',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onClick',\n                                          disabled: true,\n                                        },\n                                      ],\n                                    },\n                                    onClick: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onClickPreThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                  },\n                                  condition: {\n                                    type: 'JSExpression',\n                                    value: 'this.state.customerProjectInfo.status > 2',\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-http-handler\": \"^1.0.0\",\n    \"@alilc/lowcode-components\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>example</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Page, Table } from '@alilc/lowcode-components';\n\nimport { createHttpHandler as __$$createHttpRequestHandler } from '@alilc/lowcode-datasource-http-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass Example$$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: { http: __$$createHttpRequestHandler() },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'userList',\n          type: 'http',\n          description: '用户列表',\n          options: function () {\n            return {\n              uri: 'https://api.example.com/user/list',\n            };\n          }.bind(_this),\n          isInit: function () {\n            return undefined;\n          }.bind(_this),\n        },\n      ],\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div>\n        <Table\n          dataSource={__$$eval(() => this.dataSourceMap['userList'])}\n          columns={[\n            { dataIndex: 'name', title: '姓名' },\n            { dataIndex: 'age', title: '年龄' },\n          ]}\n        />\n      </div>\n    );\n  }\n}\n\nexport default Example$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/routes.js",
    "content": "import Example from '@/pages/Example';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '',\n        component: Example,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      package: '@alilc/lowcode-components',\n      version: '^1.0.0',\n      componentName: 'Page',\n      destructuring: true,\n      exportName: 'Page',\n    },\n    {\n      package: '@alilc/lowcode-components',\n      version: '^1.0.0',\n      componentName: 'Table',\n      destructuring: true,\n      exportName: 'Table',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_ockp6ci0hm1',\n      props: {},\n      fileName: 'example',\n      dataSource: {\n        list: [\n          {\n            id: 'userList',\n            type: 'http',\n            description: '用户列表',\n            options: {\n              uri: 'https://api.example.com/user/list',\n            },\n          },\n        ],\n      },\n      children: [\n        {\n          componentName: 'Table',\n          id: 'node_ockp6ci0hm22',\n          props: {\n            dataSource: {\n              type: 'DataSource',\n              id: 'userList',\n            },\n            columns: [\n              {\n                dataIndex: 'name',\n                title: '姓名',\n              },\n              {\n                dataIndex: 'age',\n                title: '年龄',\n              },\n            ],\n          },\n        },\n      ],\n    },\n  ],\n  meta: {\n    name: 'example',\n    description: 'Example',\n  },\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-datasource-jsonp-handler\": \"^1.0.0\",\n    \"@alifd/next\": \"1.19.18\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>Ice App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport { Switch } from '@alifd/next';\n\nimport { createJsonpHandler as __$$createJsonpRequestHandler } from '@alilc/lowcode-datasource-jsonp-handler';\n\nimport { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';\n\nimport '@alifd/next/lib/switch/style';\n\nimport utils from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nclass $$Page extends React.Component {\n  _context = this;\n\n  _dataSourceConfig = this._defineDataSourceConfig();\n  _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {\n    runtimeConfig: true,\n    requestHandlersMap: { jsonp: __$$createJsonpRequestHandler() },\n  });\n\n  get dataSourceMap() {\n    return this._dataSourceEngine.dataSourceMap || {};\n  }\n\n  reloadDataSource = async () => {\n    await this._dataSourceEngine.reloadDataSource();\n  };\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    __$$i18n._inject2(this);\n\n    this.state = {};\n  }\n\n  $ = () => null;\n\n  $$ = () => [];\n\n  _defineDataSourceConfig() {\n    const _this = this;\n    return {\n      list: [\n        {\n          id: 'todos',\n          isInit: function () {\n            return true;\n          }.bind(_this),\n          type: 'jsonp',\n          options: function () {\n            return {\n              method: 'GET',\n              uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io',\n            };\n          }.bind(_this),\n          dataHandler: function dataHandler(data) {\n            return data.data;\n          },\n        },\n      ],\n    };\n  }\n\n  componentDidMount() {\n    this._dataSourceEngine.reloadDataSource();\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div>\n        {__$$evalArray(() => this.dataSourceMap.todos.data).map((item, index) =>\n          ((__$$context) => (\n            <div>\n              <Switch\n                checkedChildren=\"开\"\n                unCheckedChildren=\"关\"\n                checked={__$$eval(() => item.done)}\n              />\n            </div>\n          ))(__$$createChildContext(__$$context, { item, index }))\n        )}\n      </div>\n    );\n  }\n}\n\nexport default $$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/routes.js",
    "content": "import $ from '@/pages/$';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '',\n        component: $,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      componentName: 'Switch',\n      package: '@alifd/next',\n      version: '1.19.18',\n      exportName: 'Switch',\n      destructuring: true,\n      subName: '',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      props: {},\n      children: [\n        {\n          componentName: 'Div',\n          props: {},\n          children: [\n            {\n              componentName: 'Switch',\n              props: {\n                checkedChildren: '开',\n                unCheckedChildren: '关',\n                checked: {\n                  type: 'JSExpression',\n                  value: 'this.item.done',\n                },\n              },\n            },\n          ],\n          loop: {\n            type: 'JSExpression',\n            value: 'this.dataSourceMap.todos.data',\n          },\n        },\n      ],\n      dataSource: {\n        list: [\n          {\n            id: 'todos',\n            isInit: true,\n            type: 'jsonp',\n            options: {\n              method: 'GET',\n              uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io',\n            },\n            dataHandler: {\n              type: 'JSFunction',\n              value: 'function dataHandler(data) {return data.data;}',\n            },\n          },\n        ],\n      },\n    },\n  ],\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alilc/antd-lowcode-materials\": \"0.9.4\",\n    \"@alife/mc-assets-1935\": \"0.1.42\",\n    \"@alife/container\": \"0.3.7\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>Ice App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Modal,\n  Button,\n  Typography,\n  Form,\n  Select,\n  Input,\n  ConfigProvider,\n  Tooltip,\n  Empty,\n} from '@alilc/antd-lowcode-materials/dist/antd-lowcode.esm.js';\n\nimport {\n  AliAutoDiv,\n  AliAutoSearchTable,\n} from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst AliAutoDivDefault = AliAutoDiv.default;\n\nconst AliAutoSearchTableDefault = AliAutoSearchTable.default;\n\nconst NextBlockCell = NextBlock.Cell;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      pkgs: [],\n      total: 0,\n      isSearch: false,\n      projects: [],\n      results: [],\n      resultVisible: false,\n    };\n\n    this.__jp__init();\n    this.statusDesc = {\n      0: '失败',\n      1: '成功',\n      2: '构建中',\n      3: '构建超时',\n    };\n    this.pageParams = {};\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidUpdate(prevProps, prevState, snapshot) {}\n\n  componentWillUnmount() {}\n\n  __jp__init() {\n    /*...*/\n  }\n\n  __jp__initRouter() {\n    if (window.arsenal) {\n      this.$router = new window.jianpin.ArsenalRouter({\n        app: this.props.microApp,\n      });\n    } else {\n      this.$router = new window.jianpin.ArsenalRouter();\n    }\n  }\n\n  __jp__initDataSource() {\n    /*...*/\n  }\n\n  __jp__initEnv() {\n    /*...*/\n  }\n\n  __jp__initConfig() {\n    /*...*/\n  }\n\n  __jp__initUtils() {\n    this.$utils = {\n      message: window.jianpin.utils.message,\n      axios: window.jianpin.utils.axios,\n      moment: window.jianpin.utils.moment,\n    };\n  }\n\n  fetchPkgs() {\n    /*...*/\n  }\n\n  onPageChange(pageIndex, pageSize) {\n    this.pageParams = {\n      pageIndex,\n      pageSize,\n    };\n    this.fetchPkgs();\n  }\n\n  renderTime(time) {\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n  }\n\n  renderUserName(user) {\n    return user.user_name;\n  }\n\n  reload() {\n    /*...*/\n  }\n\n  handleResult() {\n    /*...*/\n  }\n\n  handleDetail() {\n    // 跳转详情页面 TODO\n  }\n\n  onResultCancel() {\n    this.setState({\n      resultVisible: false,\n    });\n  }\n\n  formatResult(item) {\n    if (!item) {\n      return '暂无结果';\n    }\n    const { channel, plat, version, status } = item;\n    return [channel, plat, version, status].join('-');\n  }\n\n  handleDownload() {\n    /*...*/\n  }\n\n  onFinish() {\n    /*...*/\n  }\n\n  componentDidMount() {\n    this.$ds.resolve('PROJECTS', {\n      params: {\n        size: 5000,\n      },\n    });\n    // if (this.state.init === false) {\n    //   this.setState({\n    //     init: true,\n    //   });\n    // }\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <Modal\n          title=\"查看结果\"\n          visible={__$$eval(() => this.state.resultVisible)}\n          footer={\n            <Button\n              type=\"primary\"\n              __events={{\n                eventDataList: [\n                  {\n                    type: 'componentEvent',\n                    name: 'onClick',\n                    relatedEventName: 'onResultCancel',\n                  },\n                ],\n                eventList: [{ name: 'onClick', disabled: true }],\n              }}\n              onClick={function () {\n                this.onResultCancel.apply(\n                  this,\n                  Array.prototype.slice.call(arguments).concat([])\n                );\n              }.bind(this)}\n            >\n              确定\n            </Button>\n          }\n          __events={{\n            eventDataList: [\n              {\n                type: 'componentEvent',\n                name: 'onCancel',\n                relatedEventName: 'onResultCancel',\n              },\n            ],\n            eventList: [\n              { name: 'onCancel', disabled: true },\n              { name: 'onOk', disabled: false },\n            ],\n          }}\n          onCancel={function () {\n            this.onResultCancel.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n          width=\"720px\"\n          centered={true}\n        >\n          {__$$evalArray(() => this.state.results).map((item, index) =>\n            ((__$$context) => (\n              <AliAutoDivDefault style={{ width: '100%' }}>\n                {!!__$$eval(\n                  () =>\n                    __$$context.state.results &&\n                    __$$context.state.results.length > 0\n                ) && (\n                  <AliAutoDivDefault\n                    style={{\n                      width: '100%',\n                      textAlign: 'left',\n                      marginBottom: '10px',\n                    }}\n                  >\n                    <Button\n                      type=\"primary\"\n                      size=\"small\"\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onClick',\n                            relatedEventName: 'handleDownload',\n                          },\n                        ],\n                        eventList: [{ name: 'onClick', disabled: true }],\n                      }}\n                      onClick={function () {\n                        this.handleDownload.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(__$$context)}\n                    >\n                      下载全部\n                    </Button>\n                  </AliAutoDivDefault>\n                )}\n                <Typography.Text>\n                  {__$$eval(() => __$$context.formatResult(item))}\n                </Typography.Text>\n                {!!__$$eval(() => item.download_link) && (\n                  <Typography.Link\n                    href={__$$eval(() => item.download_link)}\n                    target=\"_blank\"\n                  >\n                    {' '}\n                    - 点击下载\n                  </Typography.Link>\n                )}\n                {!!__$$eval(() => item.release_notes) && (\n                  <Typography.Link\n                    href={__$$eval(() => item.release_notes)}\n                    target=\"_blank\"\n                  >\n                    {' '}\n                    - 跳转发布节点\n                  </Typography.Link>\n                )}\n              </AliAutoDivDefault>\n            ))(__$$createChildContext(__$$context, { item, index }))\n          )}\n        </Modal>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface' }}\n          footer={null}\n          minHeight=\"100vh\"\n        >\n          <NextBlock\n            prefix=\"next-\"\n            placeholderStyle={{ height: '100%' }}\n            noPadding={false}\n            noBorder={false}\n            background=\"surface\"\n            layoutmode=\"O\"\n            colSpan={12}\n            rowSpan={1}\n            childTotalColumns={12}\n          >\n            <NextBlockCell\n              title=\"\"\n              prefix=\"next-\"\n              placeholderStyle={{ height: '100%' }}\n              layoutmode=\"O\"\n              childTotalColumns={12}\n              isAutoContainer={true}\n              colSpan={12}\n              rowSpan={1}\n            >\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                full={true}\n                flex={true}\n              >\n                <Form\n                  labelCol={{ span: 10 }}\n                  wrapperCol={{ span: 14 }}\n                  onFinish={function () {\n                    this.onFinish.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                  name=\"basic\"\n                  layout=\"inline\"\n                  __events={{\n                    eventDataList: [\n                      {\n                        type: 'componentEvent',\n                        name: 'onFinish',\n                        relatedEventName: 'onFinish',\n                      },\n                    ],\n                    eventList: [\n                      { name: 'onFinish', disabled: true },\n                      { name: 'onFinishFailed', disabled: false },\n                      { name: 'onFieldsChange', disabled: false },\n                      { name: 'onValuesChange', disabled: false },\n                    ],\n                  }}\n                >\n                  <Form.Item label=\"项目名称/渠道号\" name=\"channel_id\">\n                    <Select\n                      style={{ width: '280px' }}\n                      options={__$$eval(() => this.state.projects)}\n                      showArrow={true}\n                      tokenSeparators={[]}\n                      showSearch={true}\n                    />\n                  </Form.Item>\n                  <Form.Item label=\"版本号\" name=\"buildId\">\n                    <Input\n                      placeholder=\"请输入\"\n                      style={{ width: '280px' }}\n                      size=\"middle\"\n                    />\n                  </Form.Item>\n                  <Form.Item label=\"构建人\" name=\"user_id\">\n                    <Select\n                      style={{ width: 200 }}\n                      options={[\n                        { label: 'A', value: 'A' },\n                        { label: 'B', value: 'B' },\n                        { label: 'C', value: 'C' },\n                      ]}\n                      showSearch={true}\n                    />\n                  </Form.Item>\n                  <Form.Item label=\"ID\" name=\"id\">\n                    <Input placeholder=\"请输入\" style={{ width: '160px' }} />\n                  </Form.Item>\n                  <Form.Item wrapperCol={{ offset: 6 }}>\n                    <Button type=\"primary\" htmlType=\"submit\">\n                      查询\n                    </Button>\n                  </Form.Item>\n                </Form>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock childTotalColumns={12}>\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                <ConfigProvider locale=\"zh-CN\">\n                  {!!__$$eval(\n                    () =>\n                      !this.state.isSearch ||\n                      (this.state.isSearch && this.state.pkgs.length > 0)\n                  ) && (\n                    <AliAutoSearchTableDefault\n                      rowKey=\"key\"\n                      dataSource={__$$eval(() => this.state.pkgs)}\n                      columns={[\n                        {\n                          title: 'ID',\n                          dataIndex: 'id',\n                          key: 'name',\n                          width: 80,\n                        },\n                        {\n                          title: '渠道号',\n                          dataIndex: 'channels',\n                          key: 'age',\n                          width: 142,\n                          render: (text, record, index) =>\n                            ((__$$context) =>\n                              __$$evalArray(() => text.split(',')).map(\n                                (item, index) =>\n                                  ((__$$context) => (\n                                    <Typography.Text\n                                      style={{ display: 'block' }}\n                                    >\n                                      {__$$eval(() => item)}\n                                    </Typography.Text>\n                                  ))(\n                                    __$$createChildContext(__$$context, {\n                                      item,\n                                      index,\n                                    })\n                                  )\n                              ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                        },\n                        {\n                          title: '版本号',\n                          dataIndex: 'dic_version',\n                          key: 'address',\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Tooltip\n                                title={__$$evalArray(() => text || []).map(\n                                  (item, index) =>\n                                    ((__$$context) => (\n                                      <Typography.Text\n                                        style={{\n                                          display: 'block',\n                                          color: '#FFFFFF',\n                                        }}\n                                      >\n                                        {__$$eval(\n                                          () =>\n                                            item.channelId +\n                                            ' / ' +\n                                            item.version\n                                        )}\n                                      </Typography.Text>\n                                    ))(\n                                      __$$createChildContext(__$$context, {\n                                        item,\n                                        index,\n                                      })\n                                    )\n                                )}\n                              >\n                                <Typography.Text>\n                                  {__$$eval(() => text[0].version)}\n                                </Typography.Text>\n                              </Tooltip>\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 120,\n                        },\n                        { title: '构建Job', dataIndex: 'job_name', width: 180 },\n                        {\n                          title: '构建类型',\n                          dataIndex: 'packaging_type',\n                          width: 94,\n                        },\n                        {\n                          title: '构建状态',\n                          dataIndex: 'status',\n                          render: (text, record, index) =>\n                            ((__$$context) => [\n                              <Typography.Text>\n                                {__$$eval(() => __$$context.statusDesc[text])}\n                              </Typography.Text>,\n                              !!__$$eval(() => text === 2) && (\n                                <Icon\n                                  type=\"SyncOutlined\"\n                                  size={16}\n                                  spin={true}\n                                  style={{ marginLeft: '10px' }}\n                                />\n                              ),\n                            ])(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 100,\n                        },\n                        {\n                          title: '构建时间',\n                          dataIndex: 'start_time',\n                          render: function () {\n                            return this.renderTime.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this),\n                          width: 148,\n                        },\n                        {\n                          title: '构建人',\n                          dataIndex: 'user',\n                          render: function () {\n                            return this.renderUserName.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this),\n                          width: 80,\n                        },\n                        {\n                          title: 'Jenkins 链接',\n                          dataIndex: 'jenkins_link',\n                          render: (text, record, index) =>\n                            ((__$$context) => [\n                              !!__$$eval(() => text) && (\n                                <Typography.Link\n                                  href={__$$eval(() => text)}\n                                  target=\"_blank\"\n                                >\n                                  查看\n                                </Typography.Link>\n                              ),\n                              !!__$$eval(() => !text) && (\n                                <Typography.Text>暂无</Typography.Text>\n                              ),\n                            ])(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 120,\n                        },\n                        {\n                          title: '测试平台链接',\n                          dataIndex: 'is_run_testing',\n                          width: 120,\n                          render: (text, record, index) =>\n                            ((__$$context) => [\n                              !!__$$eval(() => text) && (\n                                <Typography.Link\n                                  href=\"http://rivermap.alibaba.net/dashboard/testExecute\"\n                                  target=\"_blank\"\n                                >\n                                  查看\n                                </Typography.Link>\n                              ),\n                              !!__$$eval(() => !text) && (\n                                <Typography.Text>暂无</Typography.Text>\n                              ),\n                            ])(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                        },\n                        { title: '触发源', dataIndex: 'source', width: 120 },\n                        {\n                          title: '详情',\n                          dataIndex: 'id',\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Button\n                                type=\"link\"\n                                size=\"small\"\n                                style={{ padding: '0px' }}\n                                __events={{\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'handleDetail',\n                                    },\n                                  ],\n                                  eventList: [\n                                    { name: 'onClick', disabled: true },\n                                  ],\n                                }}\n                                onClick={function () {\n                                  this.handleDetail.apply(\n                                    this,\n                                    Array.prototype.slice\n                                      .call(arguments)\n                                      .concat([])\n                                  );\n                                }.bind(__$$context)}\n                              >\n                                查看\n                              </Button>\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 80,\n                          fixed: 'right',\n                        },\n                        {\n                          title: '结果',\n                          dataIndex: 'id',\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Button\n                                type=\"link\"\n                                size=\"small\"\n                                style={{ padding: '0px' }}\n                                __events={{\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'handleResult',\n                                      paramStr: 'this.text',\n                                    },\n                                  ],\n                                  eventList: [\n                                    { name: 'onClick', disabled: true },\n                                  ],\n                                }}\n                                onClick={function () {\n                                  this.handleResult.apply(\n                                    this,\n                                    Array.prototype.slice\n                                      .call(arguments)\n                                      .concat([])\n                                  );\n                                }.bind(__$$context)}\n                                ghost={false}\n                                href={__$$eval(() => text)}\n                              >\n                                查看\n                              </Button>\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          width: 80,\n                          fixed: 'right',\n                        },\n                        {\n                          title: '重新执行',\n                          dataIndex: 'id',\n                          width: 92,\n                          render: (text, record, index) =>\n                            ((__$$context) => (\n                              <Button\n                                type=\"text\"\n                                children=\"\"\n                                icon={\n                                  <Icon\n                                    type=\"ReloadOutlined\"\n                                    size={14}\n                                    color=\"#0593d3\"\n                                    style={{\n                                      padding: '3px',\n                                      border: '1px solid #0593d3',\n                                      borderRadius: '14px',\n                                      cursor: 'pointer',\n                                      height: '22px',\n                                    }}\n                                    spin={false}\n                                  />\n                                }\n                                shape=\"circle\"\n                                __events={{\n                                  eventDataList: [\n                                    {\n                                      type: 'componentEvent',\n                                      name: 'onClick',\n                                      relatedEventName: 'reload',\n                                    },\n                                  ],\n                                  eventList: [\n                                    { name: 'onClick', disabled: true },\n                                  ],\n                                }}\n                                onClick={function () {\n                                  this.reload.apply(\n                                    this,\n                                    Array.prototype.slice\n                                      .call(arguments)\n                                      .concat([])\n                                  );\n                                }.bind(__$$context)}\n                              />\n                            ))(\n                              __$$createChildContext(__$$context, {\n                                text,\n                                record,\n                                index,\n                              })\n                            ),\n                          fixed: 'right',\n                        },\n                      ]}\n                      actions={[]}\n                      pagination={{\n                        total: __$$eval(() => this.state.total),\n                        defaultPageSize: 8,\n                        onPageChange: function () {\n                          return this.onPageChange.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this),\n                      }}\n                      scrollX={1200}\n                    />\n                  )}\n                </ConfigProvider>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock childTotalColumns={12}>\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                {!!__$$eval(\n                  () => this.state.pkgs.length < 1 && this.state.isSearch\n                ) && <Empty description=\"暂无数据\" />}\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.42',\n      exportName: 'AliAutoDiv',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoDivDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Text',\n      componentName: 'Typography.Text',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Link',\n      componentName: 'Typography.Link',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Input',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.42',\n      exportName: 'AliAutoSearchTable',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoSearchTableDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'ConfigProvider',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'ConfigProvider',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Empty',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Empty',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.9.4',\n      exportName: 'Tooltip',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Tooltip',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        constructor: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.__jp__init();\\n    this.statusDesc = {\\n      0: '失败',\\n      1: '成功',\\n      2: '构建中',\\n      3: '构建超时',\\n    };\\n    this.pageParams = {};\\n  }\",\n        },\n        componentDidMount: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.$ds.resolve('PROJECTS', {\\n      params: {\\n        size: 5000,\\n      },\\n    });\\n    // if (this.state.init === false) {\\n    //   this.setState({\\n    //     init: true,\\n    //   });\\n    // }\\n  }\",\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function(prevProps, prevState, snapshot) {}',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n      },\n      methods: {\n        __jp__init: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initRouter: {\n          type: 'JSFunction',\n          value: 'function() {\\n  if (window.arsenal) {\\n    this.$router = new window.jianpin.ArsenalRouter({\\n      app: this.props.microApp,\\n    });\\n  } else {\\n    this.$router = new window.jianpin.ArsenalRouter();\\n  }\\n}',\n        },\n        __jp__initDataSource: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initEnv: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initConfig: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initUtils: {\n          type: 'JSFunction',\n          value: 'function() {\\n  this.$utils = {\\n    message: window.jianpin.utils.message,\\n    axios: window.jianpin.utils.axios,\\n    moment: window.jianpin.utils.moment,\\n  };\\n}',\n        },\n        fetchPkgs: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onPageChange: {\n          type: 'JSFunction',\n          value: 'function(pageIndex, pageSize) {\\n    this.pageParams = {\\n      pageIndex,\\n      pageSize,\\n    };\\n    this.fetchPkgs();\\n  }',\n        },\n        renderTime: {\n          type: 'JSFunction',\n          value: \"function(time) {\\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\\n  }\",\n        },\n        renderUserName: {\n          type: 'JSFunction',\n          value: 'function(user) {\\n    return user.user_name;\\n  }',\n        },\n        reload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleResult: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleDetail: {\n          type: 'JSFunction',\n          value: 'function() {\\n    // 跳转详情页面 TODO\\n  }',\n        },\n        onResultCancel: {\n          type: 'JSFunction',\n          value: 'function() {\\n    this.setState({\\n      resultVisible: false,\\n    });\\n  }',\n        },\n        formatResult: {\n          type: 'JSFunction',\n          value: \"function(item) {\\n    if (!item) {\\n      return '暂无结果';\\n    }\\n    const { channel, plat, version, status } = item;\\n    return [channel, plat, version, status].join('-');\\n  }\",\n        },\n        handleDownload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onFinish: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n      },\n      state: {\n        pkgs: [],\n        total: 0,\n        isSearch: false,\n        projects: [],\n        results: [],\n        resultVisible: false,\n      },\n      children: [\n        {\n          componentName: 'Modal',\n          id: 'node_ocksh9yppxb',\n          props: {\n            title: '查看结果',\n            visible: {\n              type: 'JSExpression',\n              value: 'this.state.resultVisible',\n            },\n            footer: {\n              type: 'JSSlot',\n              value: [\n                {\n                  componentName: 'Button',\n                  id: 'node_ocksh9yppxf',\n                  props: {\n                    type: 'primary',\n                    children: '确定',\n                    __events: {\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onClick',\n                          relatedEventName: 'onResultCancel',\n                        },\n                      ],\n                      eventList: [\n                        {\n                          name: 'onClick',\n                          disabled: true,\n                        },\n                      ],\n                    },\n                    onClick: {\n                      type: 'JSFunction',\n                      value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                    },\n                  },\n                },\n              ],\n            },\n            __events: {\n              eventDataList: [\n                {\n                  type: 'componentEvent',\n                  name: 'onCancel',\n                  relatedEventName: 'onResultCancel',\n                },\n              ],\n              eventList: [\n                {\n                  name: 'onCancel',\n                  disabled: true,\n                },\n                {\n                  name: 'onOk',\n                  disabled: false,\n                },\n              ],\n            },\n            onCancel: {\n              type: 'JSFunction',\n              value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n            width: '720px',\n            centered: true,\n          },\n          hidden: true,\n          children: [\n            {\n              componentName: 'AliAutoDivDefault',\n              id: 'node_ockshazuxa4',\n              props: {\n                style: {\n                  width: '100%',\n                },\n              },\n              loop: {\n                type: 'JSExpression',\n                value: 'this.state.results',\n              },\n              children: [\n                {\n                  componentName: 'AliAutoDivDefault',\n                  id: 'node_ockshazuxai',\n                  props: {\n                    style: {\n                      width: '100%',\n                      textAlign: 'left',\n                      marginBottom: '10px',\n                    },\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.state.results && this.state.results.length > 0',\n                  },\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node_ockshazuxah',\n                      props: {\n                        type: 'primary',\n                        children: '下载全部',\n                        size: 'small',\n                        __events: {\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'handleDownload',\n                            },\n                          ],\n                          eventList: [\n                            {\n                              name: 'onClick',\n                              disabled: true,\n                            },\n                          ],\n                        },\n                        onClick: {\n                          type: 'JSFunction',\n                          value: 'function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Typography.Text',\n                  id: 'node_ockshazuxa5',\n                  props: {\n                    children: {\n                      type: 'JSExpression',\n                      value: 'this.formatResult(this.item)',\n                    },\n                  },\n                },\n                {\n                  componentName: 'Typography.Link',\n                  id: 'node_ockshazuxa6',\n                  props: {\n                    href: {\n                      type: 'JSExpression',\n                      value: 'this.item.download_link',\n                    },\n                    target: '_blank',\n                    children: ' - 点击下载',\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.item.download_link',\n                  },\n                },\n                {\n                  componentName: 'Typography.Link',\n                  id: 'node_ockshazuxa7',\n                  props: {\n                    href: {\n                      type: 'JSExpression',\n                      value: 'this.item.release_notes',\n                    },\n                    target: '_blank',\n                    children: ' - 跳转发布节点',\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.item.release_notes',\n                  },\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'NextPage',\n          id: 'node_ocko19zplh1',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocko19zplh2',\n              props: {\n                prefix: 'next-',\n                placeholderStyle: {\n                  height: '100%',\n                },\n                noPadding: false,\n                noBorder: false,\n                background: 'surface',\n                layoutmode: 'O',\n                colSpan: 12,\n                rowSpan: 1,\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocko19zplh3',\n                  props: {\n                    title: '',\n                    prefix: 'next-',\n                    placeholderStyle: {\n                      height: '100%',\n                    },\n                    layoutmode: 'O',\n                    childTotalColumns: 12,\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocks8dtt1ms',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        full: true,\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Form',\n                          id: 'node_ocks8dtt1mt',\n                          props: {\n                            labelCol: {\n                              span: 10,\n                            },\n                            wrapperCol: {\n                              span: 14,\n                            },\n                            onFinish: {\n                              type: 'JSFunction',\n                              value: 'function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                            },\n                            name: 'basic',\n                            layout: 'inline',\n                            __events: {\n                              eventDataList: [\n                                {\n                                  type: 'componentEvent',\n                                  name: 'onFinish',\n                                  relatedEventName: 'onFinish',\n                                },\n                              ],\n                              eventList: [\n                                {\n                                  name: 'onFinish',\n                                  disabled: true,\n                                },\n                                {\n                                  name: 'onFinishFailed',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onFieldsChange',\n                                  disabled: false,\n                                },\n                                {\n                                  name: 'onValuesChange',\n                                  disabled: false,\n                                },\n                              ],\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1mz',\n                              props: {\n                                label: '项目名称/渠道号',\n                                name: 'channel_id',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ocksfuhwhsd',\n                                  props: {\n                                    style: {\n                                      width: '280px',\n                                    },\n                                    options: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.projects',\n                                    },\n                                    showArrow: true,\n                                    tokenSeparators: [],\n                                    showSearch: true,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1m12',\n                              props: {\n                                label: '版本号',\n                                name: 'buildId',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ocksfuhwhs3',\n                                  props: {\n                                    placeholder: '请输入',\n                                    style: {\n                                      width: '280px',\n                                    },\n                                    size: 'middle',\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1m18',\n                              props: {\n                                label: '构建人',\n                                name: 'user_id',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Select',\n                                  id: 'node_ocksfuhwhsi',\n                                  props: {\n                                    style: {\n                                      width: 200,\n                                    },\n                                    options: [\n                                      {\n                                        label: 'A',\n                                        value: 'A',\n                                      },\n                                      {\n                                        label: 'B',\n                                        value: 'B',\n                                      },\n                                      {\n                                        label: 'C',\n                                        value: 'C',\n                                      },\n                                    ],\n                                    showSearch: true,\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1m19',\n                              props: {\n                                label: 'ID',\n                                name: 'id',\n                              },\n                              children: [\n                                {\n                                  componentName: 'Input',\n                                  id: 'node_ocksfuhwhs8',\n                                  props: {\n                                    placeholder: '请输入',\n                                    style: {\n                                      width: '160px',\n                                    },\n                                  },\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'Form.Item',\n                              id: 'node_ocks8dtt1mw',\n                              props: {\n                                wrapperCol: {\n                                  offset: 6,\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ocks8dtt1mx',\n                                  props: {\n                                    type: 'primary',\n                                    children: '查询',\n                                    htmlType: 'submit',\n                                  },\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ockshc4ifn1b',\n              props: {\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ockshc4ifn1c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockshc4ifn1d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'ConfigProvider',\n                          id: 'node_ockshc4ifn1e',\n                          props: {\n                            locale: 'zh-CN',\n                          },\n                          children: [\n                            {\n                              componentName: 'AliAutoSearchTableDefault',\n                              id: 'node_ocksfuhwhsx',\n                              props: {\n                                rowKey: 'key',\n                                dataSource: {\n                                  type: 'JSExpression',\n                                  value: 'this.state.pkgs',\n                                },\n                                columns: [\n                                  {\n                                    title: 'ID',\n                                    dataIndex: 'id',\n                                    key: 'name',\n                                    width: 80,\n                                  },\n                                  {\n                                    title: '渠道号',\n                                    dataIndex: 'channels',\n                                    key: 'age',\n                                    width: 142,\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh2bq0428',\n                                          props: {\n                                            children: {\n                                              type: 'JSExpression',\n                                              value: 'this.item',\n                                            },\n                                            style: {\n                                              display: 'block',\n                                            },\n                                          },\n                                          loop: {\n                                            type: 'JSExpression',\n                                            value: \"this.text.split(',')\",\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  },\n                                  {\n                                    title: '版本号',\n                                    dataIndex: 'dic_version',\n                                    key: 'address',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Tooltip',\n                                          id: 'node_ocksso4xavj',\n                                          props: {\n                                            title: {\n                                              type: 'JSSlot',\n                                              value: [\n                                                {\n                                                  componentName: 'Typography.Text',\n                                                  id: 'node_ocksso4xavn',\n                                                  props: {\n                                                    children: {\n                                                      type: 'JSExpression',\n                                                      value: \"this.item. channelId + ' / ' +  this.item.version\",\n                                                    },\n                                                    style: {\n                                                      display: 'block',\n                                                      color: '#FFFFFF',\n                                                    },\n                                                  },\n                                                  loop: {\n                                                    type: 'JSExpression',\n                                                    value: 'this.text || []',\n                                                  },\n                                                },\n                                              ],\n                                            },\n                                          },\n                                          children: [\n                                            {\n                                              componentName: 'Typography.Text',\n                                              id: 'node_ocksso4xavm',\n                                              props: {\n                                                children: {\n                                                  type: 'JSExpression',\n                                                  value: 'this.text[0].version',\n                                                },\n                                              },\n                                            },\n                                          ],\n                                        },\n                                      ],\n                                    },\n                                    width: 120,\n                                  },\n                                  {\n                                    title: '构建Job',\n                                    dataIndex: 'job_name',\n                                    width: 180,\n                                  },\n                                  {\n                                    title: '构建类型',\n                                    dataIndex: 'packaging_type',\n                                    width: 94,\n                                  },\n                                  {\n                                    title: '构建状态',\n                                    dataIndex: 'status',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh3jkxzw',\n                                          props: {\n                                            children: {\n                                              type: 'JSExpression',\n                                              value: 'this.statusDesc[this.text]',\n                                            },\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Icon',\n                                          id: 'node_ocksh3jkxzx',\n                                          props: {\n                                            type: 'SyncOutlined',\n                                            size: 16,\n                                            spin: true,\n                                            style: {\n                                              marginLeft: '10px',\n                                            },\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: 'this.text === 2',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 100,\n                                  },\n                                  {\n                                    title: '构建时间',\n                                    dataIndex: 'start_time',\n                                    render: {\n                                      type: 'JSFunction',\n                                      value: 'function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    width: 148,\n                                  },\n                                  {\n                                    title: '构建人',\n                                    dataIndex: 'user',\n                                    render: {\n                                      type: 'JSFunction',\n                                      value: 'function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    width: 80,\n                                  },\n                                  {\n                                    title: 'Jenkins 链接',\n                                    dataIndex: 'jenkins_link',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Link',\n                                          id: 'node_ocksh64kbx21',\n                                          props: {\n                                            href: {\n                                              type: 'JSExpression',\n                                              value: 'this.text',\n                                            },\n                                            target: '_blank',\n                                            children: '查看',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: 'this.text',\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh64kbx22',\n                                          props: {\n                                            children: '暂无',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: '!this.text',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 120,\n                                  },\n                                  {\n                                    title: '测试平台链接',\n                                    dataIndex: 'is_run_testing',\n                                    width: 120,\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Typography.Link',\n                                          id: 'node_ocksh3jkxz3e',\n                                          props: {\n                                            href: 'http://rivermap.alibaba.net/dashboard/testExecute',\n                                            target: '_blank',\n                                            children: '查看',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: 'this.text',\n                                          },\n                                        },\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksh3jkxz3f',\n                                          props: {\n                                            children: '暂无',\n                                          },\n                                          condition: {\n                                            type: 'JSExpression',\n                                            value: '!this.text',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  },\n                                  {\n                                    title: '触发源',\n                                    dataIndex: 'source',\n                                    width: 120,\n                                  },\n                                  {\n                                    title: '详情',\n                                    dataIndex: 'id',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocksh8yryw7',\n                                          props: {\n                                            type: 'link',\n                                            children: '查看',\n                                            size: 'small',\n                                            style: {\n                                              padding: '0px',\n                                            },\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'handleDetail',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 80,\n                                    fixed: 'right',\n                                  },\n                                  {\n                                    title: '结果',\n                                    dataIndex: 'id',\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocksh9v6jw7',\n                                          props: {\n                                            type: 'link',\n                                            children: '查看',\n                                            size: 'small',\n                                            style: {\n                                              padding: '0px',\n                                            },\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'handleResult',\n                                                  paramStr: 'this.text',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            ghost: false,\n                                            href: {\n                                              type: 'JSExpression',\n                                              value: 'this.text',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    width: 80,\n                                    fixed: 'right',\n                                  },\n                                  {\n                                    title: '重新执行',\n                                    dataIndex: 'id',\n                                    width: 92,\n                                    render: {\n                                      type: 'JSSlot',\n                                      params: ['text', 'record', 'index'],\n                                      value: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocksh96rad1g',\n                                          props: {\n                                            type: 'text',\n                                            children: '',\n                                            icon: {\n                                              type: 'JSSlot',\n                                              value: [\n                                                {\n                                                  componentName: 'Icon',\n                                                  id: 'node_ocksh96rad1j',\n                                                  props: {\n                                                    type: 'ReloadOutlined',\n                                                    size: 14,\n                                                    color: '#0593d3',\n                                                    style: {\n                                                      padding: '3px',\n                                                      border: '1px solid #0593d3',\n                                                      borderRadius: '14px',\n                                                      cursor: 'pointer',\n                                                      height: '22px',\n                                                    },\n                                                    spin: false,\n                                                  },\n                                                },\n                                              ],\n                                            },\n                                            shape: 'circle',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onClick',\n                                                  relatedEventName: 'reload',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onClick',\n                                                  disabled: true,\n                                                },\n                                              ],\n                                            },\n                                            onClick: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    fixed: 'right',\n                                  },\n                                ],\n                                actions: [],\n                                pagination: {\n                                  total: {\n                                    type: 'JSExpression',\n                                    value: 'this.state.total',\n                                  },\n                                  defaultPageSize: 8,\n                                  onPageChange: {\n                                    type: 'JSFunction',\n                                    value: 'function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                  },\n                                },\n                                scrollX: 1200,\n                              },\n                              condition: {\n                                type: 'JSExpression',\n                                value: '!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)',\n                              },\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocksk6f8fa3b',\n              props: {\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocksk6f8fa3c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocksk6f8fa3d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Empty',\n                          id: 'node_ocksk6f8fa3e',\n                          props: {\n                            description: '暂无数据',\n                          },\n                          condition: {\n                            type: 'JSExpression',\n                            value: 'this.state.pkgs.length < 1 && this.state.isSearch',\n                          },\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ]\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"icejs-demo-app\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-router\": \"^5.2.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"intl-messageformat\": \"^9.3.6\",\n    \"@ice/store\": \"^1.4.3\",\n    \"@loadable/component\": \"^5.15.2\",\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"undefined\": \"*\",\n    \"@alilc/antd-lowcode-materials\": \"0.11.0\",\n    \"@alife/mc-assets-1935\": \"0.1.43\",\n    \"@alife/container\": \"0.3.7\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": {\n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": {\n    \"type\": \"react\",\n    \"adapter\": \"adapter-react-v3\"\n  },\n  \"engines\": {\n    \"node\": \">=8.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>Ice App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/app.js",
    "content": "import { createApp } from 'ice';\n\nconst appConfig = {\n  app: {\n    rootId: 'app',\n  },\n  router: {\n    type: 'hash',\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/constants.js",
    "content": "const __$$constants = {};\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import '@alifd/next/reset.scss';\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js",
    "content": "const i18nConfig = {};\n\nlet locale =\n  typeof navigator === 'object' && typeof navigator.language === 'string'\n    ? navigator.language\n    : 'zh-CN';\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst isEmptyVariables = (variables) =>\n  (Array.isArray(variables) && variables.length === 0) ||\n  (typeof variables === 'object' &&\n    (!variables || Object.keys(variables).length === 0));\n\n// 按低代码规范里面的要求进行变量替换\nconst format = (msg, variables) =>\n  typeof msg === 'string'\n    ? msg.replace(/\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '')\n    : msg;\n\nconst i18nFormat = ({ id, defaultMessage, fallback }, variables) => {\n  const msg =\n    i18nConfig[locale]?.[id] ??\n    i18nConfig[locale.replace('-', '_')]?.[id] ??\n    defaultMessage;\n  if (msg == null) {\n    console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);\n    return fallback === undefined ? `${id}` : fallback;\n  }\n\n  return format(msg, variables);\n};\n\nconst i18n = (id, params) => {\n  return i18nFormat({ id }, params);\n};\n\n// 将国际化的一些方法注入到目标对象&上下文中\nconst _inject2 = (target) => {\n  target.i18n = i18n;\n  target.getLocale = getLocale;\n  target.setLocale = (locale) => {\n    setLocale(locale);\n    target.forceUpdate();\n  };\n  target._i18nText = (t) => {\n    // 优先取直接传过来的语料\n    const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];\n    if (localMsg != null) {\n      return format(localMsg, t.params);\n    }\n\n    // 其次用项目级别的\n    const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);\n    if (projectMsg != null) {\n      return projectMsg;\n    }\n\n    // 兜底用 use 指定的或默认语言的\n    return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);\n  };\n\n  // 注入到上下文中去\n  if (target._context && target._context !== target) {\n    Object.assign(target._context, {\n      i18n,\n      getLocale,\n      setLocale: target.setLocale,\n    });\n  }\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat, _inject2 };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.css",
    "content": "body {\n  font-size: 12px;\n}\n\n.botton {\n  width: 100px;\n  color: #ff00ff;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx",
    "content": "// 注意: 出码引擎注入的临时变量默认都以 \"__$$\" 开头，禁止在搭建的代码中直接访问。\n// 例外：react 框架的导出名和各种组件名除外。\nimport React from 'react';\n\nimport {\n  Modal,\n  Button,\n  Typography,\n  Form,\n  Select,\n  Input,\n  Tooltip,\n  Icon,\n  Empty,\n} from '@alilc/antd-lowcode-materials/dist/antd-lowcode.esm.js';\n\nimport {\n  AliAutoDiv,\n  AliAutoSearchTable,\n} from '@alife/mc-assets-1935/build/lowcode/index.js';\n\nimport {\n  Page as NextPage,\n  Block as NextBlock,\n  P as NextP,\n} from '@alife/container/lib/index.js';\n\nimport utils, { RefsManager } from '../../utils';\n\nimport * as __$$i18n from '../../i18n';\n\nimport __$$constants from '../../constants';\n\nimport './index.css';\n\nconst AliAutoDivDefault = AliAutoDiv.default;\n\nconst AliAutoSearchTableDefault = AliAutoSearchTable.default;\n\nconst NextBlockCell = NextBlock.Cell;\n\nclass Test$$Page extends React.Component {\n  _context = this;\n\n  get constants() {\n    return __$$constants || {};\n  }\n\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this._refsManager = new RefsManager();\n\n    __$$i18n._inject2(this);\n\n    this.state = {\n      pkgs: [],\n      total: 0,\n      isSearch: false,\n      projects: [],\n      results: [],\n      resultVisible: false,\n      userOptions: [],\n      searchValues: { user_id: '', channel_id: '' },\n    };\n\n    this.__jp__init();\n    this.statusDesc = {\n      0: '失败',\n      1: '成功',\n      2: '构建中',\n      3: '构建超时',\n    };\n    this.pageParams = {};\n    this.searchParams = {};\n    this.userTimeout = null;\n    this.currentUser = null;\n    this.notFoundContent = null;\n    this.projectTimeout = null;\n    this.currentProject = null;\n  }\n\n  $ = (refName) => {\n    return this._refsManager.get(refName);\n  };\n\n  $$ = (refName) => {\n    return this._refsManager.getAll(refName);\n  };\n\n  componentDidUpdate(prevProps, prevState, snapshot) {}\n\n  componentWillUnmount() {}\n\n  __jp__init() {\n    /*...*/\n  }\n\n  __jp__initRouter() {\n    /*...*/\n  }\n\n  __jp__initDataSource() {\n    /*...*/\n  }\n\n  __jp__initEnv() {\n    /*...*/\n  }\n\n  __jp__initConfig() {\n    /*...*/\n  }\n\n  __jp__initUtils() {\n    /*...*/\n  }\n\n  setSearchItem() {\n    /*...*/\n  }\n\n  fetchProject() {\n    /*...*/\n  }\n\n  handleProjectSearch() {\n    /*...*/\n  }\n\n  handleProjectChange(id) {\n    this.setSearchItem({\n      channel_id: id,\n    });\n  }\n\n  fetchUser() {\n    /*...*/\n  }\n\n  handleUserSearch() {\n    /*...*/\n  }\n\n  handleUserChange(user) {\n    console.log('debug user', user);\n    this.setSearchItem({\n      user_id: user,\n    });\n  }\n\n  fetchPkgs() {\n    /*...*/\n  }\n\n  onPageChange(pageIndex, pageSize) {\n    this.pageParams = {\n      pageIndex,\n      pageSize,\n    };\n    this.fetchPkgs();\n  }\n\n  renderTime(time) {\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n  }\n\n  renderUserName(user) {\n    return user.user_name;\n  }\n\n  reload() {\n    /*...*/\n  }\n\n  handleResult() {\n    /*...*/\n  }\n\n  handleDetail() {\n    /*...*/\n  }\n\n  onResultCancel() {\n    /*...*/\n  }\n\n  formatResult() {\n    /*...*/\n  }\n\n  handleDownload() {\n    /*...*/\n  }\n\n  onFinish() {\n    /*...*/\n  }\n\n  componentDidMount() {\n    this.$ds.resolve('PROJECTS');\n    if (this.userTimeout) {\n      clearTimeout(this.userTimeout);\n      this.userTimeout = null;\n    }\n    if (this.projectTimeout) {\n      clearTimeout(this.projectTimeout);\n      this.projectTimeout = null;\n    }\n  }\n\n  render() {\n    const __$$context = this._context || this;\n    const { state } = __$$context;\n    return (\n      <div\n        ref={this._refsManager.linkRef('outterView')}\n        style={{ height: '100%' }}\n      >\n        <Modal\n          title=\"查看结果\"\n          visible={__$$eval(() => this.state.resultVisible)}\n          footer={\n            <Button\n              type=\"primary\"\n              __events={{\n                eventDataList: [\n                  {\n                    type: 'componentEvent',\n                    name: 'onClick',\n                    relatedEventName: 'onResultCancel',\n                  },\n                ],\n                eventList: [{ name: 'onClick', disabled: true }],\n              }}\n              onClick={function () {\n                this.onResultCancel.apply(\n                  this,\n                  Array.prototype.slice.call(arguments).concat([])\n                );\n              }.bind(this)}\n            >\n              确定\n            </Button>\n          }\n          __events={{\n            eventDataList: [\n              {\n                type: 'componentEvent',\n                name: 'onCancel',\n                relatedEventName: 'onResultCancel',\n              },\n            ],\n            eventList: [\n              { name: 'onCancel', disabled: true },\n              { name: 'onOk', disabled: false },\n            ],\n          }}\n          onCancel={function () {\n            this.onResultCancel.apply(\n              this,\n              Array.prototype.slice.call(arguments).concat([])\n            );\n          }.bind(this)}\n          width=\"720px\"\n          centered={true}\n          closable={true}\n          keyboard={true}\n          mask={true}\n          maskClosable={true}\n        >\n          <AliAutoDivDefault style={{ width: '100%' }}>\n            {!!__$$eval(\n              () => this.state.results && this.state.results.length > 0\n            ) && (\n              <AliAutoDivDefault\n                style={{\n                  width: '100%',\n                  textAlign: 'left',\n                  marginBottom: '16px',\n                }}\n              >\n                <Button\n                  type=\"primary\"\n                  size=\"small\"\n                  __events={{\n                    eventDataList: [\n                      {\n                        type: 'componentEvent',\n                        name: 'onClick',\n                        relatedEventName: 'handleDownload',\n                      },\n                    ],\n                    eventList: [{ name: 'onClick', disabled: true }],\n                  }}\n                  onClick={function () {\n                    this.handleDownload.apply(\n                      this,\n                      Array.prototype.slice.call(arguments).concat([])\n                    );\n                  }.bind(this)}\n                >\n                  下载全部\n                </Button>\n              </AliAutoDivDefault>\n            )}\n            {__$$evalArray(() => this.state.results).map((item, index) =>\n              ((__$$context) => (\n                <AliAutoDivDefault style={{ width: '100%', marginTop: '10px' }}>\n                  <Typography.Text>\n                    {__$$eval(() => __$$context.formatResult(item))}\n                  </Typography.Text>\n                  {!!__$$eval(() => item.download_link) && (\n                    <Typography.Link\n                      href={__$$eval(() => item.download_link)}\n                      target=\"_blank\"\n                    >\n                      {' '}\n                      - 点击下载\n                    </Typography.Link>\n                  )}\n                  {!!__$$eval(() => item.release_notes) && (\n                    <Typography.Link\n                      href={__$$eval(() => item.release_notes)}\n                      target=\"_blank\"\n                    >\n                      {' '}\n                      - 跳转发布节点\n                    </Typography.Link>\n                  )}\n                </AliAutoDivDefault>\n              ))(__$$createChildContext(__$$context, { item, index }))\n            )}\n          </AliAutoDivDefault>\n        </Modal>\n        <NextPage\n          columns={12}\n          headerDivider={true}\n          placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }}\n          placeholder=\"页面主体内容：拖拽Block布局组件到这里\"\n          header={null}\n          headerProps={{ background: 'surface', style: { padding: '' } }}\n          footer={null}\n          minHeight=\"100vh\"\n          contentProps={{ noPadding: false, background: 'transparent' }}\n        >\n          <NextBlock childTotalColumns={12}>\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                <AliAutoDivDefault style={{ width: '100%', display: 'flex' }}>\n                  <AliAutoDivDefault style={{ flex: '1' }}>\n                    <Form\n                      labelCol={{ span: 10 }}\n                      wrapperCol={{ span: 14 }}\n                      onFinish={function () {\n                        this.onFinish.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this)}\n                      name=\"basic\"\n                      layout=\"inline\"\n                      __events={{\n                        eventDataList: [\n                          {\n                            type: 'componentEvent',\n                            name: 'onFinish',\n                            relatedEventName: 'onFinish',\n                          },\n                        ],\n                        eventList: [\n                          { name: 'onFinish', disabled: true },\n                          { name: 'onFinishFailed', disabled: false },\n                          { name: 'onFieldsChange', disabled: false },\n                          { name: 'onValuesChange', disabled: false },\n                        ],\n                      }}\n                      colon={true}\n                      labelAlign=\"right\"\n                      preserve={true}\n                      scrollToFirstError={true}\n                      size=\"middle\"\n                      values={__$$eval(() => this.state.searchValues)}\n                    >\n                      <Form.Item\n                        label=\"项目名称/渠道号\"\n                        name=\"channel_id\"\n                        labelAlign=\"right\"\n                        colon={true}\n                      >\n                        <Select\n                          style={{ width: '320px' }}\n                          options={__$$eval(() => this.state.projects)}\n                          showArrow={false}\n                          tokenSeparators={[]}\n                          showSearch={true}\n                          defaultActiveFirstOption={true}\n                          size=\"middle\"\n                          bordered={true}\n                          filterOption={true}\n                          optionFilterProp=\"label\"\n                          allowClear={true}\n                          placeholder=\"请输入项目名称/渠道号\"\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onChange',\n                                relatedEventName: 'handleProjectChange',\n                              },\n                              {\n                                type: 'componentEvent',\n                                name: 'onSearch',\n                                relatedEventName: 'handleProjectSearch',\n                              },\n                            ],\n                            eventList: [\n                              { name: 'onBlur', disabled: false },\n                              { name: 'onChange', disabled: true },\n                              { name: 'onDeselect', disabled: false },\n                              { name: 'onFocus', disabled: false },\n                              { name: 'onInputKeyDown', disabled: false },\n                              { name: 'onMouseEnter', disabled: false },\n                              { name: 'onMouseLeave', disabled: false },\n                              { name: 'onPopupScroll', disabled: false },\n                              { name: 'onSearch', disabled: true },\n                              { name: 'onSelect', disabled: false },\n                              {\n                                name: 'onDropdownVisibleChange',\n                                disabled: false,\n                              },\n                            ],\n                          }}\n                          onChange={function () {\n                            this.handleProjectChange.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                          onSearch={function () {\n                            this.handleProjectSearch.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                        />\n                      </Form.Item>\n                      <Form.Item label=\"版本号\" name=\"buildId\">\n                        <Input\n                          placeholder=\"请输入版本号\"\n                          style={{ width: '180px' }}\n                          size=\"middle\"\n                          bordered={true}\n                        />\n                      </Form.Item>\n                      <Form.Item label=\"构建人\" name=\"user_id\">\n                        <Select\n                          style={{ width: '210px' }}\n                          options={__$$eval(() => this.state.userOptions)}\n                          showSearch={true}\n                          defaultActiveFirstOption={false}\n                          size=\"middle\"\n                          bordered={true}\n                          filterOption={true}\n                          optionFilterProp=\"label\"\n                          notFoundContent={__$$eval(\n                            () => this.userNotFoundContent\n                          )}\n                          showArrow={false}\n                          placeholder=\"请输入构建人\"\n                          __events={{\n                            eventDataList: [\n                              {\n                                type: 'componentEvent',\n                                name: 'onChange',\n                                relatedEventName: 'handleUserChange',\n                              },\n                              {\n                                type: 'componentEvent',\n                                name: 'onSearch',\n                                relatedEventName: 'handleUserSearch',\n                              },\n                            ],\n                            eventList: [\n                              { name: 'onBlur', disabled: false },\n                              { name: 'onChange', disabled: true },\n                              { name: 'onDeselect', disabled: false },\n                              { name: 'onFocus', disabled: false },\n                              { name: 'onInputKeyDown', disabled: false },\n                              { name: 'onMouseEnter', disabled: false },\n                              { name: 'onMouseLeave', disabled: false },\n                              { name: 'onPopupScroll', disabled: false },\n                              { name: 'onSearch', disabled: true },\n                              { name: 'onSelect', disabled: false },\n                              {\n                                name: 'onDropdownVisibleChange',\n                                disabled: false,\n                              },\n                            ],\n                          }}\n                          onChange={function () {\n                            this.handleUserChange.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                          onSearch={function () {\n                            this.handleUserSearch.apply(\n                              this,\n                              Array.prototype.slice.call(arguments).concat([])\n                            );\n                          }.bind(this)}\n                          allowClear={true}\n                        />\n                      </Form.Item>\n                      <Form.Item\n                        label=\"ID\"\n                        name=\"id\"\n                        labelAlign=\"right\"\n                        colon={true}\n                      >\n                        <Input\n                          placeholder=\"请输入ID\"\n                          style={{ width: '180px' }}\n                          bordered={true}\n                          size=\"middle\"\n                        />\n                      </Form.Item>\n                      <Form.Item\n                        wrapperCol={{ offset: 6 }}\n                        labelAlign=\"right\"\n                        colon={true}\n                        style={{ flex: '1', textAlign: 'right' }}\n                      >\n                        <Button\n                          type=\"primary\"\n                          htmlType=\"submit\"\n                          shape=\"default\"\n                          size=\"middle\"\n                        >\n                          查询\n                        </Button>\n                      </Form.Item>\n                    </Form>\n                  </AliAutoDivDefault>\n                  <AliAutoDivDefault style={{}}>\n                    <Button\n                      type=\"link\"\n                      htmlType=\"button\"\n                      shape=\"default\"\n                      size=\"middle\"\n                    >\n                      新增打包\n                    </Button>\n                  </AliAutoDivDefault>\n                </AliAutoDivDefault>\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock\n            childTotalColumns={12}\n            mode=\"inset\"\n            layoutmode=\"O\"\n            autolayout=\"(12|1)\"\n          >\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                {!!__$$eval(\n                  () =>\n                    !this.state.isSearch ||\n                    (this.state.isSearch && this.state.pkgs.length > 0)\n                ) && (\n                  <AliAutoSearchTableDefault\n                    rowKey=\"key\"\n                    dataSource={__$$eval(() => this.state.pkgs)}\n                    columns={[\n                      { title: 'ID', dataIndex: 'id', key: 'name', width: 80 },\n                      {\n                        title: '渠道号',\n                        dataIndex: 'channels',\n                        key: 'age',\n                        width: 142,\n                        render: (text, record, index) =>\n                          ((__$$context) =>\n                            __$$evalArray(() => text.split(',')).map(\n                              (item, index) =>\n                                ((__$$context) => (\n                                  <Typography.Text style={{ display: 'block' }}>\n                                    {__$$eval(() => item)}\n                                  </Typography.Text>\n                                ))(\n                                  __$$createChildContext(__$$context, {\n                                    item,\n                                    index,\n                                  })\n                                )\n                            ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                      },\n                      {\n                        title: '版本号',\n                        dataIndex: 'dic_version',\n                        key: 'address',\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Tooltip\n                              title={__$$evalArray(() => text || []).map(\n                                (item, index) =>\n                                  ((__$$context) => (\n                                    <Typography.Text\n                                      style={{\n                                        display: 'block',\n                                        color: '#FFFFFF',\n                                      }}\n                                    >\n                                      {__$$eval(\n                                        () =>\n                                          item.channelId + ' / ' + item.version\n                                      )}\n                                    </Typography.Text>\n                                  ))(\n                                    __$$createChildContext(__$$context, {\n                                      item,\n                                      index,\n                                    })\n                                  )\n                              )}\n                            >\n                              <Typography.Text>\n                                {__$$eval(() => text[0].version)}\n                              </Typography.Text>\n                            </Tooltip>\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 120,\n                      },\n                      { title: '构建Job', dataIndex: 'job_name', width: 180 },\n                      {\n                        title: '构建类型',\n                        dataIndex: 'packaging_type',\n                        width: 94,\n                      },\n                      {\n                        title: '构建状态',\n                        dataIndex: 'status',\n                        render: (text, record, index) =>\n                          ((__$$context) => [\n                            <Typography.Text>\n                              {__$$eval(() => __$$context.statusDesc[text])}\n                            </Typography.Text>,\n                            !!__$$eval(() => text === 2) && (\n                              <Icon\n                                type=\"SyncOutlined\"\n                                size={16}\n                                spin={true}\n                                style={{ marginLeft: '10px' }}\n                              />\n                            ),\n                          ])(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 100,\n                      },\n                      {\n                        title: '构建时间',\n                        dataIndex: 'start_time',\n                        render: function () {\n                          return this.renderTime.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this),\n                        width: 148,\n                      },\n                      {\n                        title: '构建人',\n                        dataIndex: 'user',\n                        render: function () {\n                          return this.renderUserName.apply(\n                            this,\n                            Array.prototype.slice.call(arguments).concat([])\n                          );\n                        }.bind(this),\n                        width: 80,\n                      },\n                      {\n                        title: 'Jenkins 链接',\n                        dataIndex: 'jenkins_link',\n                        render: (text, record, index) =>\n                          ((__$$context) => [\n                            !!__$$eval(() => text) && (\n                              <Typography.Link\n                                href={__$$eval(() => text)}\n                                target=\"_blank\"\n                              >\n                                查看\n                              </Typography.Link>\n                            ),\n                            !!__$$eval(() => !text) && (\n                              <Typography.Text>暂无</Typography.Text>\n                            ),\n                          ])(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 120,\n                      },\n                      {\n                        title: '测试平台链接',\n                        dataIndex: 'is_run_testing',\n                        width: 120,\n                        render: (text, record, index) =>\n                          ((__$$context) => [\n                            !!__$$eval(() => text) && (\n                              <Typography.Link\n                                href=\"http://rivermap.alibaba.net/dashboard/testExecute\"\n                                target=\"_blank\"\n                              >\n                                查看\n                              </Typography.Link>\n                            ),\n                            !!__$$eval(() => !text) && (\n                              <Typography.Text>暂无</Typography.Text>\n                            ),\n                          ])(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                      },\n                      { title: '触发源', dataIndex: 'source', width: 120 },\n                      {\n                        title: '详情',\n                        dataIndex: 'id',\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Button\n                              type=\"link\"\n                              size=\"small\"\n                              style={{ padding: '0px' }}\n                              __events={{\n                                eventDataList: [\n                                  {\n                                    type: 'componentEvent',\n                                    name: 'onClick',\n                                    relatedEventName: 'handleDetail',\n                                  },\n                                ],\n                                eventList: [\n                                  { name: 'onClick', disabled: true },\n                                ],\n                              }}\n                              onClick={function () {\n                                this.handleDetail.apply(\n                                  this,\n                                  Array.prototype.slice\n                                    .call(arguments)\n                                    .concat([])\n                                );\n                              }.bind(__$$context)}\n                            >\n                              查看\n                            </Button>\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 80,\n                        fixed: 'right',\n                      },\n                      {\n                        title: '结果',\n                        dataIndex: 'id',\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Button\n                              type=\"link\"\n                              size=\"small\"\n                              style={{ padding: '0px' }}\n                              __events={{\n                                eventDataList: [\n                                  {\n                                    type: 'componentEvent',\n                                    name: 'onClick',\n                                    relatedEventName: 'handleResult',\n                                    paramStr: 'this.text',\n                                  },\n                                ],\n                                eventList: [\n                                  { name: 'onClick', disabled: true },\n                                ],\n                              }}\n                              onClick={function () {\n                                this.handleResult.apply(\n                                  this,\n                                  Array.prototype.slice\n                                    .call(arguments)\n                                    .concat([])\n                                );\n                              }.bind(__$$context)}\n                              ghost={false}\n                              href={__$$eval(() => text)}\n                            >\n                              查看\n                            </Button>\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        width: 80,\n                        fixed: 'right',\n                      },\n                      {\n                        title: '重新执行',\n                        dataIndex: 'id',\n                        width: 92,\n                        render: (text, record, index) =>\n                          ((__$$context) => (\n                            <Button\n                              type=\"text\"\n                              children=\"\"\n                              icon={\n                                <Icon\n                                  type=\"ReloadOutlined\"\n                                  size={14}\n                                  color=\"#0593d3\"\n                                  style={{\n                                    padding: '3px',\n                                    border: '1px solid #0593d3',\n                                    borderRadius: '14px',\n                                    cursor: 'pointer',\n                                    height: '22px',\n                                  }}\n                                  spin={false}\n                                />\n                              }\n                              shape=\"circle\"\n                              __events={{\n                                eventDataList: [\n                                  {\n                                    type: 'componentEvent',\n                                    name: 'onClick',\n                                    relatedEventName: 'reload',\n                                  },\n                                ],\n                                eventList: [\n                                  { name: 'onClick', disabled: true },\n                                ],\n                              }}\n                              onClick={function () {\n                                this.reload.apply(\n                                  this,\n                                  Array.prototype.slice\n                                    .call(arguments)\n                                    .concat([])\n                                );\n                              }.bind(__$$context)}\n                            />\n                          ))(\n                            __$$createChildContext(__$$context, {\n                              text,\n                              record,\n                              index,\n                            })\n                          ),\n                        fixed: 'right',\n                      },\n                    ]}\n                    actions={[]}\n                    pagination={{\n                      total: __$$eval(() => this.state.total),\n                      defaultPageSize: 10,\n                      onPageChange: function () {\n                        return this.onPageChange.apply(\n                          this,\n                          Array.prototype.slice.call(arguments).concat([])\n                        );\n                      }.bind(this),\n                      defaultPageIndex: 1,\n                    }}\n                    scrollX={1200}\n                    isPagination={true}\n                  />\n                )}\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n          <NextBlock\n            childTotalColumns={12}\n            mode=\"inset\"\n            layoutmode=\"O\"\n            autolayout=\"(12|1)\"\n          >\n            <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}>\n              <NextP\n                wrap={false}\n                type=\"body2\"\n                verAlign=\"middle\"\n                textSpacing={true}\n                align=\"left\"\n                flex={true}\n              >\n                {!!__$$eval(\n                  () => this.state.pkgs.length < 1 && this.state.isSearch\n                ) && <Empty description=\"暂无数据\" />}\n              </NextP>\n            </NextBlockCell>\n          </NextBlock>\n        </NextPage>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n\nfunction __$$eval(expr) {\n  try {\n    return expr();\n  } catch (error) {}\n}\n\nfunction __$$evalArray(expr) {\n  const res = __$$eval(expr);\n  return Array.isArray(res) ? res : [];\n}\n\nfunction __$$createChildContext(oldContext, ext) {\n  const childContext = {\n    ...oldContext,\n    ...ext,\n  };\n  childContext.__proto__ = oldContext;\n  return childContext;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/routes.js",
    "content": "import Test from '@/pages/Test';\n\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst routerConfig = [\n  {\n    path: '/',\n    component: BasicLayout,\n    children: [\n      {\n        path: '',\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/utils.js",
    "content": "import { createRef } from 'react';\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/schema.json5",
    "content": "{\n  version: '1.0.0',\n  componentsMap: [\n    {\n      devMode: 'lowcode',\n      componentName: 'Slot',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Button',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Button',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.43',\n      exportName: 'AliAutoDiv',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoDivDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Text',\n      componentName: 'Typography.Text',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Typography',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Link',\n      componentName: 'Typography.Link',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Modal',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Modal',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Select',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Select',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      subName: 'Item',\n      componentName: 'Form.Item',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Input',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Input',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Form',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Form',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'P',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextP',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: 'Cell',\n      componentName: 'NextBlockCell',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Block',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextBlock',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Tooltip',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Tooltip',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Icon',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Icon',\n    },\n    {\n      package: '@alife/mc-assets-1935',\n      version: '0.1.43',\n      exportName: 'AliAutoSearchTable',\n      main: 'build/lowcode/index.js',\n      destructuring: true,\n      subName: 'default',\n      componentName: 'AliAutoSearchTableDefault',\n    },\n    {\n      package: '@alilc/antd-lowcode-materials',\n      version: '0.11.0',\n      exportName: 'Empty',\n      main: 'dist/antd-lowcode.esm.js',\n      destructuring: true,\n      componentName: 'Empty',\n    },\n    {\n      package: '@alife/container',\n      version: '0.3.7',\n      exportName: 'Page',\n      main: 'lib/index.js',\n      destructuring: true,\n      subName: '',\n      componentName: 'NextPage',\n    },\n    {\n      devMode: 'lowcode',\n      componentName: 'Page',\n    },\n  ],\n  componentsTree: [\n    {\n      componentName: 'Page',\n      id: 'node_dockcviv8fo1',\n      props: {\n        ref: 'outterView',\n        style: {\n          height: '100%',\n        },\n      },\n      fileName: 'test',\n      dataSource: {\n        list: [],\n      },\n      css: 'body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}',\n      lifeCycles: {\n        constructor: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.__jp__init();\\n    this.statusDesc = {\\n      0: '失败',\\n      1: '成功',\\n      2: '构建中',\\n      3: '构建超时',\\n    };\\n    this.pageParams = {};\\n    this.searchParams = {};\\n    this.userTimeout = null;\\n    this.currentUser = null;\\n    this.notFoundContent = null;\\n    this.projectTimeout = null;\\n    this.currentProject = null;\\n  }\",\n        },\n        componentDidMount: {\n          type: 'JSFunction',\n          value: \"function() {\\n    this.$ds.resolve('PROJECTS');\\n    if (this.userTimeout) {\\n      clearTimeout(this.userTimeout);\\n      this.userTimeout = null;\\n    }\\n    if (this.projectTimeout) {\\n      clearTimeout(this.projectTimeout);\\n      this.projectTimeout = null;\\n    }\\n  }\",\n        },\n        componentDidUpdate: {\n          type: 'JSFunction',\n          value: 'function(prevProps, prevState, snapshot) {}',\n        },\n        componentWillUnmount: {\n          type: 'JSFunction',\n          value: 'function() {}',\n        },\n      },\n      methods: {\n        __jp__init: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initRouter: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initDataSource: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initEnv: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initConfig: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        __jp__initUtils: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        setSearchItem: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        fetchProject: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleProjectSearch: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleProjectChange: {\n          type: 'JSFunction',\n          value: 'function(id) {\\n    this.setSearchItem({\\n      channel_id: id,\\n    });\\n  }',\n        },\n        fetchUser: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleUserSearch: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleUserChange: {\n          type: 'JSFunction',\n          value: \"function(user) {\\n    console.log('debug user', user);\\n    this.setSearchItem({\\n      user_id: user,\\n    });\\n  }\",\n        },\n        fetchPkgs: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onPageChange: {\n          type: 'JSFunction',\n          value: 'function(pageIndex, pageSize) {\\n    this.pageParams = {\\n      pageIndex,\\n      pageSize,\\n    };\\n    this.fetchPkgs();\\n  }',\n        },\n        renderTime: {\n          type: 'JSFunction',\n          value: \"function(time) {\\n    return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\\n  }\",\n        },\n        renderUserName: {\n          type: 'JSFunction',\n          value: 'function(user) {\\n    return user.user_name;\\n  }',\n        },\n        reload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleResult: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleDetail: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onResultCancel: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        formatResult: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        handleDownload: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n        onFinish: {\n          type: 'JSFunction',\n          value: 'function() { /*...*/ }',\n        },\n      },\n      state: {\n        pkgs: [],\n        total: 0,\n        isSearch: false,\n        projects: [],\n        results: [],\n        resultVisible: false,\n        userOptions: [],\n        searchValues: {\n          user_id: '',\n          channel_id: '',\n        },\n      },\n      children: [\n        {\n          componentName: 'Modal',\n          id: 'node_ocksh9yppxb',\n          props: {\n            title: '查看结果',\n            visible: {\n              type: 'JSExpression',\n              value: 'this.state.resultVisible',\n            },\n            footer: {\n              type: 'JSSlot',\n              value: [\n                {\n                  componentName: 'Button',\n                  id: 'node_ocksh9yppxf',\n                  props: {\n                    type: 'primary',\n                    children: '确定',\n                    __events: {\n                      eventDataList: [\n                        {\n                          type: 'componentEvent',\n                          name: 'onClick',\n                          relatedEventName: 'onResultCancel',\n                        },\n                      ],\n                      eventList: [\n                        {\n                          name: 'onClick',\n                          disabled: true,\n                        },\n                      ],\n                    },\n                    onClick: {\n                      type: 'JSFunction',\n                      value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                    },\n                  },\n                },\n              ],\n            },\n            __events: {\n              eventDataList: [\n                {\n                  type: 'componentEvent',\n                  name: 'onCancel',\n                  relatedEventName: 'onResultCancel',\n                },\n              ],\n              eventList: [\n                {\n                  name: 'onCancel',\n                  disabled: true,\n                },\n                {\n                  name: 'onOk',\n                  disabled: false,\n                },\n              ],\n            },\n            onCancel: {\n              type: 'JSFunction',\n              value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n            },\n            width: '720px',\n            centered: true,\n            closable: true,\n            keyboard: true,\n            mask: true,\n            maskClosable: true,\n          },\n          hidden: true,\n          children: [\n            {\n              componentName: 'AliAutoDivDefault',\n              id: 'node_ockshazuxa4',\n              props: {\n                style: {\n                  width: '100%',\n                },\n              },\n              children: [\n                {\n                  componentName: 'AliAutoDivDefault',\n                  id: 'node_ockshazuxai',\n                  props: {\n                    style: {\n                      width: '100%',\n                      textAlign: 'left',\n                      marginBottom: '16px',\n                    },\n                  },\n                  condition: {\n                    type: 'JSExpression',\n                    value: 'this.state.results && this.state.results.length > 0',\n                  },\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node_ockshazuxah',\n                      props: {\n                        type: 'primary',\n                        children: '下载全部',\n                        size: 'small',\n                        __events: {\n                          eventDataList: [\n                            {\n                              type: 'componentEvent',\n                              name: 'onClick',\n                              relatedEventName: 'handleDownload',\n                            },\n                          ],\n                          eventList: [\n                            {\n                              name: 'onClick',\n                              disabled: true,\n                            },\n                          ],\n                        },\n                        onClick: {\n                          type: 'JSFunction',\n                          value: 'function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'AliAutoDivDefault',\n                  id: 'node_ockt2muyfi4',\n                  props: {\n                    style: {\n                      width: '100%',\n                      marginTop: '10px',\n                    },\n                  },\n                  loop: {\n                    type: 'JSExpression',\n                    value: 'this.state.results',\n                  },\n                  children: [\n                    {\n                      componentName: 'Typography.Text',\n                      id: 'node_ockshazuxa5',\n                      props: {\n                        children: {\n                          type: 'JSExpression',\n                          value: 'this.formatResult(this.item)',\n                        },\n                      },\n                    },\n                    {\n                      componentName: 'Typography.Link',\n                      id: 'node_ockshazuxa6',\n                      props: {\n                        href: {\n                          type: 'JSExpression',\n                          value: 'this.item.download_link',\n                        },\n                        target: '_blank',\n                        children: ' - 点击下载',\n                      },\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.item.download_link',\n                      },\n                    },\n                    {\n                      componentName: 'Typography.Link',\n                      id: 'node_ockshazuxa7',\n                      props: {\n                        href: {\n                          type: 'JSExpression',\n                          value: 'this.item.release_notes',\n                        },\n                        target: '_blank',\n                        children: ' - 跳转发布节点',\n                      },\n                      condition: {\n                        type: 'JSExpression',\n                        value: 'this.item.release_notes',\n                      },\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'NextPage',\n          id: 'node_ocko19zplh1',\n          props: {\n            columns: 12,\n            headerDivider: true,\n            placeholderStyle: {\n              gridRowEnd: 'span 1',\n              gridColumnEnd: 'span 12',\n            },\n            placeholder: '页面主体内容：拖拽Block布局组件到这里',\n            header: {\n              type: 'JSSlot',\n              title: 'header',\n            },\n            headerProps: {\n              background: 'surface',\n              style: {\n                padding: '',\n              },\n            },\n            footer: {\n              type: 'JSSlot',\n              title: 'footer',\n            },\n            minHeight: '100vh',\n            contentProps: {\n              noPadding: false,\n              background: 'transparent',\n            },\n          },\n          title: '页面',\n          children: [\n            {\n              componentName: 'NextBlock',\n              id: 'node_ockt3t4q8565',\n              props: {\n                childTotalColumns: 12,\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ockt3t4q8566',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockt3t4q8567',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'AliAutoDivDefault',\n                          id: 'node_ockt3t4q8568',\n                          props: {\n                            style: {\n                              width: '100%',\n                              display: 'flex',\n                            },\n                          },\n                          children: [\n                            {\n                              componentName: 'AliAutoDivDefault',\n                              id: 'node_ockt3t4q857a',\n                              props: {\n                                style: {\n                                  flex: '1',\n                                },\n                              },\n                              children: [\n                                {\n                                  componentName: 'Form',\n                                  id: 'node_ocks8dtt1mt',\n                                  props: {\n                                    labelCol: {\n                                      span: 10,\n                                    },\n                                    wrapperCol: {\n                                      span: 14,\n                                    },\n                                    onFinish: {\n                                      type: 'JSFunction',\n                                      value: 'function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                    },\n                                    name: 'basic',\n                                    layout: 'inline',\n                                    __events: {\n                                      eventDataList: [\n                                        {\n                                          type: 'componentEvent',\n                                          name: 'onFinish',\n                                          relatedEventName: 'onFinish',\n                                        },\n                                      ],\n                                      eventList: [\n                                        {\n                                          name: 'onFinish',\n                                          disabled: true,\n                                        },\n                                        {\n                                          name: 'onFinishFailed',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onFieldsChange',\n                                          disabled: false,\n                                        },\n                                        {\n                                          name: 'onValuesChange',\n                                          disabled: false,\n                                        },\n                                      ],\n                                    },\n                                    colon: true,\n                                    labelAlign: 'right',\n                                    preserve: true,\n                                    scrollToFirstError: true,\n                                    size: 'middle',\n                                    values: {\n                                      type: 'JSExpression',\n                                      value: 'this.state.searchValues',\n                                    },\n                                  },\n                                  children: [\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1mz',\n                                      props: {\n                                        label: '项目名称/渠道号',\n                                        name: 'channel_id',\n                                        labelAlign: 'right',\n                                        colon: true,\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Select',\n                                          id: 'node_ocksfuhwhsd',\n                                          props: {\n                                            style: {\n                                              width: '320px',\n                                            },\n                                            options: {\n                                              type: 'JSExpression',\n                                              value: 'this.state.projects',\n                                            },\n                                            showArrow: false,\n                                            tokenSeparators: [],\n                                            showSearch: true,\n                                            defaultActiveFirstOption: true,\n                                            size: 'middle',\n                                            bordered: true,\n                                            filterOption: true,\n                                            optionFilterProp: 'label',\n                                            allowClear: true,\n                                            placeholder: '请输入项目名称/渠道号',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onChange',\n                                                  relatedEventName: 'handleProjectChange',\n                                                },\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onSearch',\n                                                  relatedEventName: 'handleProjectSearch',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onBlur',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onChange',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onDeselect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onFocus',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onInputKeyDown',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseEnter',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseLeave',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onPopupScroll',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onSearch',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onSelect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onDropdownVisibleChange',\n                                                  disabled: false,\n                                                },\n                                              ],\n                                            },\n                                            onChange: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleProjectChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            onSearch: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleProjectSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1m12',\n                                      props: {\n                                        label: '版本号',\n                                        name: 'buildId',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Input',\n                                          id: 'node_ocksfuhwhs3',\n                                          props: {\n                                            placeholder: '请输入版本号',\n                                            style: {\n                                              width: '180px',\n                                            },\n                                            size: 'middle',\n                                            bordered: true,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1m18',\n                                      props: {\n                                        label: '构建人',\n                                        name: 'user_id',\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Select',\n                                          id: 'node_ocksfuhwhsi',\n                                          props: {\n                                            style: {\n                                              width: '210px',\n                                            },\n                                            options: {\n                                              type: 'JSExpression',\n                                              value: 'this.state.userOptions',\n                                            },\n                                            showSearch: true,\n                                            defaultActiveFirstOption: false,\n                                            size: 'middle',\n                                            bordered: true,\n                                            filterOption: true,\n                                            optionFilterProp: 'label',\n                                            notFoundContent: {\n                                              type: 'JSExpression',\n                                              value: 'this.userNotFoundContent',\n                                            },\n                                            showArrow: false,\n                                            placeholder: '请输入构建人',\n                                            __events: {\n                                              eventDataList: [\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onChange',\n                                                  relatedEventName: 'handleUserChange',\n                                                },\n                                                {\n                                                  type: 'componentEvent',\n                                                  name: 'onSearch',\n                                                  relatedEventName: 'handleUserSearch',\n                                                },\n                                              ],\n                                              eventList: [\n                                                {\n                                                  name: 'onBlur',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onChange',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onDeselect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onFocus',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onInputKeyDown',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseEnter',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onMouseLeave',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onPopupScroll',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onSearch',\n                                                  disabled: true,\n                                                },\n                                                {\n                                                  name: 'onSelect',\n                                                  disabled: false,\n                                                },\n                                                {\n                                                  name: 'onDropdownVisibleChange',\n                                                  disabled: false,\n                                                },\n                                              ],\n                                            },\n                                            onChange: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleUserChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            onSearch: {\n                                              type: 'JSFunction',\n                                              value: 'function(){this.handleUserSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                            },\n                                            allowClear: true,\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1m19',\n                                      props: {\n                                        label: 'ID',\n                                        name: 'id',\n                                        labelAlign: 'right',\n                                        colon: true,\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Input',\n                                          id: 'node_ocksfuhwhs8',\n                                          props: {\n                                            placeholder: '请输入ID',\n                                            style: {\n                                              width: '180px',\n                                            },\n                                            bordered: true,\n                                            size: 'middle',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                    {\n                                      componentName: 'Form.Item',\n                                      id: 'node_ocks8dtt1mw',\n                                      props: {\n                                        wrapperCol: {\n                                          offset: 6,\n                                        },\n                                        labelAlign: 'right',\n                                        colon: true,\n                                        style: {\n                                          flex: '1',\n                                          textAlign: 'right',\n                                        },\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Button',\n                                          id: 'node_ocks8dtt1mx',\n                                          props: {\n                                            type: 'primary',\n                                            children: '查询',\n                                            htmlType: 'submit',\n                                            shape: 'default',\n                                            size: 'middle',\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  ],\n                                },\n                              ],\n                            },\n                            {\n                              componentName: 'AliAutoDivDefault',\n                              id: 'node_ockt3t4q856b',\n                              props: {\n                                style: {},\n                              },\n                              children: [\n                                {\n                                  componentName: 'Button',\n                                  id: 'node_ockt3t4q85y',\n                                  props: {\n                                    type: 'link',\n                                    children: '新增打包',\n                                    htmlType: 'button',\n                                    shape: 'default',\n                                    size: 'middle',\n                                  },\n                                  condition: true,\n                                },\n                              ],\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ockshc4ifn1b',\n              props: {\n                childTotalColumns: 12,\n                mode: 'inset',\n                layoutmode: 'O',\n                autolayout: '(12|1)',\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ockshc4ifn1c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ockshc4ifn1d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'AliAutoSearchTableDefault',\n                          id: 'node_ocksfuhwhsx',\n                          props: {\n                            rowKey: 'key',\n                            dataSource: {\n                              type: 'JSExpression',\n                              value: 'this.state.pkgs',\n                            },\n                            columns: [\n                              {\n                                title: 'ID',\n                                dataIndex: 'id',\n                                key: 'name',\n                                width: 80,\n                              },\n                              {\n                                title: '渠道号',\n                                dataIndex: 'channels',\n                                key: 'age',\n                                width: 142,\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh2bq0428',\n                                      props: {\n                                        children: {\n                                          type: 'JSExpression',\n                                          value: 'this.item',\n                                        },\n                                        style: {\n                                          display: 'block',\n                                        },\n                                      },\n                                      loop: {\n                                        type: 'JSExpression',\n                                        value: \"this.text.split(',')\",\n                                      },\n                                    },\n                                  ],\n                                },\n                              },\n                              {\n                                title: '版本号',\n                                dataIndex: 'dic_version',\n                                key: 'address',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Tooltip',\n                                      id: 'node_ocksts0jqgj',\n                                      props: {\n                                        title: {\n                                          type: 'JSSlot',\n                                          value: [\n                                            {\n                                              componentName: 'Typography.Text',\n                                              id: 'node_ocksts0jqgn',\n                                              props: {\n                                                children: {\n                                                  type: 'JSExpression',\n                                                  value: \"this.item. channelId + ' / ' +  this.item.version\",\n                                                },\n                                                style: {\n                                                  display: 'block',\n                                                  color: '#FFFFFF',\n                                                },\n                                              },\n                                              loop: {\n                                                type: 'JSExpression',\n                                                value: 'this.text || []',\n                                              },\n                                            },\n                                          ],\n                                        },\n                                      },\n                                      children: [\n                                        {\n                                          componentName: 'Typography.Text',\n                                          id: 'node_ocksts0jqgm',\n                                          props: {\n                                            children: {\n                                              type: 'JSExpression',\n                                              value: 'this.text[0].version',\n                                            },\n                                          },\n                                        },\n                                      ],\n                                    },\n                                  ],\n                                },\n                                width: 120,\n                              },\n                              {\n                                title: '构建Job',\n                                dataIndex: 'job_name',\n                                width: 180,\n                              },\n                              {\n                                title: '构建类型',\n                                dataIndex: 'packaging_type',\n                                width: 94,\n                              },\n                              {\n                                title: '构建状态',\n                                dataIndex: 'status',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh3jkxzw',\n                                      props: {\n                                        children: {\n                                          type: 'JSExpression',\n                                          value: 'this.statusDesc[this.text]',\n                                        },\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Icon',\n                                      id: 'node_ocksh3jkxzx',\n                                      props: {\n                                        type: 'SyncOutlined',\n                                        size: 16,\n                                        spin: true,\n                                        style: {\n                                          marginLeft: '10px',\n                                        },\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: 'this.text === 2',\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 100,\n                              },\n                              {\n                                title: '构建时间',\n                                dataIndex: 'start_time',\n                                render: {\n                                  type: 'JSFunction',\n                                  value: 'function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                                width: 148,\n                              },\n                              {\n                                title: '构建人',\n                                dataIndex: 'user',\n                                render: {\n                                  type: 'JSFunction',\n                                  value: 'function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                },\n                                width: 80,\n                              },\n                              {\n                                title: 'Jenkins 链接',\n                                dataIndex: 'jenkins_link',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Link',\n                                      id: 'node_ocksh64kbx21',\n                                      props: {\n                                        href: {\n                                          type: 'JSExpression',\n                                          value: 'this.text',\n                                        },\n                                        target: '_blank',\n                                        children: '查看',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: 'this.text',\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh64kbx22',\n                                      props: {\n                                        children: '暂无',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: '!this.text',\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 120,\n                              },\n                              {\n                                title: '测试平台链接',\n                                dataIndex: 'is_run_testing',\n                                width: 120,\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Typography.Link',\n                                      id: 'node_ocksh3jkxz3e',\n                                      props: {\n                                        href: 'http://rivermap.alibaba.net/dashboard/testExecute',\n                                        target: '_blank',\n                                        children: '查看',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: 'this.text',\n                                      },\n                                    },\n                                    {\n                                      componentName: 'Typography.Text',\n                                      id: 'node_ocksh3jkxz3f',\n                                      props: {\n                                        children: '暂无',\n                                      },\n                                      condition: {\n                                        type: 'JSExpression',\n                                        value: '!this.text',\n                                      },\n                                    },\n                                  ],\n                                },\n                              },\n                              {\n                                title: '触发源',\n                                dataIndex: 'source',\n                                width: 120,\n                              },\n                              {\n                                title: '详情',\n                                dataIndex: 'id',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Button',\n                                      id: 'node_ocksh8yryw7',\n                                      props: {\n                                        type: 'link',\n                                        children: '查看',\n                                        size: 'small',\n                                        style: {\n                                          padding: '0px',\n                                        },\n                                        __events: {\n                                          eventDataList: [\n                                            {\n                                              type: 'componentEvent',\n                                              name: 'onClick',\n                                              relatedEventName: 'handleDetail',\n                                            },\n                                          ],\n                                          eventList: [\n                                            {\n                                              name: 'onClick',\n                                              disabled: true,\n                                            },\n                                          ],\n                                        },\n                                        onClick: {\n                                          type: 'JSFunction',\n                                          value: 'function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 80,\n                                fixed: 'right',\n                              },\n                              {\n                                title: '结果',\n                                dataIndex: 'id',\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Button',\n                                      id: 'node_ocksh9v6jw7',\n                                      props: {\n                                        type: 'link',\n                                        children: '查看',\n                                        size: 'small',\n                                        style: {\n                                          padding: '0px',\n                                        },\n                                        __events: {\n                                          eventDataList: [\n                                            {\n                                              type: 'componentEvent',\n                                              name: 'onClick',\n                                              relatedEventName: 'handleResult',\n                                              paramStr: 'this.text',\n                                            },\n                                          ],\n                                          eventList: [\n                                            {\n                                              name: 'onClick',\n                                              disabled: true,\n                                            },\n                                          ],\n                                        },\n                                        onClick: {\n                                          type: 'JSFunction',\n                                          value: 'function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                        },\n                                        ghost: false,\n                                        href: {\n                                          type: 'JSExpression',\n                                          value: 'this.text',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                                width: 80,\n                                fixed: 'right',\n                              },\n                              {\n                                title: '重新执行',\n                                dataIndex: 'id',\n                                width: 92,\n                                render: {\n                                  type: 'JSSlot',\n                                  params: ['text', 'record', 'index'],\n                                  value: [\n                                    {\n                                      componentName: 'Button',\n                                      id: 'node_ocksh96rad1g',\n                                      props: {\n                                        type: 'text',\n                                        children: '',\n                                        icon: {\n                                          type: 'JSSlot',\n                                          value: [\n                                            {\n                                              componentName: 'Icon',\n                                              id: 'node_ocksh96rad1j',\n                                              props: {\n                                                type: 'ReloadOutlined',\n                                                size: 14,\n                                                color: '#0593d3',\n                                                style: {\n                                                  padding: '3px',\n                                                  border: '1px solid #0593d3',\n                                                  borderRadius: '14px',\n                                                  cursor: 'pointer',\n                                                  height: '22px',\n                                                },\n                                                spin: false,\n                                              },\n                                            },\n                                          ],\n                                        },\n                                        shape: 'circle',\n                                        __events: {\n                                          eventDataList: [\n                                            {\n                                              type: 'componentEvent',\n                                              name: 'onClick',\n                                              relatedEventName: 'reload',\n                                            },\n                                          ],\n                                          eventList: [\n                                            {\n                                              name: 'onClick',\n                                              disabled: true,\n                                            },\n                                          ],\n                                        },\n                                        onClick: {\n                                          type: 'JSFunction',\n                                          value: 'function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                                        },\n                                      },\n                                    },\n                                  ],\n                                },\n                                fixed: 'right',\n                              },\n                            ],\n                            actions: [],\n                            pagination: {\n                              total: {\n                                type: 'JSExpression',\n                                value: 'this.state.total',\n                              },\n                              defaultPageSize: 10,\n                              onPageChange: {\n                                type: 'JSFunction',\n                                value: 'function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }',\n                              },\n                              defaultPageIndex: 1,\n                            },\n                            scrollX: 1200,\n                            isPagination: true,\n                          },\n                          condition: {\n                            type: 'JSExpression',\n                            value: '!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)',\n                          },\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'NextBlock',\n              id: 'node_ocksk6f8fa3b',\n              props: {\n                childTotalColumns: 12,\n                mode: 'inset',\n                layoutmode: 'O',\n                autolayout: '(12|1)',\n              },\n              title: '区块',\n              children: [\n                {\n                  componentName: 'NextBlockCell',\n                  id: 'node_ocksk6f8fa3c',\n                  props: {\n                    isAutoContainer: true,\n                    colSpan: 12,\n                    rowSpan: 1,\n                  },\n                  title: '子区块',\n                  children: [\n                    {\n                      componentName: 'NextP',\n                      id: 'node_ocksk6f8fa3d',\n                      props: {\n                        wrap: false,\n                        type: 'body2',\n                        verAlign: 'middle',\n                        textSpacing: true,\n                        align: 'left',\n                        flex: true,\n                      },\n                      title: '段落',\n                      children: [\n                        {\n                          componentName: 'Empty',\n                          id: 'node_ocksk6f8fa3e',\n                          props: {\n                            description: '暂无数据',\n                          },\n                          condition: {\n                            type: 'JSExpression',\n                            value: 'this.state.pkgs.length < 1 && this.state.isSearch',\n                          },\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n  ],\n  i18n: {},\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.editorconfig",
    "content": "\n# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.eslintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n.ice/\n\n# node 覆盖率文件\ncoverage/\n\n# 忽略文件\n**/*-min.js\n**/*.min.js\n\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.eslintrc.js",
    "content": "\nconst { eslint } = require('@ice/spec');\n\nmodule.exports = eslint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules/\n\n# production\nbuild/\ndist/\ntmp/\nlib/\n\n# misc\n.idea/\n.happypack\n.DS_Store\n*.swp\n*.dia~\n.ice\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nindex.module.scss.d.ts\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.prettierignore",
    "content": "\nbuild/\ntests/\ndemo/\n.ice/\ncoverage/\n**/*-min.js\n**/*.min.js\npackage-lock.json\nyarn.lock\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.prettierrc.js",
    "content": "\nconst { prettier } = require('@ice/spec');\n\nmodule.exports = prettier;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.stylelintignore",
    "content": "\n# 忽略目录\nbuild/\ntests/\ndemo/\n\n# node 覆盖率文件\ncoverage/\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/.stylelintrc.js",
    "content": "\nconst { stylelint } = require('@ice/spec');\n\nmodule.exports = stylelint;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/README.md",
    "content": "\n## Scaffold Lite\n\n> 轻量级模板，使用 JavaScript，仅包含基础的 Layout。\n\n## 使用\n\n```bash\n# 安装依赖\n$ npm install\n\n# 启动服务\n$ npm start  # visit http://localhost:3333\n```\n\n[More docs](https://ice.work/docs/guide/about).\n\n## 目录\n\n```md\n├── build/                         # 构建产物\n├── mock/                          # 本地模拟数据\n│   ├── index.[j,t]s\n├── public/\n│   ├── index.html                 # 应用入口 HTML\n│   └── favicon.png                # Favicon\n├── src/                           # 源码路径\n│   ├── components/                # 自定义业务组件\n│   │   └── Guide/\n│   │       ├── index.[j,t]sx\n│   │       ├── index.module.scss\n│   ├── layouts/                   # 布局组件\n│   │   └── BasicLayout/\n│   │       ├── index.[j,t]sx\n│   │       └── index.module.scss\n│   ├── pages/                     # 页面\n│   │   └── Home/                  # home 页面，约定路由转成小写\n│   │       ├── components/        # 页面级自定义业务组件\n│   │       ├── models.[j,t]sx     # 页面级数据状态\n│   │       ├── index.[j,t]sx      # 页面入口\n│   │       └── index.module.scss  # 页面样式文件\n│   ├── configs/                   # [可选] 配置文件\n│   │   └── menu.[j,t]s            # [可选] 菜单配置\n│   ├── models/                    # [可选] 应用级数据状态\n│   │   └── user.[j,t]s\n│   ├── utils/                     # [可选] 工具库\n│   ├── global.scss                # 全局样式\n│   ├── routes.[j,t]s              # 路由配置\n│   └── app.[j,t]s[x]              # 应用入口脚本\n├── build.json                     # 工程配置\n├── README.md\n├── package.json\n├── .editorconfig\n├── .eslintignore\n├── .eslintrc.[j,t]s\n├── .gitignore\n├── .stylelintignore\n├── .stylelintrc.[j,t]s\n├── .gitignore\n└── [j,t]sconfig.json\n```\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/abc.json",
    "content": "\n{\n  \"type\": \"ice-app\",\n  \"builder\": \"@ali/builder-ice-app\"\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/build.json",
    "content": "\n{\n  \"entry\": \"src/app.js\",\n  \"plugins\": [\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-design-pro\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ],\n    \"@ali/build-plugin-ice-def\"\n  ]\n}\n      "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/jsconfig.json",
    "content": "\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"jsx\": \"react\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/package.json",
    "content": "{\n  \"name\": \"@alifd/scaffold-lite-js\",\n  \"version\": \"0.1.5\",\n  \"description\": \"轻量级模板，使用 JavaScript，仅包含基础的 Layout。\",\n  \"dependencies\": {\n    \"moment\": \"^2.24.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"@alifd/theme-design-pro\": \"^0.x\",\n    \"@alifd/next\": \"1.19.18\"\n  },\n  \"devDependencies\": {\n    \"@ice/spec\": \"^1.0.0\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"eslint\": \"^6.0.1\",\n    \"ice.js\": \"^1.0.0\",\n    \"stylelint\": \"^13.2.0\",\n    \"@ali/build-plugin-ice-def\": \"^0.1.0\"\n  },\n  \"scripts\": {\n    \"start\": \"icejs start\",\n    \"build\": \"icejs build\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"eslint\": \"eslint --cache --ext .js,.jsx ./\",\n    \"stylelint\": \"stylelint ./**/*.scss\"\n  },\n  \"ideMode\": { \n    \"name\": \"ice-react\"\n  },\n  \"iceworks\": { \n    \"type\": \"react\", \n    \"adapter\": \"adapter-react-v3\" \n  },\n  \"engines\": { \n    \"node\": \">=8.0.0\" \n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://gitlab.xxx.com/msd/leak-scan/tree/master\"\n  },\n  \"private\": true,\n  \"originTemplate\": \"@alifd/scaffold-lite-js\"\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>demo应用</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/app.js",
    "content": "import { createApp } from \"ice\";\n\nconst appConfig = {\n  app: {\n    rootId: \"app\",\n  },\n  router: {\n    type: \"hash\",\n  },\n};\ncreateApp(appConfig);\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/constants.js",
    "content": "const __$$constants = { ENV: \"prod\", DOMAIN: \"xxx.xxx.com\" };\n\nexport default __$$constants;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/global.scss",
    "content": "// 引入默认全局样式\n@import \"@alifd/next/reset.scss\";\n\nbody {\n  -webkit-font-smoothing: antialiased;\n}\n\nbody {\n  font-size: 12px;\n}\n.table {\n  width: 100px;\n}\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/i18n.js",
    "content": "import IntlMessageFormat from \"intl-messageformat\";\n\nconst i18nConfig = {};\n\nlet locale = \"en-US\";\n\nconst getLocale = () => locale;\n\nconst setLocale = (target) => {\n  locale = target;\n};\n\nconst i18nFormat = ({ id, defaultMessage }, variables) => {\n  const msg =\n    (i18nConfig && i18nConfig[locale] && i18nConfig[locale][id]) ||\n    defaultMessage;\n  if (msg == null) {\n    console.warn(\"[i18n]: unknown message id: %o (locale=%o)\", id, locale);\n    return `${id}`;\n  }\n\n  if (!variables || !variables.length) {\n    return msg;\n  }\n\n  return new IntlMessageFormat(msg, locale).format(variables);\n};\n\nconst i18n = (id) => {\n  return i18nFormat({ id });\n};\n\nexport { getLocale, setLocale, i18n, i18nFormat };\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx",
    "content": "\nimport React from 'react';\nimport styles from './index.module.scss';\n\nexport default function Footer() {\n  return (\n    <p className={styles.footer}>\n      <span className={styles.logo}>Alibaba Fusion</span>\n      <br />\n      <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>\n    </p>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss",
    "content": "\n.footer {\n  line-height: 20px;\n  text-align: center;\n}\n\n.logo {\n  font-weight: bold;\n  font-size: 16px;\n}\n\n.copyright {\n  font-size: 12px;\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx",
    "content": "\nimport React from 'react';\nimport { Link } from 'ice';\nimport styles from './index.module.scss';\n\nexport default function Logo({ image, text, url }) {\n  return (\n    <div className=\"logo\">\n      <Link to={url || '/'} className={styles.logo}>\n        {image && <img src={image} alt=\"logo\" />}\n        <span>{text}</span>\n      </Link>\n    </div>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss",
    "content": "\n.logo{\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: $color-text1-1;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 22px;\n\n  &:visited, &:link {\n    color: $color-text1-1;\n  }\n\n  img {\n    height: 24px;\n    margin-right: 10px;\n  }\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { Link, withRouter } from 'ice';\nimport { Nav } from '@alifd/next';\nimport { asideMenuConfig } from '../../menuConfig';\n\nconst { SubNav } = Nav;\nconst NavItem = Nav.Item;\n\nfunction getNavMenuItems(menusData) {\n  if (!menusData) {\n    return [];\n  }\n\n  return menusData\n    .filter(item => item.name && !item.hideInMenu)\n    .map((item, index) => getSubMenuOrItem(item, index));\n}\n\nfunction getSubMenuOrItem(item, index) {\n  if (item.children && item.children.some(child => child.name)) {\n    const childrenItems = getNavMenuItems(item.children);\n\n    if (childrenItems && childrenItems.length > 0) {\n      const subNav = (\n        <SubNav key={index} icon={item.icon} label={item.name}>\n          {childrenItems}\n        </SubNav>\n      );\n      return subNav;\n    }\n\n    return null;\n  }\n\n  const navItem = (\n    <NavItem key={item.path} icon={item.icon}>\n      <Link to={item.path}>{item.name}</Link>\n    </NavItem>\n  );\n  return navItem;\n}\n\nconst Navigation = (props, context) => {\n  const { location } = props;\n  const { pathname } = location;\n  const { isCollapse } = context;\n  return (\n    <Nav\n      type=\"primary\"\n      selectedKeys={[pathname]}\n      defaultSelectedKeys={[pathname]}\n      embeddable\n      openMode=\"single\"\n      iconOnly={isCollapse}\n      hasArrow={false}\n      mode={isCollapse ? 'popup' : 'inline'}\n    >\n      {getNavMenuItems(asideMenuConfig)}\n    </Nav>\n  );\n};\n\nNavigation.contextTypes = {\n  isCollapse: PropTypes.bool,\n};\nconst PageNav = withRouter(Navigation);\nexport default PageNav;\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx",
    "content": "\nimport React, { useState } from 'react';\nimport { Shell, ConfigProvider } from '@alifd/next';\nimport PageNav from './components/PageNav';\nimport Logo from './components/Logo';\nimport Footer from './components/Footer';\n\n(function() {\n  const throttle = function(type, name, obj = window) {\n    let running = false;\n\n    const func = () => {\n      if (running) {\n        return;\n      }\n\n      running = true;\n      requestAnimationFrame(() => {\n        obj.dispatchEvent(new CustomEvent(name));\n        running = false;\n      });\n    };\n\n    obj.addEventListener(type, func);\n  };\n\n  throttle('resize', 'optimizedResize');\n})();\n\nexport default function BasicLayout({ children }) {\n  const getDevice = width => {\n    const isPhone =\n      typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);\n\n    if (width < 680 || isPhone) {\n      return 'phone';\n    }\n    if (width < 1280 && width > 680) {\n      return 'tablet';\n    }\n    return 'desktop';\n  };\n\n  const [device, setDevice] = useState(getDevice(NaN));\n  window.addEventListener('optimizedResize', e => {\n    setDevice(getDevice(e && e.target && e.target.innerWidth));\n  });\n  return (\n    <ConfigProvider device={device}>\n      <Shell\n        type=\"dark\"\n        style={{\n          minHeight: '100vh',\n        }}\n      >\n        <Shell.Branding>\n          <Logo\n            image=\"https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png\"\n            text=\"Logo\"\n          />\n        </Shell.Branding>\n        <Shell.Navigation\n          direction=\"hoz\"\n          style={{\n            marginRight: 10,\n          }}\n        ></Shell.Navigation>\n        <Shell.Action></Shell.Action>\n        <Shell.Navigation>\n          <PageNav />\n        </Shell.Navigation>\n\n        <Shell.Content>{children}</Shell.Content>\n        <Shell.Footer>\n          <Footer />\n        </Shell.Footer>\n      </Shell>\n    </ConfigProvider>\n  );\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js",
    "content": "\nconst headerMenuConfig = [];\nconst asideMenuConfig = [\n  {\n    name: 'Dashboard',\n    path: '/',\n    icon: 'smile',\n  },\n];\nexport { headerMenuConfig, asideMenuConfig };\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/pages/Test/index.css",
    "content": ""
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/pages/Test/index.jsx",
    "content": "import React from \"react\";\n\nimport { Form, Input, NumberPicker, Select, Button } from \"@alifd/next\";\n\nimport utils, { RefsManager } from \"../../utils\";\n\nimport \"./index.css\";\n\nclass Test$$Page extends React.Component {\n  constructor(props, context) {\n    super(props);\n\n    this.utils = utils;\n\n    this.state = { text: \"outter\" };\n\n    this.refsManager = new RefsManager();\n  }\n\n  componentDidMount() {\n\n  }\n\n  $(refName) {\n    return this.refsManager.get(refName);\n  }\n\n  $$(refName) {\n    return this.refsManager.getAll(refName);\n  }\n\n  render() {\n    return (\n      <div ref={this.refsManager.linkRef(\"outterView\")} autoLoading={true}>\n        <Form\n          labelCol={this.state.colNum}\n          style={{}}\n          ref={this.refsManager.linkRef(\"testForm\")}\n        >\n          <Form.Item label=\"姓名：\" name=\"name\" initValue=\"李雷\">\n            <Input placeholder=\"请输入\" size=\"medium\" style={{ width: 320 }} />\n          </Form.Item>\n          <Form.Item label=\"年龄：\" name=\"age\" initValue=\"22\">\n            <NumberPicker size=\"medium\" type=\"normal\" />\n          </Form.Item>\n          <Form.Item label=\"职业：\" name=\"profession\">\n            <Select\n              dataSource={[\n                { label: \"教师\", value: \"t\" },\n                { label: \"医生\", value: \"d\" },\n                { label: \"歌手\", value: \"s\" },\n              ]}\n            />\n          </Form.Item>\n          <div style={{ textAlign: \"center\" }}>\n            <Button.Group>\n              <Button\n                type=\"primary\"\n                style={{ margin: \"0 5px 0 5px\" }}\n                htmlType=\"submit\"\n              >\n                提交\n              </Button>\n              <Button\n                type=\"normal\"\n                style={{ margin: \"0 5px 0 5px\" }}\n                htmlType=\"reset\"\n              >\n                重置\n              </Button>\n            </Button.Group>\n          </div>\n        </Form>\n      </div>\n    );\n  }\n}\n\nexport default Test$$Page;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/routes.js",
    "content": "import Test from \"@/pages/Test\";\n\nimport BasicLayout from \"@/layouts/BasicLayout\";\n\nconst routerConfig = [\n  {\n    path: \"/\",\n    component: BasicLayout,\n    children: [\n      {\n        path: \"/\",\n        component: Test,\n      },\n    ],\n  },\n];\n\nexport default routerConfig;\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/src/utils.js",
    "content": "import { createRef } from \"react\";\n\nexport class RefsManager {\n  constructor() {\n    this.refInsStore = {};\n  }\n\n  clearNullRefs() {\n    Object.keys(this.refInsStore).forEach((refName) => {\n      const filteredInsList = this.refInsStore[refName].filter(\n        (insRef) => !!insRef.current\n      );\n      if (filteredInsList.length > 0) {\n        this.refInsStore[refName] = filteredInsList;\n      } else {\n        delete this.refInsStore[refName];\n      }\n    });\n  }\n\n  get(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName][0].current;\n    }\n\n    return null;\n  }\n\n  getAll(refName) {\n    this.clearNullRefs();\n    if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {\n      return this.refInsStore[refName].map((i) => i.current);\n    }\n\n    return [];\n  }\n\n  linkRef(refName) {\n    const refIns = createRef();\n    this.refInsStore[refName] = this.refInsStore[refName] || [];\n    this.refInsStore[refName].push(refIns);\n    return refIns;\n  }\n}\n\nexport default {};\n"
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/tsconfig.json",
    "content": "\n{\n  \"compileOnSave\": false,\n  \"buildOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es6\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\"es6\", \"dom\"],\n    \"sourceMap\": true,\n    \"allowJs\": true,\n    \"rootDir\": \"./\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": false,\n    \"importHelpers\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"ice\": [\".ice/index.ts\"],\n      \"ice/*\": [\".ice/pages/*\"]\n    }\n  },\n  \"include\": [\"src/*\", \".ice\"],\n  \"exclude\": [\"node_modules\", \"build\", \"public\"]\n}\n    "
  },
  {
    "path": "modules/code-generator/tests/fixtures/test-cases/react-module/demo1/schema.json5",
    "content": "{\n\t\"version\": \"1.0.0\",\n\t\"componentsMap\": [\n\t\t{\n\t\t\t\"componentName\": \"Button\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Button\",\n\t\t\t\"subName\": \"Group\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Input\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Input\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Form\",\n\t\t\t\"subName\": \"Item\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"NumberPicker\"\n\t\t},\n\t\t{\n\t\t\t\"componentName\": \"Select\",\n\t\t\t\"package\": \"@alifd/next\",\n\t\t\t\"version\": \"1.19.18\",\n\t\t\t\"destructuring\": true,\n\t\t\t\"exportName\": \"Select\"\n\t\t}\n\t],\n\t\"componentsTree\": [\n\t\t{\n\t\t\t\"componentName\": \"Page\",\n\t\t\t\"id\": \"node$1\",\n\t\t\t\"meta\": {\n\t\t\t\t\"title\": \"测试\",\n\t\t\t\t\"router\": \"/\"\n\t\t\t},\n\t\t\t\"props\": {\n\t\t\t\t\"ref\": \"outterView\",\n\t\t\t\t\"autoLoading\": true\n\t\t\t},\n\t\t\t\"fileName\": \"test\",\n\t\t\t\"state\": {\n\t\t\t\t\"text\": \"outter\"\n\t\t\t},\n\t\t\t\"lifeCycles\": {\n\t\t\t\t\"componentDidMount\": {\n\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\"value\": \"function() { console.log('componentDidMount'); }\"\n\t\t\t\t}\n\t\t\t},\n\t\t\tdataSource: {\n        list: [\n          {\n            id: 'urlParams',\n            type: 'urlParams',\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/user\n          {\n            id: 'user',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: 'https://shs.xxx.com/mock/1458/demo/user',\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.success){\\n    throw new Error(response.message);\\n  }\\n  return response.data;\\n}',\n            },\n          },\n          // 示例数据源：https://shs.xxx.com/mock/1458/demo/orders\n          {\n            id: 'orders',\n            type: 'fetch',\n            options: {\n              method: 'GET',\n              uri: {\n                type: 'JSExpression',\n                value: 'this.state.user.ordersApiUri',\n              },\n              isSync: true,\n            },\n            dataHandler: {\n              type: 'JSExpression',\n              value: 'function (response) {\\nif (!response.success){\\n    throw new Error(response.message);\\n  }\\n  return response.data.result;\\n}',\n            },\n          },\n        ],\n        dataHandler: {\n          type: 'JSExpression',\n          value: 'function (dataMap) {\\n  console.info(\"All datasources loaded:\", dataMap);\\n}',\n        },\n      },\n\t\t\t\"children\": [\n\t\t\t\t{\n\t\t\t\t\t\"componentName\": \"Form\",\n\t\t\t\t\t\"id\": \"node$2\",\n\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\"labelCol\": {\n\t\t\t\t\t\t\t\"type\": \"JSExpression\",\n\t\t\t\t\t\t\t\"value\": \"this.state.colNum\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"style\": {},\n\t\t\t\t\t\t\"ref\": \"testForm\"\n\t\t\t\t\t},\n\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$3\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"姓名：\",\n\t\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\t\"initValue\": \"李雷\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Input\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$4\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"placeholder\": \"请输入\",\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\"width\": 320\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$5\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"年龄：\",\n\t\t\t\t\t\t\t\t\"name\": \"age\",\n\t\t\t\t\t\t\t\t\"initValue\": \"22\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"NumberPicker\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$6\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"size\": \"medium\",\n\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Form.Item\",\n\t\t\t\t\t\t\t\"id\": \"node$7\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"label\": \"职业：\",\n\t\t\t\t\t\t\t\t\"name\": \"profession\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Select\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$8\",\n\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\"dataSource\": [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"教师\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"t\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"医生\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"d\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"label\": \"歌手\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": \"s\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"componentName\": \"Div\",\n\t\t\t\t\t\t\t\"id\": \"node$9\",\n\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\"textAlign\": \"center\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"componentName\": \"Button.Group\",\n\t\t\t\t\t\t\t\t\t\"id\": \"node$a\",\n\t\t\t\t\t\t\t\t\t\"props\": {},\n\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$b\",\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"primary\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"htmlType\": \"submit\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\"提交\"\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"componentName\": \"Button\",\n\t\t\t\t\t\t\t\t\t\t\t\"id\": \"node$d\",\n\t\t\t\t\t\t\t\t\t\t\t\"props\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"normal\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"style\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"margin\": \"0 5px 0 5px\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"htmlType\": \"reset\"\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"children\": [\n\t\t\t\t\t\t\t\t\t\t\t\t\"重置\"\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"constants\": {\n\t\t\"ENV\": \"prod\",\n\t\t\"DOMAIN\": \"xxx.xxx.com\"\n\t},\n\t\"i18n\": {\n\t\t\"zh-CN\": {\n\t\t\t\"i18n-jwg27yo4\": \"你好\",\n\t\t\t\"i18n-jwg27yo3\": \"中国\"\n\t\t},\n\t\t\"en-US\": {\n\t\t\t\"i18n-jwg27yo4\": \"Hello\",\n\t\t\t\"i18n-jwg27yo3\": \"China\"\n\t\t}\n\t},\n\t\"css\": \"body {font-size: 12px;} .table { width: 100px;}\",\n\t\"config\": {\n\t\t\"sdkVersion\": \"1.0.3\",\n\t\t\"historyMode\": \"hash\",\n\t\t\"targetRootID\": \"J_Container\",\n\t\t\"layout\": {\n\t\t\t\"componentName\": \"BasicLayout\",\n\t\t\t\"props\": {\n\t\t\t\t\"logo\": \"...\",\n\t\t\t\t\"name\": \"测试网站\"\n\t\t\t}\n\t\t},\n\t\t\"theme\": {\n\t\t\t\"package\": \"@alife/theme-fusion\",\n\t\t\t\"version\": \"^0.1.0\",\n\t\t\t\"primary\": \"#ff9966\"\n\t\t}\n\t},\n\t\"meta\": {\n\t\t\"name\": \"demo应用\",\n\t\t\"git_group\": \"appGroup\",\n\t\t\"project_name\": \"app_demo\",\n\t\t\"description\": \"这是一个测试应用\",\n\t\t\"spma\": \"spa23d\",\n\t\t\"creator\": \"月飞\"\n\t}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/helpers/solutionHelper.ts",
    "content": "import { spawnSync } from 'child_process';\nimport fs from 'fs';\nimport path from 'path';\nimport chalk from 'chalk';\n\nexport { createDiskPublisher } from '../../src/publisher/disk';\n\nexport function removeActualDirRecursiveSync(actualDir: string, caseFullDir: string) {\n  ensureShellExec('rm', ['-rf', actualDir], { cwd: caseFullDir });\n}\n\nexport function runPrettierSync(files: string[], cwd: string) {\n  ensureShellExec('npx', ['prettier', '--write', ...files], { cwd });\n}\n\nexport function diffActualAndExpectedSync(caseFullDir: string): string {\n  const res = spawnSync(\n    'diff',\n    ['-wBur', '-x', '.eslintrc.js', '-x', 'abc.json', 'expected', 'actual'],\n    {\n      cwd: caseFullDir,\n      stdio: 'pipe',\n      shell: true,\n      encoding: 'utf-8',\n    },\n  );\n\n  return colorizeDiffOutput(res.stdout);\n}\n\nexport function ensureShellExec(\n  shellCmd: string,\n  args: string[],\n  { cwd = process.cwd() }: { cwd?: string } = {},\n): { stdout: string; stderr: string } {\n  const res = spawnSync(shellCmd, args, {\n    stdio: 'pipe',\n    shell: true,\n    cwd,\n    encoding: 'utf-8',\n  });\n\n  if (res.status !== 0) {\n    throw new Error(\n      `Shell command \"${shellCmd} ${args.slice(0, 2).join(' ')}...\" failed with status: ${\n        res.status\n      } (Full command: \"${shellCmd} ${args.join(' ')}\" ) (stderr: ${res.stderr})`,\n    );\n  }\n\n  return res;\n}\n\nexport function colorizeDiffOutput(output: string): string {\n  if (!output) {\n    return output;\n  }\n\n  return output\n    .split('\\n')\n    .map((line) => {\n      if (/^Only/i.test(line)) {\n        return chalk.red(line);\n      } else if (line[0] === '+') {\n        return chalk.yellow(line);\n      } else if (line[0] === '-') {\n        return chalk.red(line);\n      } else {\n        return line;\n      }\n    })\n    .join('\\n');\n}\n\nexport function getSubDirectoriesSync(baseDir: string) {\n  return fs\n    .readdirSync(baseDir)\n    .filter((dirOrFileName: string) =>\n      fs.statSync(path.join(baseDir, dirOrFileName)).isDirectory(),\n    );\n}\n\nexpect.extend({\n  toBeSameFileContents(caseFullDir: string) {\n    const differences = diffActualAndExpectedSync(caseFullDir);\n    if (differences) {\n      return {\n        message: () => differences,\n        pass: false,\n      };\n    } else {\n      return {\n        message: () => `expected case [${caseFullDir}] not to be same`,\n        pass: true,\n      };\n    }\n  },\n});\n\ndeclare global {\n  namespace jest {\n    interface Matchers<R> {\n      toBeSameFileContents(): R;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/code-generator/tests/plugins/common/__snapshots__/requireUtils.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`tests/plugins/common/requireUtils should works 1`] = `\nObject {\n  \"chunks\": Array [\n    Object {\n      \"content\": \"import * from 'react';\",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [],\n      \"name\": \"CommonInternalDependencyImport\",\n      \"type\": \"string\",\n    },\n  ],\n  \"contextData\": Object {},\n  \"depNames\": Array [],\n  \"ir\": Object {},\n}\n`;\n"
  },
  {
    "path": "modules/code-generator/tests/plugins/common/requireUtils.test.ts",
    "content": "import requireUtils from '../../../src/plugins/common/requireUtils';\nimport { ICodeStruct } from '../../../src/types';\n\ndescribe('tests/plugins/common/requireUtils', () => {\n  it('should works', async () => {\n    const plugin = requireUtils();\n    const ctx: ICodeStruct = {\n      chunks: [],\n      depNames: [],\n      ir: {},\n      contextData: {},\n    };\n\n    const newCtx = await plugin.apply(ctx, [ctx]);\n    expect(newCtx).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`condition at root condition and loop should be both works 1`] = `\nObject {\n  \"chunks\": Array [\n    Object {\n      \"content\": \"\n        const __$$context = this._context || this;\n        const { state } = __$$context;\n        return (__$$evalArray(() => (this.state.otherThings))).map((item, index) => ((__$$context) => (!!(__$$eval(() => (__$$context.state.something))) && (<Page><Text>Hello world!</Text></Page>)))(__$$createChildContext(__$$context, { item, index })));\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"ReactComponentClassRenderStart\",\n        \"ReactComponentClassRenderPre\",\n      ],\n      \"name\": \"ReactComponentClassRenderJSX\",\n      \"type\": \"string\",\n    },\n    Object {\n      \"content\": \"\n          function __$$eval(expr) {\n            try {\n              return expr();\n            } catch (error) {\n              \n            }\n          }\n\n          function __$$evalArray(expr) {\n            const res = __$$eval(expr);\n            return Array.isArray(res) ? res : [];\n          }\n      \n\n        function __$$createChildContext(oldContext, ext) {\n          const childContext = {\n            ...oldContext,\n            ...ext,\n          };\n          childContext.__proto__ = oldContext;\n          return childContext;\n        }\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"CommonFileExport\",\n      ],\n      \"name\": \"CommonCustomContent\",\n      \"type\": \"string\",\n    },\n  ],\n  \"contextData\": Object {},\n  \"depNames\": Array [],\n  \"ir\": Object {\n    \"children\": Array [\n      Object {\n        \"children\": \"Hello world!\",\n        \"componentName\": \"Text\",\n      },\n    ],\n    \"componentName\": \"Page\",\n    \"condition\": Object {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.state.something\",\n    },\n    \"containerType\": \"Page\",\n    \"fileName\": \"test\",\n    \"loop\": Object {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.state.otherThings\",\n    },\n    \"moduleName\": \"test\",\n  },\n}\n`;\n\nexports[`condition at root condition=JSExpression should be ignored 1`] = `\nObject {\n  \"chunks\": Array [\n    Object {\n      \"content\": \"\n        const __$$context = this._context || this;\n        const { state } = __$$context;\n        return !!(__$$eval(() => (this.state.something))) && (<Page><Text>Hello world!</Text></Page>);\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"ReactComponentClassRenderStart\",\n        \"ReactComponentClassRenderPre\",\n      ],\n      \"name\": \"ReactComponentClassRenderJSX\",\n      \"type\": \"string\",\n    },\n    Object {\n      \"content\": \"\n          function __$$eval(expr) {\n            try {\n              return expr();\n            } catch (error) {\n              \n            }\n          }\n\n          function __$$evalArray(expr) {\n            const res = __$$eval(expr);\n            return Array.isArray(res) ? res : [];\n          }\n      \n\n        function __$$createChildContext(oldContext, ext) {\n          const childContext = {\n            ...oldContext,\n            ...ext,\n          };\n          childContext.__proto__ = oldContext;\n          return childContext;\n        }\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"CommonFileExport\",\n      ],\n      \"name\": \"CommonCustomContent\",\n      \"type\": \"string\",\n    },\n  ],\n  \"contextData\": Object {},\n  \"depNames\": Array [],\n  \"ir\": Object {\n    \"children\": Array [\n      Object {\n        \"children\": \"Hello world!\",\n        \"componentName\": \"Text\",\n      },\n    ],\n    \"componentName\": \"Page\",\n    \"condition\": Object {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.state.something\",\n    },\n    \"containerType\": \"Page\",\n    \"fileName\": \"test\",\n    \"moduleName\": \"test\",\n  },\n}\n`;\n\nexports[`condition at root condition=null should be ignored 1`] = `\nObject {\n  \"chunks\": Array [\n    Object {\n      \"content\": \"\n        const __$$context = this._context || this;\n        const { state } = __$$context;\n        return <Page><Text>Hello world!</Text></Page>;\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"ReactComponentClassRenderStart\",\n        \"ReactComponentClassRenderPre\",\n      ],\n      \"name\": \"ReactComponentClassRenderJSX\",\n      \"type\": \"string\",\n    },\n    Object {\n      \"content\": \"\n          function __$$eval(expr) {\n            try {\n              return expr();\n            } catch (error) {\n              \n            }\n          }\n\n          function __$$evalArray(expr) {\n            const res = __$$eval(expr);\n            return Array.isArray(res) ? res : [];\n          }\n      \n\n        function __$$createChildContext(oldContext, ext) {\n          const childContext = {\n            ...oldContext,\n            ...ext,\n          };\n          childContext.__proto__ = oldContext;\n          return childContext;\n        }\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"CommonFileExport\",\n      ],\n      \"name\": \"CommonCustomContent\",\n      \"type\": \"string\",\n    },\n  ],\n  \"contextData\": Object {},\n  \"depNames\": Array [],\n  \"ir\": Object {\n    \"children\": Array [\n      Object {\n        \"children\": \"Hello world!\",\n        \"componentName\": \"Text\",\n      },\n    ],\n    \"componentName\": \"Page\",\n    \"condition\": null,\n    \"containerType\": \"Page\",\n    \"fileName\": \"test\",\n    \"moduleName\": \"test\",\n  },\n}\n`;\n\nexports[`condition at root condition=true should be ignored 1`] = `\nObject {\n  \"chunks\": Array [\n    Object {\n      \"content\": \"\n        const __$$context = this._context || this;\n        const { state } = __$$context;\n        return <Page><Text>Hello world!</Text></Page>;\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"ReactComponentClassRenderStart\",\n        \"ReactComponentClassRenderPre\",\n      ],\n      \"name\": \"ReactComponentClassRenderJSX\",\n      \"type\": \"string\",\n    },\n    Object {\n      \"content\": \"\n          function __$$eval(expr) {\n            try {\n              return expr();\n            } catch (error) {\n              \n            }\n          }\n\n          function __$$evalArray(expr) {\n            const res = __$$eval(expr);\n            return Array.isArray(res) ? res : [];\n          }\n      \n\n        function __$$createChildContext(oldContext, ext) {\n          const childContext = {\n            ...oldContext,\n            ...ext,\n          };\n          childContext.__proto__ = oldContext;\n          return childContext;\n        }\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"CommonFileExport\",\n      ],\n      \"name\": \"CommonCustomContent\",\n      \"type\": \"string\",\n    },\n  ],\n  \"contextData\": Object {},\n  \"depNames\": Array [],\n  \"ir\": Object {\n    \"children\": Array [\n      Object {\n        \"children\": \"Hello world!\",\n        \"componentName\": \"Text\",\n      },\n    ],\n    \"componentName\": \"Page\",\n    \"condition\": true,\n    \"containerType\": \"Page\",\n    \"fileName\": \"test\",\n    \"moduleName\": \"test\",\n  },\n}\n`;\n\nexports[`condition at root invalid attr name should not be generated 1`] = `\nObject {\n  \"chunks\": Array [\n    Object {\n      \"content\": \"\n        const __$$context = this._context || this;\n        const { state } = __$$context;\n        return <Page><Text a={1}>Hello world!</Text></Page>;\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"ReactComponentClassRenderStart\",\n        \"ReactComponentClassRenderPre\",\n      ],\n      \"name\": \"ReactComponentClassRenderJSX\",\n      \"type\": \"string\",\n    },\n    Object {\n      \"content\": \"\n          function __$$eval(expr) {\n            try {\n              return expr();\n            } catch (error) {\n              \n            }\n          }\n\n          function __$$evalArray(expr) {\n            const res = __$$eval(expr);\n            return Array.isArray(res) ? res : [];\n          }\n      \n\n        function __$$createChildContext(oldContext, ext) {\n          const childContext = {\n            ...oldContext,\n            ...ext,\n          };\n          childContext.__proto__ = oldContext;\n          return childContext;\n        }\n      \",\n      \"fileType\": \"jsx\",\n      \"linkAfter\": Array [\n        \"CommonFileExport\",\n      ],\n      \"name\": \"CommonCustomContent\",\n      \"type\": \"string\",\n    },\n  ],\n  \"contextData\": Object {},\n  \"depNames\": Array [],\n  \"ir\": Object {\n    \"children\": Array [\n      Object {\n        \"children\": \"Hello world!\",\n        \"componentName\": \"Text\",\n        \"props\": Object {\n          \"a\": 1,\n          \"a.b\": 2,\n        },\n      },\n    ],\n    \"componentName\": \"Page\",\n    \"condition\": null,\n    \"containerType\": \"Page\",\n    \"fileName\": \"test\",\n    \"moduleName\": \"test\",\n  },\n}\n`;\n"
  },
  {
    "path": "modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts",
    "content": "import jsx from '../../../src/plugins/component/react/jsx';\nimport { IContainerInfo } from '../../../src/types';\n\ndescribe('condition at root', () => {\n  test('condition=true should be ignored', async () => {\n    const containerIr: IContainerInfo = {\n      containerType: 'Page',\n      moduleName: 'test',\n      componentName: 'Page',\n      fileName: 'test',\n      condition: true,\n      children: [{ componentName: 'Text', children: 'Hello world!' }],\n    };\n    const result = await jsx()({\n      ir: containerIr,\n      contextData: {},\n      chunks: [],\n      depNames: [],\n    });\n    expect(result).toMatchSnapshot();\n  });\n\n  test('condition=null should be ignored', async () => {\n    const containerIr: IContainerInfo = {\n      containerType: 'Page',\n      moduleName: 'test',\n      componentName: 'Page',\n      fileName: 'test',\n      condition: null,\n      children: [{ componentName: 'Text', children: 'Hello world!' }],\n    };\n    const result = await jsx()({\n      ir: containerIr,\n      contextData: {},\n      chunks: [],\n      depNames: [],\n    });\n    expect(result).toMatchSnapshot();\n  });\n\n  test('condition=JSExpression should be ignored', async () => {\n    const containerIr: IContainerInfo = {\n      containerType: 'Page',\n      moduleName: 'test',\n      componentName: 'Page',\n      fileName: 'test',\n      condition: {\n        type: 'JSExpression',\n        value: 'this.state.something',\n      },\n      children: [{ componentName: 'Text', children: 'Hello world!' }],\n    };\n    const result = await jsx()({\n      ir: containerIr,\n      contextData: {},\n      chunks: [],\n      depNames: [],\n    });\n    expect(result).toMatchSnapshot();\n  });\n\n  test('condition and loop should be both works', async () => {\n    const containerIr: IContainerInfo = {\n      containerType: 'Page',\n      moduleName: 'test',\n      componentName: 'Page',\n      fileName: 'test',\n      condition: {\n        type: 'JSExpression',\n        value: 'this.state.something',\n      },\n      loop: {\n        type: 'JSExpression',\n        value: 'this.state.otherThings',\n      },\n      children: [{ componentName: 'Text', children: 'Hello world!' }],\n    };\n    const result = await jsx()({\n      ir: containerIr,\n      contextData: {},\n      chunks: [],\n      depNames: [],\n    });\n    expect(result).toMatchSnapshot();\n  });\n\n  test('invalid attr name should not be generated', async () => {\n    const containerIr: IContainerInfo = {\n      containerType: 'Page',\n      moduleName: 'test',\n      componentName: 'Page',\n      fileName: 'test',\n      condition: null,\n      children: [{ componentName: 'Text', children: 'Hello world!', props: { 'a': 1, 'a.b': 2 } }],\n    };\n    const result = await jsx()({\n      ir: containerIr,\n      contextData: {},\n      chunks: [],\n      depNames: [],\n    });\n    expect(result).toMatchSnapshot();\n  })\n});\n"
  },
  {
    "path": "modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`postprocessor/prettier should works for custom files 1`] = `\n\"<template>\n  <div>Hello</div>\n  <script>\n    export default {};\n  </script>\n</template>\n\"\n`;\n\nexports[`postprocessor/prettier should works for js file 1`] = `\n\"import { Button } from '@alifd/next';\nexport function App() {\n  return <Button />;\n}\n\"\n`;\n\nexports[`postprocessor/prettier should works for json file 1`] = `\n\"{\n  \\\\\"components\\\\\": [\n    \\\\\"Button\\\\\",\n    \\\\\"Block\\\\\"\n  ]\n}\n\"\n`;\n\nexports[`postprocessor/prettier should works for jsx file 1`] = `\n\"import { Button } from '@alifd/next';\nexport function App() {\n  return <Button />;\n}\n\"\n`;\n\nexports[`postprocessor/prettier should works for other files 1`] = `\n\".foo {\n  font-size: 12px;\n}\n\"\n`;\n"
  },
  {
    "path": "modules/code-generator/tests/postprocessor/prettier.test.ts",
    "content": "import { prettier } from '../../src/postprocessor';\n\ndescribe('postprocessor/prettier', () => {\n  it('should works for js file', () => {\n    const fileType = 'js';\n    const content = `import { Button } from '@alifd/next'; export function App(){return <Button />}`;\n    expect(prettier()(content, fileType)).toMatchSnapshot();\n  });\n\n  it('should works for jsx file', () => {\n    const fileType = 'jsx';\n    const content = `import { Button } from '@alifd/next'; export function App(){return <Button />}`;\n    expect(prettier()(content, fileType)).toMatchSnapshot();\n  });\n\n  it('should works for json file', () => {\n    const fileType = 'json';\n    const content = `{\"components\": [\"Button\",\"Block\"]}`;\n    expect(prettier()(content, fileType)).toMatchSnapshot();\n  });\n\n  it('should works for custom files', () => {\n    const fileType = 'vue';\n    const content = `<template><div>Hello</div><script>export default {  }</script>`;\n    expect(\n      prettier({\n        customFileTypeParser: {\n          vue: 'html',\n        },\n      })(content, fileType),\n    ).toMatchSnapshot();\n  });\n\n  it('should works for other files', () => {\n    const fileType = 'less';\n    const content = `.foo{font-size: 12px;}`;\n    expect(prettier()(content, fileType)).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/public/README.md",
    "content": "# 这里测试的都是对外公开的 API，必须要保持稳定性\n"
  },
  {
    "path": "modules/code-generator/tests/public/SchemaParser/__snapshots__/p0-basic.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`tests/public/SchemaParser/p0-basics should be able to get dependencies in slots 1`] = `\nArray [\n  Array [\n    Object {\n      \"componentName\": \"Page\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": false,\n      \"devMode\": \"lowcode\",\n      \"exportName\": \"Page\",\n      \"version\": \"*\",\n    },\n    Object {\n      \"componentName\": \"Modal\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Modal\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"AliAutoDivDefault\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"AliAutoDiv\",\n      \"main\": \"build/lowcode/index.js\",\n      \"package\": \"@alife/mc-assets-1935\",\n      \"subName\": \"default\",\n      \"version\": \"0.1.43\",\n    },\n    Object {\n      \"componentName\": \"Button\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Button\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"Typography.Text\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"subName\": \"Text\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"Typography.Link\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"subName\": \"Link\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"NextPage\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"@alife/container\",\n      \"subName\": \"\",\n      \"version\": \"0.3.7\",\n    },\n    Object {\n      \"componentName\": \"NextBlock\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"@alife/container\",\n      \"subName\": \"\",\n      \"version\": \"0.3.7\",\n    },\n    Object {\n      \"componentName\": \"NextBlockCell\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"@alife/container\",\n      \"subName\": \"Cell\",\n      \"version\": \"0.3.7\",\n    },\n    Object {\n      \"componentName\": \"NextP\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"@alife/container\",\n      \"subName\": \"\",\n      \"version\": \"0.3.7\",\n    },\n    Object {\n      \"componentName\": \"Form\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"Form.Item\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"subName\": \"Item\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"Select\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Select\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"Input\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Input\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"AliAutoSearchTableDefault\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"AliAutoSearchTable\",\n      \"main\": \"build/lowcode/index.js\",\n      \"package\": \"@alife/mc-assets-1935\",\n      \"subName\": \"default\",\n      \"version\": \"0.1.43\",\n    },\n    Object {\n      \"componentName\": \"Tooltip\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Tooltip\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"Icon\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Icon\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n    Object {\n      \"componentName\": \"Empty\",\n      \"dependencyType\": \"External\",\n      \"destructuring\": true,\n      \"exportName\": \"Empty\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n    },\n  ],\n]\n`;\n"
  },
  {
    "path": "modules/code-generator/tests/public/SchemaParser/data/schema-with-slot.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Slot\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Button\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Button\"\n    },\n    {\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.43\",\n      \"exportName\": \"AliAutoDiv\",\n      \"main\": \"build/lowcode/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoDivDefault\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Text\",\n      \"componentName\": \"Typography.Text\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Link\",\n      \"componentName\": \"Typography.Link\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Modal\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Modal\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Select\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Select\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Item\",\n      \"componentName\": \"Form.Item\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Input\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Input\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Form\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextP\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"Cell\",\n      \"componentName\": \"NextBlockCell\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlock\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Tooltip\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Tooltip\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Icon\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Icon\"\n    },\n    {\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.43\",\n      \"exportName\": \"AliAutoSearchTable\",\n      \"main\": \"build/lowcode/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoSearchTableDefault\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Empty\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Empty\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextPage\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Page\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"style\": {\n          \"height\": \"100%\"\n        }\n      },\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}\",\n      \"lifeCycles\": {\n        \"constructor\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"componentDidUpdate\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"componentWillUnmount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {}\"\n        }\n      },\n      \"methods\": {\n        \"__jp__init\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initRouter\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initDataSource\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initEnv\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initConfig\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initUtils\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"setSearchItem\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"fetchProject\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleProjectSearch\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleProjectChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"fetchUser\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleUserSearch\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleUserChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"fetchPkgs\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"onPageChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"renderTime\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"renderUserName\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"reload\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleResult\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleDetail\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"onResultCancel\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"formatResult\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleDownload\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"onFinish\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        }\n      },\n      \"state\": {\n        \"pkgs\": [],\n        \"total\": 0,\n        \"isSearch\": false,\n        \"projects\": [],\n        \"results\": [],\n        \"resultVisible\": false,\n        \"userOptions\": [],\n        \"searchValues\": {\n          \"user_id\": \"\",\n          \"channel_id\": \"\"\n        }\n      },\n      \"children\": [\n        {\n          \"componentName\": \"Modal\",\n          \"id\": \"node_ocksh9yppxb\",\n          \"props\": {\n            \"title\": \"查看结果\",\n            \"visible\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"this.state.resultVisible\"\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"value\": [\n                {\n                  \"componentName\": \"Button\",\n                  \"id\": \"node_ocksh9yppxf\",\n                  \"props\": {\n                    \"type\": \"primary\",\n                    \"children\": \"确定\",\n                    \"__events\": {\n                      \"eventDataList\": [\n                        {\n                          \"type\": \"componentEvent\",\n                          \"name\": \"onClick\",\n                          \"relatedEventName\": \"onResultCancel\"\n                        }\n                      ],\n                      \"eventList\": [\n                        {\n                          \"name\": \"onClick\",\n                          \"disabled\": true\n                        }\n                      ]\n                    },\n                    \"onClick\": {\n                      \"type\": \"JSFunction\",\n                      \"value\": \"function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                    }\n                  }\n                }\n              ]\n            },\n            \"__events\": {\n              \"eventDataList\": [\n                {\n                  \"type\": \"componentEvent\",\n                  \"name\": \"onCancel\",\n                  \"relatedEventName\": \"onResultCancel\"\n                }\n              ],\n              \"eventList\": [\n                {\n                  \"name\": \"onCancel\",\n                  \"disabled\": true\n                },\n                {\n                  \"name\": \"onOk\",\n                  \"disabled\": false\n                }\n              ]\n            },\n            \"onCancel\": {\n              \"type\": \"JSFunction\",\n              \"value\": \"function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n            },\n            \"width\": \"720px\",\n            \"centered\": true,\n            \"closable\": true,\n            \"keyboard\": true,\n            \"mask\": true,\n            \"maskClosable\": true\n          },\n          \"hidden\": true,\n          \"children\": [\n            {\n              \"componentName\": \"AliAutoDivDefault\",\n              \"id\": \"node_ockshazuxa4\",\n              \"props\": {\n                \"style\": {\n                  \"width\": \"100%\"\n                }\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"AliAutoDivDefault\",\n                  \"id\": \"node_ockshazuxai\",\n                  \"props\": {\n                    \"style\": {\n                      \"width\": \"100%\",\n                      \"textAlign\": \"left\",\n                      \"marginBottom\": \"16px\"\n                    }\n                  },\n                  \"condition\": {\n                    \"type\": \"JSExpression\",\n                    \"value\": \"this.state.results && this.state.results.length > 0\"\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"Button\",\n                      \"id\": \"node_ockshazuxah\",\n                      \"props\": {\n                        \"type\": \"primary\",\n                        \"children\": \"下载全部\",\n                        \"size\": \"small\",\n                        \"__events\": {\n                          \"eventDataList\": [\n                            {\n                              \"type\": \"componentEvent\",\n                              \"name\": \"onClick\",\n                              \"relatedEventName\": \"handleDownload\"\n                            }\n                          ],\n                          \"eventList\": [\n                            {\n                              \"name\": \"onClick\",\n                              \"disabled\": true\n                            }\n                          ]\n                        },\n                        \"onClick\": {\n                          \"type\": \"JSFunction\",\n                          \"value\": \"function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                        }\n                      }\n                    }\n                  ]\n                },\n                {\n                  \"componentName\": \"AliAutoDivDefault\",\n                  \"id\": \"node_ockt2muyfi4\",\n                  \"props\": {\n                    \"style\": {\n                      \"width\": \"100%\",\n                      \"marginTop\": \"10px\"\n                    }\n                  },\n                  \"loop\": {\n                    \"type\": \"JSExpression\",\n                    \"value\": \"this.state.results\"\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"Typography.Text\",\n                      \"id\": \"node_ockshazuxa5\",\n                      \"props\": {\n                        \"children\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.formatResult(this.item)\"\n                        }\n                      }\n                    },\n                    {\n                      \"componentName\": \"Typography.Link\",\n                      \"id\": \"node_ockshazuxa6\",\n                      \"props\": {\n                        \"href\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.item.download_link\"\n                        },\n                        \"target\": \"_blank\",\n                        \"children\": \" - 点击下载\"\n                      },\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.item.download_link\"\n                      }\n                    },\n                    {\n                      \"componentName\": \"Typography.Link\",\n                      \"id\": \"node_ockshazuxa7\",\n                      \"props\": {\n                        \"href\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.item.release_notes\"\n                        },\n                        \"target\": \"_blank\",\n                        \"children\": \" - 跳转发布节点\"\n                      },\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.item.release_notes\"\n                      }\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ocko19zplh1\",\n          \"props\": {\n            \"columns\": 12,\n            \"headerDivider\": true,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"header\"\n            },\n            \"headerProps\": {\n              \"background\": \"surface\",\n              \"style\": {\n                \"padding\": \"\"\n              }\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"footer\"\n            },\n            \"minHeight\": \"100vh\",\n            \"contentProps\": {\n              \"noPadding\": false,\n              \"background\": \"transparent\"\n            }\n          },\n          \"title\": \"页面\",\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockt3t4q8565\",\n              \"props\": {\n                \"childTotalColumns\": 12\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockt3t4q8566\",\n                  \"props\": {\n                    \"isAutoContainer\": true,\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1\n                  },\n                  \"title\": \"子区块\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ockt3t4q8567\",\n                      \"props\": {\n                        \"wrap\": false,\n                        \"type\": \"body2\",\n                        \"verAlign\": \"middle\",\n                        \"textSpacing\": true,\n                        \"align\": \"left\",\n                        \"flex\": true\n                      },\n                      \"title\": \"段落\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"AliAutoDivDefault\",\n                          \"id\": \"node_ockt3t4q8568\",\n                          \"props\": {\n                            \"style\": {\n                              \"width\": \"100%\",\n                              \"display\": \"flex\"\n                            }\n                          },\n                          \"children\": [\n                            {\n                              \"componentName\": \"AliAutoDivDefault\",\n                              \"id\": \"node_ockt3t4q857a\",\n                              \"props\": {\n                                \"style\": {\n                                  \"flex\": \"1\"\n                                }\n                              },\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Form\",\n                                  \"id\": \"node_ocks8dtt1mt\",\n                                  \"props\": {\n                                    \"labelCol\": {\n                                      \"span\": 10\n                                    },\n                                    \"wrapperCol\": {\n                                      \"span\": 14\n                                    },\n                                    \"onFinish\": {\n                                      \"type\": \"JSFunction\",\n                                      \"value\": \"function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                    },\n                                    \"name\": \"basic\",\n                                    \"layout\": \"inline\",\n                                    \"__events\": {\n                                      \"eventDataList\": [\n                                        {\n                                          \"type\": \"componentEvent\",\n                                          \"name\": \"onFinish\",\n                                          \"relatedEventName\": \"onFinish\"\n                                        }\n                                      ],\n                                      \"eventList\": [\n                                        {\n                                          \"name\": \"onFinish\",\n                                          \"disabled\": true\n                                        },\n                                        {\n                                          \"name\": \"onFinishFailed\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onFieldsChange\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onValuesChange\",\n                                          \"disabled\": false\n                                        }\n                                      ]\n                                    },\n                                    \"colon\": true,\n                                    \"labelAlign\": \"right\",\n                                    \"preserve\": true,\n                                    \"scrollToFirstError\": true,\n                                    \"size\": \"middle\",\n                                    \"values\": {\n                                      \"type\": \"JSExpression\",\n                                      \"value\": \"this.state.searchValues\"\n                                    }\n                                  },\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1mz\",\n                                      \"props\": {\n                                        \"label\": \"项目名称/渠道号\",\n                                        \"name\": \"channel_id\",\n                                        \"labelAlign\": \"right\",\n                                        \"colon\": true\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Select\",\n                                          \"id\": \"node_ocksfuhwhsd\",\n                                          \"props\": {\n                                            \"style\": {\n                                              \"width\": \"320px\"\n                                            },\n                                            \"options\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.state.projects\"\n                                            },\n                                            \"showArrow\": false,\n                                            \"tokenSeparators\": [],\n                                            \"showSearch\": true,\n                                            \"defaultActiveFirstOption\": true,\n                                            \"size\": \"middle\",\n                                            \"bordered\": true,\n                                            \"filterOption\": true,\n                                            \"optionFilterProp\": \"label\",\n                                            \"allowClear\": true,\n                                            \"placeholder\": \"请输入项目名称/渠道号\",\n                                            \"__events\": {\n                                              \"eventDataList\": [\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onChange\",\n                                                  \"relatedEventName\": \"handleProjectChange\"\n                                                },\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onSearch\",\n                                                  \"relatedEventName\": \"handleProjectSearch\"\n                                                }\n                                              ],\n                                              \"eventList\": [\n                                                {\n                                                  \"name\": \"onBlur\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onChange\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onDeselect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onFocus\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onInputKeyDown\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseEnter\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseLeave\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onPopupScroll\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onSearch\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onSelect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onDropdownVisibleChange\",\n                                                  \"disabled\": false\n                                                }\n                                              ]\n                                            },\n                                            \"onChange\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleProjectChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            },\n                                            \"onSearch\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleProjectSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            }\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1m12\",\n                                      \"props\": {\n                                        \"label\": \"版本号\",\n                                        \"name\": \"buildId\"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Input\",\n                                          \"id\": \"node_ocksfuhwhs3\",\n                                          \"props\": {\n                                            \"placeholder\": \"请输入版本号\",\n                                            \"style\": {\n                                              \"width\": \"180px\"\n                                            },\n                                            \"size\": \"middle\",\n                                            \"bordered\": true\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1m18\",\n                                      \"props\": {\n                                        \"label\": \"构建人\",\n                                        \"name\": \"user_id\"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Select\",\n                                          \"id\": \"node_ocksfuhwhsi\",\n                                          \"props\": {\n                                            \"style\": {\n                                              \"width\": \"210px\"\n                                            },\n                                            \"options\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.state.userOptions\"\n                                            },\n                                            \"showSearch\": true,\n                                            \"defaultActiveFirstOption\": false,\n                                            \"size\": \"middle\",\n                                            \"bordered\": true,\n                                            \"filterOption\": true,\n                                            \"optionFilterProp\": \"label\",\n                                            \"notFoundContent\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.userNotFoundContent\"\n                                            },\n                                            \"showArrow\": false,\n                                            \"placeholder\": \"请输入构建人\",\n                                            \"__events\": {\n                                              \"eventDataList\": [\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onChange\",\n                                                  \"relatedEventName\": \"handleUserChange\"\n                                                },\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onSearch\",\n                                                  \"relatedEventName\": \"handleUserSearch\"\n                                                }\n                                              ],\n                                              \"eventList\": [\n                                                {\n                                                  \"name\": \"onBlur\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onChange\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onDeselect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onFocus\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onInputKeyDown\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseEnter\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseLeave\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onPopupScroll\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onSearch\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onSelect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onDropdownVisibleChange\",\n                                                  \"disabled\": false\n                                                }\n                                              ]\n                                            },\n                                            \"onChange\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleUserChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            },\n                                            \"onSearch\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleUserSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            },\n                                            \"allowClear\": true\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1m19\",\n                                      \"props\": {\n                                        \"label\": \"ID\",\n                                        \"name\": \"id\",\n                                        \"labelAlign\": \"right\",\n                                        \"colon\": true\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Input\",\n                                          \"id\": \"node_ocksfuhwhs8\",\n                                          \"props\": {\n                                            \"placeholder\": \"请输入ID\",\n                                            \"style\": {\n                                              \"width\": \"180px\"\n                                            },\n                                            \"bordered\": true,\n                                            \"size\": \"middle\"\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1mw\",\n                                      \"props\": {\n                                        \"wrapperCol\": {\n                                          \"offset\": 6\n                                        },\n                                        \"labelAlign\": \"right\",\n                                        \"colon\": true,\n                                        \"style\": {\n                                          \"flex\": \"1\",\n                                          \"textAlign\": \"right\"\n                                        }\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Button\",\n                                          \"id\": \"node_ocks8dtt1mx\",\n                                          \"props\": {\n                                            \"type\": \"primary\",\n                                            \"children\": \"查询\",\n                                            \"htmlType\": \"submit\",\n                                            \"shape\": \"default\",\n                                            \"size\": \"middle\"\n                                          }\n                                        }\n                                      ]\n                                    }\n                                  ]\n                                }\n                              ]\n                            },\n                            {\n                              \"componentName\": \"AliAutoDivDefault\",\n                              \"id\": \"node_ockt3t4q856b\",\n                              \"props\": {\n                                \"style\": {}\n                              },\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Button\",\n                                  \"id\": \"node_ockt3t4q85y\",\n                                  \"props\": {\n                                    \"type\": \"link\",\n                                    \"children\": \"新增打包\",\n                                    \"htmlType\": \"button\",\n                                    \"shape\": \"default\",\n                                    \"size\": \"middle\"\n                                  },\n                                  \"condition\": true\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            },\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockshc4ifn1b\",\n              \"props\": {\n                \"childTotalColumns\": 12,\n                \"mode\": \"inset\",\n                \"layoutmode\": \"O\",\n                \"autolayout\": \"(12|1)\"\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockshc4ifn1c\",\n                  \"props\": {\n                    \"isAutoContainer\": true,\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1\n                  },\n                  \"title\": \"子区块\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ockshc4ifn1d\",\n                      \"props\": {\n                        \"wrap\": false,\n                        \"type\": \"body2\",\n                        \"verAlign\": \"middle\",\n                        \"textSpacing\": true,\n                        \"align\": \"left\",\n                        \"flex\": true\n                      },\n                      \"title\": \"段落\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"AliAutoSearchTableDefault\",\n                          \"id\": \"node_ocksfuhwhsx\",\n                          \"props\": {\n                            \"rowKey\": \"key\",\n                            \"dataSource\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.state.pkgs\"\n                            },\n                            \"columns\": [\n                              {\n                                \"title\": \"ID\",\n                                \"dataIndex\": \"id\",\n                                \"key\": \"name\",\n                                \"width\": 80\n                              },\n                              {\n                                \"title\": \"渠道号\",\n                                \"dataIndex\": \"channels\",\n                                \"key\": \"age\",\n                                \"width\": 142,\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh2bq0428\",\n                                      \"props\": {\n                                        \"children\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.item\"\n                                        },\n                                        \"style\": {\n                                          \"display\": \"block\"\n                                        }\n                                      },\n                                      \"loop\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text.split(',')\"\n                                      }\n                                    }\n                                  ]\n                                }\n                              },\n                              {\n                                \"title\": \"版本号\",\n                                \"dataIndex\": \"dic_version\",\n                                \"key\": \"address\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Tooltip\",\n                                      \"id\": \"node_ocksts0jqgj\",\n                                      \"props\": {\n                                        \"title\": {\n                                          \"type\": \"JSSlot\",\n                                          \"value\": [\n                                            {\n                                              \"componentName\": \"Typography.Text\",\n                                              \"id\": \"node_ocksts0jqgn\",\n                                              \"props\": {\n                                                \"children\": {\n                                                  \"type\": \"JSExpression\",\n                                                  \"value\": \"this.item. channelId + ' / ' +  this.item.version\"\n                                                },\n                                                \"style\": {\n                                                  \"display\": \"block\",\n                                                  \"color\": \"#FFFFFF\"\n                                                }\n                                              },\n                                              \"loop\": {\n                                                \"type\": \"JSExpression\",\n                                                \"value\": \"this.text || []\"\n                                              }\n                                            }\n                                          ]\n                                        }\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Typography.Text\",\n                                          \"id\": \"node_ocksts0jqgm\",\n                                          \"props\": {\n                                            \"children\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.text[0].version\"\n                                            }\n                                          }\n                                        }\n                                      ]\n                                    }\n                                  ]\n                                },\n                                \"width\": 120\n                              },\n                              {\n                                \"title\": \"构建Job\",\n                                \"dataIndex\": \"job_name\",\n                                \"width\": 180\n                              },\n                              {\n                                \"title\": \"构建类型\",\n                                \"dataIndex\": \"packaging_type\",\n                                \"width\": 94\n                              },\n                              {\n                                \"title\": \"构建状态\",\n                                \"dataIndex\": \"status\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh3jkxzw\",\n                                      \"props\": {\n                                        \"children\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.statusDesc[this.text]\"\n                                        }\n                                      }\n                                    },\n                                    {\n                                      \"componentName\": \"Icon\",\n                                      \"id\": \"node_ocksh3jkxzx\",\n                                      \"props\": {\n                                        \"type\": \"SyncOutlined\",\n                                        \"size\": 16,\n                                        \"spin\": true,\n                                        \"style\": {\n                                          \"marginLeft\": \"10px\"\n                                        }\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text === 2\"\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 100\n                              },\n                              {\n                                \"title\": \"构建时间\",\n                                \"dataIndex\": \"start_time\",\n                                \"render\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                },\n                                \"width\": 148\n                              },\n                              {\n                                \"title\": \"构建人\",\n                                \"dataIndex\": \"user\",\n                                \"render\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                },\n                                \"width\": 80\n                              },\n                              {\n                                \"title\": \"Jenkins 链接\",\n                                \"dataIndex\": \"jenkins_link\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Link\",\n                                      \"id\": \"node_ocksh64kbx21\",\n                                      \"props\": {\n                                        \"href\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.text\"\n                                        },\n                                        \"target\": \"_blank\",\n                                        \"children\": \"查看\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text\"\n                                      }\n                                    },\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh64kbx22\",\n                                      \"props\": {\n                                        \"children\": \"暂无\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"!this.text\"\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 120\n                              },\n                              {\n                                \"title\": \"测试平台链接\",\n                                \"dataIndex\": \"is_run_testing\",\n                                \"width\": 120,\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Link\",\n                                      \"id\": \"node_ocksh3jkxz3e\",\n                                      \"props\": {\n                                        \"href\": \"http://rivermap.alibaba.net/dashboard/testExecute\",\n                                        \"target\": \"_blank\",\n                                        \"children\": \"查看\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text\"\n                                      }\n                                    },\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh3jkxz3f\",\n                                      \"props\": {\n                                        \"children\": \"暂无\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"!this.text\"\n                                      }\n                                    }\n                                  ]\n                                }\n                              },\n                              {\n                                \"title\": \"触发源\",\n                                \"dataIndex\": \"source\",\n                                \"width\": 120\n                              },\n                              {\n                                \"title\": \"详情\",\n                                \"dataIndex\": \"id\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Button\",\n                                      \"id\": \"node_ocksh8yryw7\",\n                                      \"props\": {\n                                        \"type\": \"link\",\n                                        \"children\": \"查看\",\n                                        \"size\": \"small\",\n                                        \"style\": {\n                                          \"padding\": \"0px\"\n                                        },\n                                        \"__events\": {\n                                          \"eventDataList\": [\n                                            {\n                                              \"type\": \"componentEvent\",\n                                              \"name\": \"onClick\",\n                                              \"relatedEventName\": \"handleDetail\"\n                                            }\n                                          ],\n                                          \"eventList\": [\n                                            {\n                                              \"name\": \"onClick\",\n                                              \"disabled\": true\n                                            }\n                                          ]\n                                        },\n                                        \"onClick\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        }\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 80,\n                                \"fixed\": \"right\"\n                              },\n                              {\n                                \"title\": \"结果\",\n                                \"dataIndex\": \"id\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Button\",\n                                      \"id\": \"node_ocksh9v6jw7\",\n                                      \"props\": {\n                                        \"type\": \"link\",\n                                        \"children\": \"查看\",\n                                        \"size\": \"small\",\n                                        \"style\": {\n                                          \"padding\": \"0px\"\n                                        },\n                                        \"__events\": {\n                                          \"eventDataList\": [\n                                            {\n                                              \"type\": \"componentEvent\",\n                                              \"name\": \"onClick\",\n                                              \"relatedEventName\": \"handleResult\",\n                                              \"paramStr\": \"this.text\"\n                                            }\n                                          ],\n                                          \"eventList\": [\n                                            {\n                                              \"name\": \"onClick\",\n                                              \"disabled\": true\n                                            }\n                                          ]\n                                        },\n                                        \"onClick\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        },\n                                        \"ghost\": false,\n                                        \"href\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.text\"\n                                        }\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 80,\n                                \"fixed\": \"right\"\n                              },\n                              {\n                                \"title\": \"重新执行\",\n                                \"dataIndex\": \"id\",\n                                \"width\": 92,\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Button\",\n                                      \"id\": \"node_ocksh96rad1g\",\n                                      \"props\": {\n                                        \"type\": \"text\",\n                                        \"children\": \"\",\n                                        \"icon\": {\n                                          \"type\": \"JSSlot\",\n                                          \"value\": [\n                                            {\n                                              \"componentName\": \"Icon\",\n                                              \"id\": \"node_ocksh96rad1j\",\n                                              \"props\": {\n                                                \"type\": \"ReloadOutlined\",\n                                                \"size\": 14,\n                                                \"color\": \"#0593d3\",\n                                                \"style\": {\n                                                  \"padding\": \"3px\",\n                                                  \"border\": \"1px solid #0593d3\",\n                                                  \"borderRadius\": \"14px\",\n                                                  \"cursor\": \"pointer\",\n                                                  \"height\": \"22px\"\n                                                },\n                                                \"spin\": false\n                                              }\n                                            }\n                                          ]\n                                        },\n                                        \"shape\": \"circle\",\n                                        \"__events\": {\n                                          \"eventDataList\": [\n                                            {\n                                              \"type\": \"componentEvent\",\n                                              \"name\": \"onClick\",\n                                              \"relatedEventName\": \"reload\"\n                                            }\n                                          ],\n                                          \"eventList\": [\n                                            {\n                                              \"name\": \"onClick\",\n                                              \"disabled\": true\n                                            }\n                                          ]\n                                        },\n                                        \"onClick\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        }\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"fixed\": \"right\"\n                              }\n                            ],\n                            \"actions\": [],\n                            \"pagination\": {\n                              \"total\": {\n                                \"type\": \"JSExpression\",\n                                \"value\": \"this.state.total\"\n                              },\n                              \"defaultPageSize\": 10,\n                              \"onPageChange\": {\n                                \"type\": \"JSFunction\",\n                                \"value\": \"function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                              },\n                              \"defaultPageIndex\": 1\n                            },\n                            \"scrollX\": 1200,\n                            \"isPagination\": true\n                          },\n                          \"condition\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)\"\n                          }\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            },\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ocksk6f8fa3b\",\n              \"props\": {\n                \"childTotalColumns\": 12,\n                \"mode\": \"inset\",\n                \"layoutmode\": \"O\",\n                \"autolayout\": \"(12|1)\"\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ocksk6f8fa3c\",\n                  \"props\": {\n                    \"isAutoContainer\": true,\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1\n                  },\n                  \"title\": \"子区块\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ocksk6f8fa3d\",\n                      \"props\": {\n                        \"wrap\": false,\n                        \"type\": \"body2\",\n                        \"verAlign\": \"middle\",\n                        \"textSpacing\": true,\n                        \"align\": \"left\",\n                        \"flex\": true\n                      },\n                      \"title\": \"段落\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"Empty\",\n                          \"id\": \"node_ocksk6f8fa3e\",\n                          \"props\": {\n                            \"description\": \"暂无数据\"\n                          },\n                          \"condition\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"this.state.pkgs.length < 1 && this.state.isSearch\"\n                          }\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/public/SchemaParser/p0-basic.test.ts",
    "content": "import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { SchemaParser } from '../../../src';\nimport SCHEMA_WITH_SLOT from './data/schema-with-slot.json';\n\ndescribe('tests/public/SchemaParser/p0-basics', () => {\n  it('should be able to get dependencies in slots', () => {\n    const schemaParser = new SchemaParser();\n    const result = schemaParser.parse(SCHEMA_WITH_SLOT as IPublicTypeProjectSchema);\n    expect(result.containers.map((c) => c.deps)).toMatchSnapshot();\n    expect(result.containers[0].deps?.some((dep) => dep.componentName === 'Tooltip')).toBeTruthy();\n    expect(result.containers[0].deps?.some((dep) => dep.componentName === 'Icon')).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/public/cli.test.ts",
    "content": "import * as fs from 'fs';\nimport * as path from 'path';\nimport { spawnSync } from 'child_process';\n\nconst PROJECT_ROOT = path.resolve(__dirname, '../..');\n\ndescribe('cli - lowcode-code-generator', () => {\n  it('should works', () => {\n    const res = spawnSync('node bin/lowcode-code-generator --solution icejs example-schema.json', {\n      shell: true,\n      stdio: 'pipe',\n      encoding: 'utf8',\n      cwd: PROJECT_ROOT,\n    });\n\n    expect({\n      status: res.status,\n      stdout: res.stdout,\n      stderr: res.stderr,\n    }).toMatchInlineSnapshot(`\n      Object {\n        \"status\": 0,\n        \"stderr\": \"\",\n        \"stdout\": \"\",\n      }\n    `);\n\n    expect(\n      fs.existsSync(path.join(PROJECT_ROOT, 'generated/src/pages/Test/index.jsx')),\n    ).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/public/publisher/disk/disk.test.ts",
    "content": "import CodeGen from '../../../../src';\nimport { ResultDir } from '@alilc/lowcode-types';\n\ndescribe('public/publisher/disk/disk', () => {\n  // standalone 模式下没有 disk publisher\n  if (process.env.TEST_TARGET === 'standalone') {\n    it('should ignore', () => {\n      expect(true).toBe(true);\n    });\n    return;\n  }\n\n  it('should works', async () => {\n    const disk = CodeGen.publishers.disk({\n      outputPath: 'demo-output',\n      projectSlug: 'example-project',\n    });\n\n    const demoProject: ResultDir = {\n      name: 'demo',\n      dirs: [],\n      files: [\n        {\n          name: 'package',\n          ext: 'json',\n          content: '{ \"name\": \"demo\", \"version\": \"1.0.0\" }',\n        },\n      ],\n    };\n\n    expect(disk.getOutputPath()).toMatchInlineSnapshot(`\"demo-output\"`);\n\n    disk.setProject(demoProject);\n    expect(disk.getProject()).toBeTruthy();\n\n    expect(disk.getOutputPath()).toMatchInlineSnapshot(`\"demo-output\"`);\n    expect(disk.setOutputPath('output')).toBe(undefined);\n    expect(disk.getOutputPath()).toMatchInlineSnapshot(`\"output\"`);\n\n    const publishRes = await disk.publish({\n      project: demoProject,\n    });\n\n    expect(publishRes.success).toBeTruthy();\n    expect(publishRes.payload).toBeTruthy();\n  });\n\n  it('should throws Error when project is missing', async () => {\n    const disk = CodeGen.publishers.disk({});\n    expect(disk.publish()).rejects.toBeTruthy();\n\n    expect(() => {\n      return disk.getProject();\n    }).toThrowError(/MissingProject/);\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/public/publisher/zip/zip.test.ts",
    "content": "import CodeGen from '../../../../src';\nimport fileSaver from 'file-saver';\nimport * as utils from '../../../../src/publisher/zip/utils';\n\njest.mock('file-saver');\n\ndescribe('public/publisher/zip/zip', () => {\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  it('should works', async () => {\n    const zip = CodeGen.publishers.zip({\n      outputPath: 'demo-output',\n      projectSlug: 'example-project',\n    });\n\n    const demoProject = {\n      name: 'demo',\n      dirs: [],\n      files: [\n        {\n          name: 'package',\n          ext: 'json',\n          content: '{ \"name\": \"demo\", \"version\": \"1.0.0\" }',\n        },\n      ],\n    };\n\n    expect(zip.getOutputPath()).toMatchInlineSnapshot('\"demo-output\"');\n\n    expect(zip.getProject()).toMatchInlineSnapshot('undefined');\n    zip.setProject(demoProject);\n    expect(zip.getProject()).toBeTruthy();\n\n    expect(zip.getOutputPath()).toMatchInlineSnapshot('\"demo-output\"');\n    expect(zip.setOutputPath('output')).toBe(undefined);\n    expect(zip.getOutputPath()).toMatchInlineSnapshot('\"output\"');\n\n    const publishRes = await zip.publish({\n      project: demoProject,\n    });\n\n    expect(publishRes.success).toBeTruthy();\n    expect(publishRes.payload).toBeTruthy();\n  });\n\n  it('should throws Error when project is missing', async () => {\n    const zip = CodeGen.publishers.zip({});\n    expect(zip.publish()).rejects.toBeTruthy();\n  });\n\n  it('should publish the project as a zip file in the browser', async () => {\n    const zipContent = 'zip content';\n    const zipName = 'example-project';\n    jest.spyOn(utils, 'isNodeProcess').mockReturnValue(false);\n    // new Zip 里面也有平台判断，所以这里 mock\n    jest.spyOn(utils, 'generateProjectZip').mockResolvedValue(zipContent as any);\n    const spy = jest.spyOn(fileSaver, 'saveAs');\n\n    const zip = CodeGen.publishers.zip({\n      projectSlug: zipName,\n    });\n\n    const demoProject = {\n      name: 'demo',\n      dirs: [],\n      files: [\n        {\n          name: 'package',\n          ext: 'json',\n          content: '{ \"name\": \"demo\", \"version\": \"1.0.0\" }',\n        },\n      ],\n    };\n\n    zip.setProject(demoProject);\n    const publishRes = await zip.publish({\n      project: demoProject,\n    });\n\n    expect(publishRes.success).toBeTruthy();\n    expect(spy).toBeCalledWith(zipContent, `${zipName}.zip`);\n    spy.mockReset();\n    spy.mockRestore();\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/public/solutions/icejs3-app.test.ts",
    "content": "import 'jest';\nimport fs from 'fs';\nimport glob from 'glob';\nimport JSON from 'json5';\nimport path from 'path';\n\nimport {\n  getSubDirectoriesSync,\n  removeActualDirRecursiveSync,\n  createDiskPublisher,\n} from '../../helpers/solutionHelper';\n\nimport CodeGenerator from '../../../src';\n\nimport type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\n\njest.setTimeout(15 * 1000);\n\nconst TEST_CASES_DIR = path.join(__dirname, '../../fixtures/test-cases/icejs3-app');\nconst SHOULD_UPDATE_EXPECTED = process.env.UPDATE_EXPECTED === 'true';\n\ngetSubDirectoriesSync(TEST_CASES_DIR).forEach(defineTest);\n\nfunction defineTest(caseDirName: string) {\n  test(`react-app (icejs 3)/${caseDirName} should works`, async () => {\n    try {\n      const caseFullDir = path.join(TEST_CASES_DIR, caseDirName);\n      const schema = JSON.parse(fs.readFileSync(path.join(caseFullDir, 'schema.json5'), 'utf-8'));\n      const actualDir = path.join(caseFullDir, SHOULD_UPDATE_EXPECTED ? 'expected' : 'actual');\n\n      removeActualDirRecursiveSync(actualDir, caseFullDir);\n\n      await exportProject(schema, actualDir, 'demo-project');\n\n      const actualFiles = glob.sync('**/*.{js,jsx,json,ts,tsx,less,css,scss,sass}', {\n        cwd: actualDir,\n      });\n\n      expect(actualFiles.length > 0).toBeTruthy();\n\n      // runPrettierSync(actualFiles, actualDir);\n\n      if (!SHOULD_UPDATE_EXPECTED) {\n        expect(caseFullDir).toBeSameFileContents();\n      }\n    } catch (e) {\n      throw e; // just for debugger\n    }\n  });\n}\n\nasync function exportProject(schemaJson: IPublicTypeProjectSchema, targetPath: string, projectName: string) {\n  const icejs3AppBuilder = CodeGenerator.solutions.icejs3();\n  const result = await icejs3AppBuilder.generateProject(schemaJson);\n\n  const publisher = createDiskPublisher();\n  await publisher.publish({\n    project: result,\n    outputPath: targetPath,\n    projectSlug: projectName,\n    createProjectFolder: true,\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/public/solutions/rax-app.test.ts",
    "content": "import 'jest';\nimport fs from 'fs';\nimport glob from 'glob';\nimport JSON from 'json5';\nimport path from 'path';\n\nimport {\n  getSubDirectoriesSync,\n  removeActualDirRecursiveSync,\n  runPrettierSync,\n  createDiskPublisher,\n} from '../../helpers/solutionHelper';\n\nimport CodeGenerator from '../../../src';\n\nimport type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\n\njest.setTimeout(15 * 1000);\n\nconst TEST_CASES_DIR = path.join(__dirname, '../../fixtures/test-cases/rax-app');\nconst SHOULD_UPDATE_EXPECTED = process.env.UPDATE_EXPECTED === 'true';\n\ngetSubDirectoriesSync(TEST_CASES_DIR).forEach(defineTest);\n\nfunction defineTest(caseDirName: string) {\n  test(`rax-app/${caseDirName} should works`, async () => {\n    try {\n      const caseFullDir = path.join(TEST_CASES_DIR, caseDirName);\n      const schema = JSON.parse(fs.readFileSync(path.join(caseFullDir, 'schema.json5'), 'utf-8'));\n      const actualDir = path.join(caseFullDir, SHOULD_UPDATE_EXPECTED ? 'expected' : 'actual');\n\n      removeActualDirRecursiveSync(actualDir, caseFullDir);\n\n      await exportProject(schema, actualDir, 'demo-project');\n\n      const actualFiles = glob.sync('**/*.{js,jsx,json,ts,tsx,less,css,scss,sass}', {\n        cwd: actualDir,\n      });\n\n      expect(actualFiles.length > 0).toBeTruthy();\n\n      runPrettierSync(actualFiles, actualDir);\n\n      if (!SHOULD_UPDATE_EXPECTED) {\n        expect(caseFullDir).toBeSameFileContents();\n      }\n    } catch (e) {\n      throw e; // just for debugger\n    }\n  });\n}\n\nasync function exportProject(schemaJson: IPublicTypeProjectSchema, targetPath: string, projectName: string) {\n  const raxAppBuilder = CodeGenerator.solutions.rax();\n  const result = await raxAppBuilder.generateProject(schemaJson);\n\n  const publisher = createDiskPublisher();\n  await publisher.publish({\n    project: result,\n    outputPath: targetPath,\n    projectSlug: projectName,\n    createProjectFolder: true,\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/public/solutions/react-app.test.ts",
    "content": "import 'jest';\nimport fs from 'fs';\nimport glob from 'glob';\nimport JSON from 'json5';\nimport path from 'path';\n\nimport {\n  getSubDirectoriesSync,\n  removeActualDirRecursiveSync,\n  createDiskPublisher,\n} from '../../helpers/solutionHelper';\n\nimport CodeGenerator from '../../../src';\n\nimport type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\n\njest.setTimeout(15 * 1000);\n\nconst TEST_CASES_DIR = path.join(__dirname, '../../fixtures/test-cases/react-app');\nconst SHOULD_UPDATE_EXPECTED = process.env.UPDATE_EXPECTED === 'true';\n\ngetSubDirectoriesSync(TEST_CASES_DIR).forEach(defineTest);\n\nfunction defineTest(caseDirName: string) {\n  test(`react-app/${caseDirName} should works`, async () => {\n    try {\n      const caseFullDir = path.join(TEST_CASES_DIR, caseDirName);\n      const schema = JSON.parse(fs.readFileSync(path.join(caseFullDir, 'schema.json5'), 'utf-8'));\n      const actualDir = path.join(caseFullDir, SHOULD_UPDATE_EXPECTED ? 'expected' : 'actual');\n\n      removeActualDirRecursiveSync(actualDir, caseFullDir);\n\n      await exportProject(schema, actualDir, 'demo-project');\n\n      const actualFiles = glob.sync('**/*.{js,jsx,json,ts,tsx,less,css,scss,sass}', {\n        cwd: actualDir,\n      });\n\n      expect(actualFiles.length > 0).toBeTruthy();\n\n      // runPrettierSync(actualFiles, actualDir);\n\n      if (!SHOULD_UPDATE_EXPECTED) {\n        expect(caseFullDir).toBeSameFileContents();\n      }\n    } catch (e) {\n      throw e; // just for debugger\n    }\n  });\n}\n\nasync function exportProject(schemaJson: IPublicTypeProjectSchema, targetPath: string, projectName: string) {\n  const reactAppBuilder = CodeGenerator.solutions.icejs();\n  const result = await reactAppBuilder.generateProject(schemaJson);\n\n  const publisher = createDiskPublisher();\n  await publisher.publish({\n    project: result,\n    outputPath: targetPath,\n    projectSlug: projectName,\n    createProjectFolder: true,\n  });\n}\n"
  },
  {
    "path": "modules/code-generator/tests/utils/compositeType.test.ts",
    "content": "import { generateCompositeType } from '../../src/utils/compositeType';\nimport { parseExpressionConvertThis2Context } from '../../src/utils/expressionParser';\nimport { Scope } from '../../src/utils/Scope';\n\ntest('single line string', () => {\n  expect(generateCompositeType('ab c', Scope.createRootScope())).toEqual('\"ab c\"');\n});\n\ntest('multi line string', () => {\n  expect(generateCompositeType('a\\nb\\nc', Scope.createRootScope())).toEqual('\"a\\\\nb\\\\nc\"');\n});\n\ntest('string with single quote', () => {\n  expect(generateCompositeType(\"a'bc\", Scope.createRootScope())).toEqual('\"a\\'bc\"');\n});\n\ntest('string with double quote', () => {\n  expect(generateCompositeType('a\"bc', Scope.createRootScope())).toEqual('\"a\\\\\"bc\"');\n});\n\nconst marcoFactory = () => {\n  const cases: any[] = [];\n\n  const marco = (value: any, cb: (expression: string) => void) => {\n    cases.push([value, cb]);\n  };\n\n  const start = () => {\n    test.each(cases)('parse expression %s', (item, cb) => {\n      const testObj = {\n        globalConfig: {},\n        online: [\n          {\n            description: '表格（CnTable）的数据源',\n            initialData: {\n              type: 'variable',\n              variable: item,\n              value: '',\n            },\n            somethingelse: 'somethingelse',\n          },\n        ],\n      };\n      const ret = generateCompositeType(testObj, Scope.createRootScope(), {\n        handlers: {\n          function: (jsFunc) => parseExpressionConvertThis2Context(jsFunc.value, '_this'),\n          expression: (jsExpr) => parseExpressionConvertThis2Context(jsExpr.value, '_this'),\n        },\n      });\n      cb(ret);\n    });\n  };\n\n  return { marco, start };\n};\n\nconst { marco: testMarco, start: startMarco } = marcoFactory();\n\n/**\n * dataSource 为低码编辑器里面数据源的输入\n * variable 为 schema 存储的结果\n * expect 为出码后期望生产的串\n\n * |dataSource         | variable                   | expect\n * |-------------------|----------------------------|--------------\n * |\"\"                 | \"\\\"\\\"\"                     | \"\"\n * |\"helo world\"       | \"\\\"hello world\\\"\"          | \"hello world\"\n * |true               | \"true\"                     | true\n * |false              | \"false\"                    | false\n * |{\"name\": gaokai}   | \"{\\\"name\\\": \\\"cone\\\"}\"     | {\"name\": gaokai}\n * |                   | \"\"                         | undefined\n * |undefined          | \"undefined\"                | undefined\n * |null               | \"null\"                     | null\n */\n\ntestMarco('\"\"', (expression) => {\n  expect(expression).toMatchInlineSnapshot(`\n    \"{\\\\\"globalConfig\\\\\": {},\n    \\\\\"online\\\\\": [{\\\\\"description\\\\\": \\\\\"表格（CnTable）的数据源\\\\\",\n    \\\\\"initialData\\\\\": \\\\\"\\\\\",\n    \\\\\"somethingelse\\\\\": \\\\\"somethingelse\\\\\"}]}\"\n  `);\n});\n\ntestMarco('\"hello world\"', (expression) => {\n  expect(expression).toMatchInlineSnapshot(`\n    \"{\\\\\"globalConfig\\\\\": {},\n    \\\\\"online\\\\\": [{\\\\\"description\\\\\": \\\\\"表格（CnTable）的数据源\\\\\",\n    \\\\\"initialData\\\\\": \\\\\"hello world\\\\\",\n    \\\\\"somethingelse\\\\\": \\\\\"somethingelse\\\\\"}]}\"\n  `);\n});\n\ntestMarco('true', (expression) => {\n  expect(expression).toMatchInlineSnapshot(`\n    \"{\\\\\"globalConfig\\\\\": {},\n    \\\\\"online\\\\\": [{\\\\\"description\\\\\": \\\\\"表格（CnTable）的数据源\\\\\",\n    \\\\\"initialData\\\\\": true,\n    \\\\\"somethingelse\\\\\": \\\\\"somethingelse\\\\\"}]}\"\n  `);\n});\n\ntestMarco('{\"name\": \"cone\"}', (expression) => {\n  expect(expression).toMatchInlineSnapshot(`\n    \"{\\\\\"globalConfig\\\\\": {},\n    \\\\\"online\\\\\": [{\\\\\"description\\\\\": \\\\\"表格（CnTable）的数据源\\\\\",\n    \\\\\"initialData\\\\\": {\n      \\\\\"name\\\\\": \\\\\"cone\\\\\"\n    },\n    \\\\\"somethingelse\\\\\": \\\\\"somethingelse\\\\\"}]}\"\n  `);\n});\n\ntestMarco('', (expression) => {\n  expect(expression).toMatchInlineSnapshot(`\n    \"{\\\\\"globalConfig\\\\\": {},\n    \\\\\"online\\\\\": [{\\\\\"description\\\\\": \\\\\"表格（CnTable）的数据源\\\\\",\n    \\\\\"initialData\\\\\": undefined,\n    \\\\\"somethingelse\\\\\": \\\\\"somethingelse\\\\\"}]}\"\n  `);\n});\n\ntestMarco('undefined', (expression) => {\n  expect(expression).toMatchInlineSnapshot(`\n    \"{\\\\\"globalConfig\\\\\": {},\n    \\\\\"online\\\\\": [{\\\\\"description\\\\\": \\\\\"表格（CnTable）的数据源\\\\\",\n    \\\\\"initialData\\\\\": undefined,\n    \\\\\"somethingelse\\\\\": \\\\\"somethingelse\\\\\"}]}\"\n  `);\n});\n\ntestMarco('null', (expression) => {\n  expect(expression).toMatchInlineSnapshot(`\n    \"{\\\\\"globalConfig\\\\\": {},\n    \\\\\"online\\\\\": [{\\\\\"description\\\\\": \\\\\"表格（CnTable）的数据源\\\\\",\n    \\\\\"initialData\\\\\": null,\n    \\\\\"somethingelse\\\\\": \\\\\"somethingelse\\\\\"}]}\"\n  `);\n});\n\nstartMarco();\n"
  },
  {
    "path": "modules/code-generator/tests/utils/errors.test.ts",
    "content": "import { getErrorMessage } from '../../src/utils/errors';\n\ndescribe('getErrorMessage', () => {\n  it('can deal normal error', () => {\n    expect(getErrorMessage(new Error('test'))).toBe('test');\n  });\n\n  it('can deal error object with message field', () => {\n    expect(getErrorMessage({ message: 'test' })).toBe('test');\n  });\n\n  it('can deal null', () => {\n    expect(getErrorMessage(null)).toBe(null);\n  });\n\n  it('can deal string', () => {\n    expect(getErrorMessage('test')).toBe('test');\n  });\n\n  it('can deal error object with detail', () => {\n    expect(getErrorMessage({ detail: 'test' })).toBe('test');\n  });\n\n  it('can deal error object with errorMessage', () => {\n    expect(getErrorMessage({ errorMessage: 'test' })).toBe('test');\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/utils/expressionParser/jsExpression.test.ts",
    "content": "import { generateFunction } from '../../../src/utils/jsExpression';\n\nconst marcoFactory = () => {\n  const cases: any[] = [];\n\n  const marco = (\n    value: { type: string; value: string },\n    config: Record<string, string | boolean>,\n    expected: any,\n  ) => {\n    cases.push([value, config, expected]);\n  };\n\n  const start = () => {\n    test.each(cases)(`after convert this to context \"${1}\" should be \"${3}\"`, (a, b, expected) => {\n      expect(generateFunction(a, b)).toEqual(expected);\n    });\n  };\n\n  return { marco, start };\n};\n\nconst { marco: testMarco, start: startMarco } = marcoFactory();\n\n// 支持普通函数\ntestMarco(\n  {\n    type: 'JSFunction',\n    value: 'function isDisabled(row, rowIndex) { \\n  \\n}',\n  },\n  { isArrow: true },\n  '(row, rowIndex) => {}',\n);\n\n// 支持 jsx 表达式\ntestMarco(\n  {\n    type: 'JSFunction',\n    value: 'function content() { \\n  return <div>我是自定义在div内容123</div> \\n}',\n  },\n  { isArrow: true },\n  '() => {\\n  return <div>我是自定义在div内容123</div>;\\n}',\n);\n\nstartMarco();\n"
  },
  {
    "path": "modules/code-generator/tests/utils/expressionParser/parseExpressionConvertThis2Context.test.ts",
    "content": "import { parseExpressionConvertThis2Context } from '../../../src/utils/expressionParser';\n\n// return providedTitle || `after convert this to context \"${input[0]}\" should be \"${expected}\"`.replace(/\\n|\\s+/g, ' ');\n\nconst marcoFactory = () => {\n  const cases: any[] = [];\n\n  const marco = (input: any[], expected: string) => {\n    const tmpInput = [...input];\n    while (tmpInput.length < 3) {\n      tmpInput.push(undefined);\n    }\n    cases.push([...tmpInput, expected]);\n  };\n\n  const start = () => {\n    test.each(cases)(\n      `after convert this to context \"${1}\" should be \"${4}\"`,\n      (a, b, c, expected) => {\n        expect(parseExpressionConvertThis2Context(a, b, c)).toEqual(expected);\n      },\n    );\n  };\n\n  return { marco, start };\n};\n\nconst { marco: testMarco, start: startMarco } = marcoFactory();\n\ntestMarco(['this.hello', '__$$context', []], '__$$context.hello');\ntestMarco(['this.utils.recordEvent', '__$$context', []], '__$$context.utils.recordEvent');\n\ntestMarco(\n  ['this.utils.recordEvent.bind(this)', '__$$context', []],\n  '__$$context.utils.recordEvent.bind(__$$context)',\n);\n\ntestMarco(['this.item', '__$$context', ['item']], 'item');\n\ntestMarco(['this.user.name', '__$$context', ['user']], 'user.name');\n\ntestMarco(['function (){}', '__$$context', []], 'function () {}');\n\ntestMarco(\n  ['function (){ this.utils.Toast.show(\"Hello world!\") }', '__$$context'],\n  'function () {\\n  __$$context.utils.Toast.show(\"Hello world!\");\\n}',\n);\n\n// 变量能被替换掉\ntestMarco(\n  ['function (){ this.utils.recordEvent(\"click\", this.item) }', '__$$context', ['item']],\n  'function () {\\n  __$$context.utils.recordEvent(\"click\", item);\\n}',\n);\n\n// 只替换顶层的，不替换内层\ntestMarco(\n  [\n    'function (){ return function (){ this.utils.recordEvent(\"click\", this.item) } }',\n    '__$$context',\n    ['item'],\n  ],\n  'function () {\\n  return function () {\\n    this.utils.recordEvent(\"click\", item);\\n  };\\n}',\n);\n\n// 只替换顶层的，不替换内层\ntestMarco(\n  [\n    'function onClick(){ return function (){ this.utils.recordEvent(\"click\", this.item) } }',\n    '__$$context',\n    ['item'],\n  ],\n  'function onClick() {\\n  return function () {\\n    this.utils.recordEvent(\"click\", item);\\n  };\\n}',\n);\n\n// 只替换顶层的，不替换内层\ntestMarco(\n  [\n    '() => { return function (){ this.utils.recordEvent(\"click\", this.item) } }',\n    '__$$context',\n    ['item'],\n  ],\n  '() => {\\n  return function () {\\n    this.utils.recordEvent(\"click\", item);\\n  };\\n}',\n);\n\n// 但是若内层有用箭头函数定义的则还是要替换下\ntestMarco(\n  [\n    '() => { return () => { this.utils.recordEvent(\"click\", this.item) } }',\n    '__$$context',\n    ['item'],\n  ],\n  '() => {\\n  return () => {\\n    __$$context.utils.recordEvent(\"click\", item);\\n  };\\n}',\n);\n\nstartMarco();\n"
  },
  {
    "path": "modules/code-generator/tests/utils/expressionParser/parseExpressionGetGlobalVariables.test.ts",
    "content": "import {\n  parseExpressionGetGlobalVariables,\n  // ParseExpressionGetGlobalVariablesOptions,\n} from '../../../src/utils/expressionParser';\n\nconst marcoFactory = () => {\n  const cases: any[] = [];\n\n  const marco = (input: any[], expected: string[]) => {\n    const tmpInput = [...input];\n    while (tmpInput.length < 2) {\n      tmpInput.push(undefined);\n    }\n    cases.push([...tmpInput, expected]);\n  };\n\n  const start = () => {\n    test.each(cases)(`global variables of \"${1}\" should be \"${3}\"`, (a, b, expected) => {\n      expect(parseExpressionGetGlobalVariables(a, b)).toEqual(expected);\n    });\n  };\n\n  return { marco, start };\n};\n\nconst { marco: testMarco, start: startMarco } = marcoFactory();\n\ntestMarco(['function (){ }', {}], []);\ntestMarco(['function (){ __$$context.utils.Toast.show(\"Hello world!\") }', {}], ['__$$context']);\n\ntestMarco(\n  ['function (){ __$$context.utils.formatPrice(item.price1, \"元\") }', {}],\n  ['__$$context', 'item'],\n);\n\ntestMarco(\n  [\n    'function (){ __$$context.utils.formatPrice(item2, \"元\"); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item2'],\n);\n\ntestMarco(\n  [\n    'function (){ __$$context.utils.log(item3, [item4, item5]); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item3', 'item4', 'item5'],\n);\n\ntestMarco(\n  [\n    'function (){ item3[item4](\"Hello\"); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item3', 'item4'],\n);\n\ntestMarco(\n  ['function (){ item3(\"Hello\"); }', { filter: (varName: string) => !/^__\\$\\$/.test(varName) }],\n  ['item3'],\n);\n\ntestMarco(\n  [\n    'function foo(){ foo[item3](\"Hello\"); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item3'],\n);\n\n// isAssignmentExpression/right\ntestMarco(\n  [\n    'function (){ let foo; foo = item3; foo(); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item3'],\n);\n\n// isAssignmentExpression/left\ntestMarco(\n  ['function (){ foo = item3; foo(); }', { filter: (varName: string) => !/^__\\$\\$/.test(varName) }],\n  ['foo', 'item3'],\n);\n\n// isVariableDeclarator\ntestMarco(\n  [\n    'function (){ const foo = item3; foo(); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item3'],\n);\n\n// isVariableDeclarator\ntestMarco(\n  [\n    'function (){ let foo = item3; foo(); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item3'],\n);\n\n// isVariableDeclarator\ntestMarco(\n  [\n    'function (){ var foo = item3; foo(); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['item3'],\n);\n\n// isTemplateLiteral\ntestMarco(\n  [\n    'function (){ console.log(`Hello ${item3};`); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['console', 'item3'],\n);\n\n// isBinaryExpression\ntestMarco(\n  [\n    'function (){ console.log(item2 | item3); }',\n    { filter: (varName: string) => !/^__\\$\\$/.test(varName) },\n  ],\n  ['console', 'item2', 'item3'],\n);\n\n// TODO: 补充更多类型的测试用例\nstartMarco();\n"
  },
  {
    "path": "modules/code-generator/tests/utils/expressionParser/parseExpressionGetKeywords.test.ts",
    "content": "import { parseExpressionGetKeywords } from '../../../src/utils/expressionParser';\n\nconst marcoFactory = () => {\n  const cases: any[] = [];\n\n  const marco = (input: string | null, expected: any) => {\n    cases.push([input, expected]);\n  };\n\n  const start = () => {\n    test.each(cases)(\n      `after convert this to context \"${1}\" should be \"${2}\"`,\n      (a, expected) => {\n        expect(parseExpressionGetKeywords(a)).toEqual(expected);\n      },\n    );\n  };\n\n  return { marco, start };\n};\n\nconst { marco: testMarco, start: startMarco } = marcoFactory();\n\n// 支持普通函数\ntestMarco('function isDisabled(row) {}', []);\ntestMarco('function content() { \\n  return \"hello world\"\\n}', []);\n\n// 支持 jsx 表达式\ntestMarco('function content() { \\n  return <div>自定义在div内容123</div> \\n}', []);\n\nstartMarco();\n"
  },
  {
    "path": "modules/code-generator/tests/utils/flattenResult.test.ts",
    "content": "import { flattenResult } from '../../src/utils/resultHelper';\n\ntest('utils/flattenResult', () => {\n  expect(\n    flattenResult({\n      name: 'demo',\n      dirs: [\n        {\n          name: 'src',\n          dirs: [\n            {\n              name: 'components',\n              dirs: [\n                {\n                  name: 'Hello',\n                  dirs: [],\n                  files: [\n                    {\n                      name: 'index',\n                      ext: 'js',\n                      content: 'export default () => <div>Hello</div>',\n                    },\n                  ],\n                },\n              ],\n              files: [\n                {\n                  name: 'index',\n                  ext: 'js',\n                  content: 'export * from \"./Hello\";',\n                },\n              ],\n            },\n          ],\n          files: [{ name: 'index', ext: 'js', content: 'console.log(\"Hello\")' }],\n        },\n      ],\n      files: [{ name: '.eslintrc', ext: '', content: '{}' }],\n    }),\n  ).toMatchInlineSnapshot(`\n    Array [\n      Object {\n        \"content\": \"{}\",\n        \"pathName\": \".eslintrc\",\n      },\n      Object {\n        \"content\": \"console.log(\\\\\"Hello\\\\\")\",\n        \"pathName\": \"src/index.js\",\n      },\n      Object {\n        \"content\": \"export * from \\\\\"./Hello\\\\\";\",\n        \"pathName\": \"src/components/index.js\",\n      },\n      Object {\n        \"content\": \"export default () => <div>Hello</div>\",\n        \"pathName\": \"src/components/Hello/index.js\",\n      },\n    ]\n  `);\n});\n"
  },
  {
    "path": "modules/code-generator/tests/utils/resultHelper/example-result.json",
    "content": "{\n  \"name\": \".\",\n  \"dirs\": [\n    {\n      \"name\": \"src\",\n      \"dirs\": [\n        {\n          \"name\": \"components\",\n          \"dirs\": [\n            {\n              \"name\": \"Hello\",\n              \"dirs\": [],\n              \"files\": [\n                {\n                  \"name\": \"index\",\n                  \"ext\": \"js\",\n                  \"content\": \"export default () => <div>Hello</div>\"\n                },\n                {\n                  \"name\": \"index\",\n                  \"ext\": \"css\",\n                  \"content\": \".hello {color: red}\"\n                }\n              ]\n            }\n          ],\n          \"files\": [\n            {\n              \"name\": \"index\",\n              \"ext\": \"js\",\n              \"content\": \"export * from \\\"./Hello\\\";\"\n            }\n          ]\n        }\n      ],\n      \"files\": [\n        { \"name\": \"index\", \"ext\": \"js\", \"content\": \"console.log(\\\"Hello\\\")\" },\n        { \"name\": \"index\", \"ext\": \"css\", \"content\": \"html,body{ padding: 0; }\" }\n      ]\n    }\n  ],\n  \"files\": [\n    { \"name\": \".eslintrc\", \"ext\": \"\", \"content\": \"{}\" },\n    { \"name\": \"package\", \"ext\": \"json\", \"content\": \"{ \\\"name\\\": \\\"demo\\\", \\\"version\\\":\\\"1.0.0\\\" }\" }\n  ]\n}\n"
  },
  {
    "path": "modules/code-generator/tests/utils/resultHelper/findFile.test.ts",
    "content": "import _ from 'lodash';\nimport CodeGen from '../../../src';\n\ndescribe('CodeGen.utils.resultHelper.findFile', () => {\n  it('could package.json by \"package.json\"', () => {\n    const result = require('./example-result.json') as any;\n    const found = CodeGen.utils.resultHelper.findFile(result, 'package.json');\n    expect(found).toMatchInlineSnapshot(`\n      Object {\n        \"content\": \"{ \\\\\"name\\\\\": \\\\\"demo\\\\\", \\\\\"version\\\\\":\\\\\"1.0.0\\\\\" }\",\n        \"ext\": \"json\",\n        \"name\": \"package\",\n      }\n    `);\n  });\n\n  it('could find a internal component by src/components/*/index.js', () => {\n    const result = require('./example-result.json') as any;\n    const found = CodeGen.utils.resultHelper.findFile(result, 'src/components/*/index.js');\n    expect(found).toMatchInlineSnapshot(`\n      Object {\n        \"content\": \"export default () => <div>Hello</div>\",\n        \"ext\": \"js\",\n        \"name\": \"index\",\n      }\n    `);\n  });\n\n  it('could not find non-existing file', () => {\n    const result = require('./example-result.json') as any;\n    const found = CodeGen.utils.resultHelper.findFile(result, 'something-not-exist.js');\n    expect(found).toBeNull();\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/utils/resultHelper/globFiles.test.ts",
    "content": "import _ from 'lodash';\nimport CodeGen from '../../../src';\n\ndescribe('CodeGen.utils.resultHelper.globFiles', () => {\n  it('could find all files exclude dot files by **/*', () => {\n    const result = require('./example-result.json') as any;\n    const files = CodeGen.utils.resultHelper.globFiles(result, '**/*');\n    expect(Array.from(files).map(_.first)).toMatchInlineSnapshot(`\n      Array [\n        \"package.json\",\n        \"src/index.js\",\n        \"src/index.css\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n        \"src/components/Hello/index.css\",\n      ]\n    `);\n  });\n\n  it('could find all files by **/* with option.dot = true ', () => {\n    const result = require('./example-result.json') as any;\n    const files = CodeGen.utils.resultHelper.globFiles(result, '**/*', { dot: true });\n    expect(Array.from(files).map(_.first)).toMatchInlineSnapshot(`\n      Array [\n        \".eslintrc\",\n        \"package.json\",\n        \"src/index.js\",\n        \"src/index.css\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n        \"src/components/Hello/index.css\",\n      ]\n    `);\n  });\n\n  it('could find all js files by **/*.js', () => {\n    const result = require('./example-result.json') as any;\n    const files = CodeGen.utils.resultHelper.globFiles(result, '**/*.js');\n    expect(Array.from(files).map(_.first)).toMatchInlineSnapshot(`\n      Array [\n        \"src/index.js\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n      ]\n    `);\n  });\n\n  it('could find package.json by package.json', () => {\n    const result = require('./example-result.json') as any;\n    const files = CodeGen.utils.resultHelper.globFiles(result, 'package.json');\n    expect(Array.from(files).map(_.first)).toMatchInlineSnapshot(`\n      Array [\n        \"package.json\",\n      ]\n    `);\n  });\n\n  it('could find all index.js in components by **/components/*/index.js', () => {\n    const result = require('./example-result.json') as any;\n    const files = CodeGen.utils.resultHelper.globFiles(result, '**/components/*/index.js');\n    expect(Array.from(files).map(_.first)).toMatchInlineSnapshot(`\n      Array [\n        \"src/components/Hello/index.js\",\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/utils/resultHelper/removeDirsFromResult.test.ts",
    "content": "import type { ResultDir } from '@alilc/lowcode-types';\nimport _ from 'lodash';\nimport CodeGen from '../../../src';\n\nconst loadResult = (): ResultDir => _.cloneDeep(require('./example-result.json'));\n\ndescribe('CodeGen.utils.resultHelper.removeDirsFromResult', () => {\n  it('could remove src by \"src\"', () => {\n    const result = loadResult();\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n        \"src\",\n        \"src/components\",\n        \"src/components/Hello\",\n      ]\n    `);\n\n    const removed = CodeGen.utils.resultHelper.removeDirsFromResult(result, 'src');\n\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n      ]\n    `);\n\n    expect(removed).toBe(1);\n  });\n\n  it('could remove src/components/Hello by \"*/components/*\"', () => {\n    const result = loadResult();\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n        \"src\",\n        \"src/components\",\n        \"src/components/Hello\",\n      ]\n    `);\n\n    const removed = CodeGen.utils.resultHelper.removeDirsFromResult(result, '*/components/*');\n\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n        \"src\",\n        \"src/components\",\n      ]\n    `);\n\n    expect(removed).toBe(1);\n  });\n\n  it('could remove all dirs by \"*\"', () => {\n    const result = loadResult();\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n        \"src\",\n        \"src/components\",\n        \"src/components/Hello\",\n      ]\n    `);\n\n    const removed = CodeGen.utils.resultHelper.removeDirsFromResult(result, '*');\n\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n      ]\n    `);\n\n    expect(removed).toBe(1);\n  });\n\n  it('could remove all dirs by \"**\"', () => {\n    const result = loadResult();\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n        \"src\",\n        \"src/components\",\n        \"src/components/Hello\",\n      ]\n    `);\n\n    const removed = CodeGen.utils.resultHelper.removeDirsFromResult(result, '**');\n\n    expect(listAllDirs(result)).toMatchInlineSnapshot(`\n      Array [\n        \"\",\n      ]\n    `);\n\n    expect(removed).toBe(3);\n  });\n});\n\nfunction listAllDirs(result: ResultDir): string[] {\n  return Array.from(CodeGen.utils.resultHelper.scanDirs(result)).map(([dirPath]) => dirPath);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/utils/resultHelper/removeFilesFromResult.test.ts",
    "content": "import type { ResultDir } from '@alilc/lowcode-types';\nimport _ from 'lodash';\nimport CodeGen from '../../../src';\n\nconst loadResult = (): ResultDir => _.cloneDeep(require('./example-result.json'));\n\ndescribe('CodeGen.utils.resultHelper.removeFilesFromResult', () => {\n  it('could remove package.json by \"package.json\"', () => {\n    const result = loadResult();\n    expect(listAllFiles(result)).toMatchInlineSnapshot(`\n      Array [\n        \".eslintrc\",\n        \"package.json\",\n        \"src/index.js\",\n        \"src/index.css\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n        \"src/components/Hello/index.css\",\n      ]\n    `);\n\n    const removed = CodeGen.utils.resultHelper.removeFilesFromResult(result, 'package.json');\n\n    expect(listAllFiles(result)).toMatchInlineSnapshot(`\n      Array [\n        \".eslintrc\",\n        \"src/index.js\",\n        \"src/index.css\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n        \"src/components/Hello/index.css\",\n      ]\n    `);\n\n    expect(removed).toBe(1);\n  });\n\n  it('could remove .eslintrc.json by \".eslintrc\" with dot=true', () => {\n    const result = loadResult();\n    expect(listAllFiles(result)).toMatchInlineSnapshot(`\n      Array [\n        \".eslintrc\",\n        \"package.json\",\n        \"src/index.js\",\n        \"src/index.css\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n        \"src/components/Hello/index.css\",\n      ]\n    `);\n\n    const removed = CodeGen.utils.resultHelper.removeFilesFromResult(result, '.eslintrc', {\n      dot: true,\n    });\n\n    expect(listAllFiles(result)).toMatchInlineSnapshot(`\n      Array [\n        \"package.json\",\n        \"src/index.js\",\n        \"src/index.css\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n        \"src/components/Hello/index.css\",\n      ]\n    `);\n\n    expect(removed).toBe(1);\n  });\n\n  it('could remove all css files by \"**/*.css\"', () => {\n    const result = loadResult();\n    expect(listAllFiles(result)).toMatchInlineSnapshot(`\n      Array [\n        \".eslintrc\",\n        \"package.json\",\n        \"src/index.js\",\n        \"src/index.css\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n        \"src/components/Hello/index.css\",\n      ]\n    `);\n\n    const removed = CodeGen.utils.resultHelper.removeFilesFromResult(result, '**/*.css');\n\n    expect(listAllFiles(result)).toMatchInlineSnapshot(`\n      Array [\n        \".eslintrc\",\n        \"package.json\",\n        \"src/index.js\",\n        \"src/components/index.js\",\n        \"src/components/Hello/index.js\",\n      ]\n    `);\n\n    expect(removed).toBe(2);\n  });\n});\n\nfunction listAllFiles(result: ResultDir): string[] {\n  return Array.from(CodeGen.utils.resultHelper.scanFiles(result)).map(([filePath]) => filePath);\n}\n"
  },
  {
    "path": "modules/code-generator/tests/utils/resultHelper/scanFiles.test.ts",
    "content": "import CodeGen from '../../../src';\n\ndescribe('CodeGen.utils.resultHelper.scanFiles', () => {\n  it('should works', () => {\n    const result = require('./example-result.json') as any;\n    const files = CodeGen.utils.resultHelper.scanFiles(result);\n    expect(Array.from(files)).toMatchInlineSnapshot(`\n      Array [\n        Array [\n          \".eslintrc\",\n          Object {\n            \"content\": \"{}\",\n            \"ext\": \"\",\n            \"name\": \".eslintrc\",\n          },\n        ],\n        Array [\n          \"package.json\",\n          Object {\n            \"content\": \"{ \\\\\"name\\\\\": \\\\\"demo\\\\\", \\\\\"version\\\\\":\\\\\"1.0.0\\\\\" }\",\n            \"ext\": \"json\",\n            \"name\": \"package\",\n          },\n        ],\n        Array [\n          \"src/index.js\",\n          Object {\n            \"content\": \"console.log(\\\\\"Hello\\\\\")\",\n            \"ext\": \"js\",\n            \"name\": \"index\",\n          },\n        ],\n        Array [\n          \"src/index.css\",\n          Object {\n            \"content\": \"html,body{ padding: 0; }\",\n            \"ext\": \"css\",\n            \"name\": \"index\",\n          },\n        ],\n        Array [\n          \"src/components/index.js\",\n          Object {\n            \"content\": \"export * from \\\\\"./Hello\\\\\";\",\n            \"ext\": \"js\",\n            \"name\": \"index\",\n          },\n        ],\n        Array [\n          \"src/components/Hello/index.js\",\n          Object {\n            \"content\": \"export default () => <div>Hello</div>\",\n            \"ext\": \"js\",\n            \"name\": \"index\",\n          },\n        ],\n        Array [\n          \"src/components/Hello/index.css\",\n          Object {\n            \"content\": \".hello {color: red}\",\n            \"ext\": \"css\",\n            \"name\": \"index\",\n          },\n        ],\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/utils/schema/data/schema-with-slot.json",
    "content": "{\n  \"version\": \"1.0.0\",\n  \"componentsMap\": [\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Slot\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Button\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Button\"\n    },\n    {\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.43\",\n      \"exportName\": \"AliAutoDiv\",\n      \"main\": \"build/lowcode/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoDivDefault\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Text\",\n      \"componentName\": \"Typography.Text\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Typography\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Link\",\n      \"componentName\": \"Typography.Link\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Modal\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Modal\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Select\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Select\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"subName\": \"Item\",\n      \"componentName\": \"Form.Item\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Input\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Input\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Form\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Form\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"P\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextP\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"Cell\",\n      \"componentName\": \"NextBlockCell\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Block\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextBlock\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Tooltip\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Tooltip\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Icon\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Icon\"\n    },\n    {\n      \"package\": \"@alife/mc-assets-1935\",\n      \"version\": \"0.1.43\",\n      \"exportName\": \"AliAutoSearchTable\",\n      \"main\": \"build/lowcode/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"default\",\n      \"componentName\": \"AliAutoSearchTableDefault\"\n    },\n    {\n      \"package\": \"@alilc/antd-lowcode-materials\",\n      \"version\": \"0.11.0\",\n      \"exportName\": \"Empty\",\n      \"main\": \"dist/antd-lowcode.esm.js\",\n      \"destructuring\": true,\n      \"componentName\": \"Empty\"\n    },\n    {\n      \"package\": \"@alife/container\",\n      \"version\": \"0.3.7\",\n      \"exportName\": \"Page\",\n      \"main\": \"lib/index.js\",\n      \"destructuring\": true,\n      \"subName\": \"\",\n      \"componentName\": \"NextPage\"\n    },\n    {\n      \"devMode\": \"lowcode\",\n      \"componentName\": \"Page\"\n    }\n  ],\n  \"componentsTree\": [\n    {\n      \"componentName\": \"Page\",\n      \"id\": \"node_dockcviv8fo1\",\n      \"props\": {\n        \"ref\": \"outterView\",\n        \"style\": {\n          \"height\": \"100%\"\n        }\n      },\n      \"fileName\": \"test\",\n      \"dataSource\": {\n        \"list\": []\n      },\n      \"css\": \"body {\\n  font-size: 12px;\\n}\\n\\n.botton {\\n  width: 100px;\\n  color: #ff00ff\\n}\",\n      \"lifeCycles\": {\n        \"constructor\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"componentDidMount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"componentDidUpdate\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function(prevProps, prevState, snapshot) {}\"\n        },\n        \"componentWillUnmount\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() {}\"\n        }\n      },\n      \"methods\": {\n        \"__jp__init\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initRouter\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initDataSource\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initEnv\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initConfig\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"__jp__initUtils\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"setSearchItem\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"fetchProject\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleProjectSearch\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleProjectChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"fetchUser\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleUserSearch\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleUserChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"fetchPkgs\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"onPageChange\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"renderTime\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"renderUserName\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"reload\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleResult\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleDetail\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"onResultCancel\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"formatResult\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"handleDownload\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        },\n        \"onFinish\": {\n          \"type\": \"JSFunction\",\n          \"value\": \"function() { /*...*/ }\"\n        }\n      },\n      \"state\": {\n        \"pkgs\": [],\n        \"total\": 0,\n        \"isSearch\": false,\n        \"projects\": [],\n        \"results\": [],\n        \"resultVisible\": false,\n        \"userOptions\": [],\n        \"searchValues\": {\n          \"user_id\": \"\",\n          \"channel_id\": \"\"\n        }\n      },\n      \"children\": [\n        {\n          \"componentName\": \"Modal\",\n          \"id\": \"node_ocksh9yppxb\",\n          \"props\": {\n            \"title\": \"查看结果\",\n            \"visible\": {\n              \"type\": \"JSExpression\",\n              \"value\": \"this.state.resultVisible\"\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"value\": [\n                {\n                  \"componentName\": \"Button\",\n                  \"id\": \"node_ocksh9yppxf\",\n                  \"props\": {\n                    \"type\": \"primary\",\n                    \"children\": \"确定\",\n                    \"__events\": {\n                      \"eventDataList\": [\n                        {\n                          \"type\": \"componentEvent\",\n                          \"name\": \"onClick\",\n                          \"relatedEventName\": \"onResultCancel\"\n                        }\n                      ],\n                      \"eventList\": [\n                        {\n                          \"name\": \"onClick\",\n                          \"disabled\": true\n                        }\n                      ]\n                    },\n                    \"onClick\": {\n                      \"type\": \"JSFunction\",\n                      \"value\": \"function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                    }\n                  }\n                }\n              ]\n            },\n            \"__events\": {\n              \"eventDataList\": [\n                {\n                  \"type\": \"componentEvent\",\n                  \"name\": \"onCancel\",\n                  \"relatedEventName\": \"onResultCancel\"\n                }\n              ],\n              \"eventList\": [\n                {\n                  \"name\": \"onCancel\",\n                  \"disabled\": true\n                },\n                {\n                  \"name\": \"onOk\",\n                  \"disabled\": false\n                }\n              ]\n            },\n            \"onCancel\": {\n              \"type\": \"JSFunction\",\n              \"value\": \"function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n            },\n            \"width\": \"720px\",\n            \"centered\": true,\n            \"closable\": true,\n            \"keyboard\": true,\n            \"mask\": true,\n            \"maskClosable\": true\n          },\n          \"hidden\": true,\n          \"children\": [\n            {\n              \"componentName\": \"AliAutoDivDefault\",\n              \"id\": \"node_ockshazuxa4\",\n              \"props\": {\n                \"style\": {\n                  \"width\": \"100%\"\n                }\n              },\n              \"children\": [\n                {\n                  \"componentName\": \"AliAutoDivDefault\",\n                  \"id\": \"node_ockshazuxai\",\n                  \"props\": {\n                    \"style\": {\n                      \"width\": \"100%\",\n                      \"textAlign\": \"left\",\n                      \"marginBottom\": \"16px\"\n                    }\n                  },\n                  \"condition\": {\n                    \"type\": \"JSExpression\",\n                    \"value\": \"this.state.results && this.state.results.length > 0\"\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"Button\",\n                      \"id\": \"node_ockshazuxah\",\n                      \"props\": {\n                        \"type\": \"primary\",\n                        \"children\": \"下载全部\",\n                        \"size\": \"small\",\n                        \"__events\": {\n                          \"eventDataList\": [\n                            {\n                              \"type\": \"componentEvent\",\n                              \"name\": \"onClick\",\n                              \"relatedEventName\": \"handleDownload\"\n                            }\n                          ],\n                          \"eventList\": [\n                            {\n                              \"name\": \"onClick\",\n                              \"disabled\": true\n                            }\n                          ]\n                        },\n                        \"onClick\": {\n                          \"type\": \"JSFunction\",\n                          \"value\": \"function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                        }\n                      }\n                    }\n                  ]\n                },\n                {\n                  \"componentName\": \"AliAutoDivDefault\",\n                  \"id\": \"node_ockt2muyfi4\",\n                  \"props\": {\n                    \"style\": {\n                      \"width\": \"100%\",\n                      \"marginTop\": \"10px\"\n                    }\n                  },\n                  \"loop\": {\n                    \"type\": \"JSExpression\",\n                    \"value\": \"this.state.results\"\n                  },\n                  \"children\": [\n                    {\n                      \"componentName\": \"Typography.Text\",\n                      \"id\": \"node_ockshazuxa5\",\n                      \"props\": {\n                        \"children\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.formatResult(this.item)\"\n                        }\n                      }\n                    },\n                    {\n                      \"componentName\": \"Typography.Link\",\n                      \"id\": \"node_ockshazuxa6\",\n                      \"props\": {\n                        \"href\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.item.download_link\"\n                        },\n                        \"target\": \"_blank\",\n                        \"children\": \" - 点击下载\"\n                      },\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.item.download_link\"\n                      }\n                    },\n                    {\n                      \"componentName\": \"Typography.Link\",\n                      \"id\": \"node_ockshazuxa7\",\n                      \"props\": {\n                        \"href\": {\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.item.release_notes\"\n                        },\n                        \"target\": \"_blank\",\n                        \"children\": \" - 跳转发布节点\"\n                      },\n                      \"condition\": {\n                        \"type\": \"JSExpression\",\n                        \"value\": \"this.item.release_notes\"\n                      }\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"componentName\": \"NextPage\",\n          \"id\": \"node_ocko19zplh1\",\n          \"props\": {\n            \"columns\": 12,\n            \"headerDivider\": true,\n            \"placeholderStyle\": {\n              \"gridRowEnd\": \"span 1\",\n              \"gridColumnEnd\": \"span 12\"\n            },\n            \"placeholder\": \"页面主体内容：拖拽Block布局组件到这里\",\n            \"header\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"header\"\n            },\n            \"headerProps\": {\n              \"background\": \"surface\",\n              \"style\": {\n                \"padding\": \"\"\n              }\n            },\n            \"footer\": {\n              \"type\": \"JSSlot\",\n              \"title\": \"footer\"\n            },\n            \"minHeight\": \"100vh\",\n            \"contentProps\": {\n              \"noPadding\": false,\n              \"background\": \"transparent\"\n            }\n          },\n          \"title\": \"页面\",\n          \"children\": [\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockt3t4q8565\",\n              \"props\": {\n                \"childTotalColumns\": 12\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockt3t4q8566\",\n                  \"props\": {\n                    \"isAutoContainer\": true,\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1\n                  },\n                  \"title\": \"子区块\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ockt3t4q8567\",\n                      \"props\": {\n                        \"wrap\": false,\n                        \"type\": \"body2\",\n                        \"verAlign\": \"middle\",\n                        \"textSpacing\": true,\n                        \"align\": \"left\",\n                        \"flex\": true\n                      },\n                      \"title\": \"段落\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"AliAutoDivDefault\",\n                          \"id\": \"node_ockt3t4q8568\",\n                          \"props\": {\n                            \"style\": {\n                              \"width\": \"100%\",\n                              \"display\": \"flex\"\n                            }\n                          },\n                          \"children\": [\n                            {\n                              \"componentName\": \"AliAutoDivDefault\",\n                              \"id\": \"node_ockt3t4q857a\",\n                              \"props\": {\n                                \"style\": {\n                                  \"flex\": \"1\"\n                                }\n                              },\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Form\",\n                                  \"id\": \"node_ocks8dtt1mt\",\n                                  \"props\": {\n                                    \"labelCol\": {\n                                      \"span\": 10\n                                    },\n                                    \"wrapperCol\": {\n                                      \"span\": 14\n                                    },\n                                    \"onFinish\": {\n                                      \"type\": \"JSFunction\",\n                                      \"value\": \"function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                    },\n                                    \"name\": \"basic\",\n                                    \"layout\": \"inline\",\n                                    \"__events\": {\n                                      \"eventDataList\": [\n                                        {\n                                          \"type\": \"componentEvent\",\n                                          \"name\": \"onFinish\",\n                                          \"relatedEventName\": \"onFinish\"\n                                        }\n                                      ],\n                                      \"eventList\": [\n                                        {\n                                          \"name\": \"onFinish\",\n                                          \"disabled\": true\n                                        },\n                                        {\n                                          \"name\": \"onFinishFailed\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onFieldsChange\",\n                                          \"disabled\": false\n                                        },\n                                        {\n                                          \"name\": \"onValuesChange\",\n                                          \"disabled\": false\n                                        }\n                                      ]\n                                    },\n                                    \"colon\": true,\n                                    \"labelAlign\": \"right\",\n                                    \"preserve\": true,\n                                    \"scrollToFirstError\": true,\n                                    \"size\": \"middle\",\n                                    \"values\": {\n                                      \"type\": \"JSExpression\",\n                                      \"value\": \"this.state.searchValues\"\n                                    }\n                                  },\n                                  \"children\": [\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1mz\",\n                                      \"props\": {\n                                        \"label\": \"项目名称/渠道号\",\n                                        \"name\": \"channel_id\",\n                                        \"labelAlign\": \"right\",\n                                        \"colon\": true\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Select\",\n                                          \"id\": \"node_ocksfuhwhsd\",\n                                          \"props\": {\n                                            \"style\": {\n                                              \"width\": \"320px\"\n                                            },\n                                            \"options\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.state.projects\"\n                                            },\n                                            \"showArrow\": false,\n                                            \"tokenSeparators\": [],\n                                            \"showSearch\": true,\n                                            \"defaultActiveFirstOption\": true,\n                                            \"size\": \"middle\",\n                                            \"bordered\": true,\n                                            \"filterOption\": true,\n                                            \"optionFilterProp\": \"label\",\n                                            \"allowClear\": true,\n                                            \"placeholder\": \"请输入项目名称/渠道号\",\n                                            \"__events\": {\n                                              \"eventDataList\": [\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onChange\",\n                                                  \"relatedEventName\": \"handleProjectChange\"\n                                                },\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onSearch\",\n                                                  \"relatedEventName\": \"handleProjectSearch\"\n                                                }\n                                              ],\n                                              \"eventList\": [\n                                                {\n                                                  \"name\": \"onBlur\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onChange\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onDeselect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onFocus\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onInputKeyDown\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseEnter\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseLeave\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onPopupScroll\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onSearch\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onSelect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onDropdownVisibleChange\",\n                                                  \"disabled\": false\n                                                }\n                                              ]\n                                            },\n                                            \"onChange\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleProjectChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            },\n                                            \"onSearch\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleProjectSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            }\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1m12\",\n                                      \"props\": {\n                                        \"label\": \"版本号\",\n                                        \"name\": \"buildId\"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Input\",\n                                          \"id\": \"node_ocksfuhwhs3\",\n                                          \"props\": {\n                                            \"placeholder\": \"请输入版本号\",\n                                            \"style\": {\n                                              \"width\": \"180px\"\n                                            },\n                                            \"size\": \"middle\",\n                                            \"bordered\": true\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1m18\",\n                                      \"props\": {\n                                        \"label\": \"构建人\",\n                                        \"name\": \"user_id\"\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Select\",\n                                          \"id\": \"node_ocksfuhwhsi\",\n                                          \"props\": {\n                                            \"style\": {\n                                              \"width\": \"210px\"\n                                            },\n                                            \"options\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.state.userOptions\"\n                                            },\n                                            \"showSearch\": true,\n                                            \"defaultActiveFirstOption\": false,\n                                            \"size\": \"middle\",\n                                            \"bordered\": true,\n                                            \"filterOption\": true,\n                                            \"optionFilterProp\": \"label\",\n                                            \"notFoundContent\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.userNotFoundContent\"\n                                            },\n                                            \"showArrow\": false,\n                                            \"placeholder\": \"请输入构建人\",\n                                            \"__events\": {\n                                              \"eventDataList\": [\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onChange\",\n                                                  \"relatedEventName\": \"handleUserChange\"\n                                                },\n                                                {\n                                                  \"type\": \"componentEvent\",\n                                                  \"name\": \"onSearch\",\n                                                  \"relatedEventName\": \"handleUserSearch\"\n                                                }\n                                              ],\n                                              \"eventList\": [\n                                                {\n                                                  \"name\": \"onBlur\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onChange\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onDeselect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onFocus\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onInputKeyDown\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseEnter\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onMouseLeave\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onPopupScroll\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onSearch\",\n                                                  \"disabled\": true\n                                                },\n                                                {\n                                                  \"name\": \"onSelect\",\n                                                  \"disabled\": false\n                                                },\n                                                {\n                                                  \"name\": \"onDropdownVisibleChange\",\n                                                  \"disabled\": false\n                                                }\n                                              ]\n                                            },\n                                            \"onChange\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleUserChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            },\n                                            \"onSearch\": {\n                                              \"type\": \"JSFunction\",\n                                              \"value\": \"function(){this.handleUserSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                            },\n                                            \"allowClear\": true\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1m19\",\n                                      \"props\": {\n                                        \"label\": \"ID\",\n                                        \"name\": \"id\",\n                                        \"labelAlign\": \"right\",\n                                        \"colon\": true\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Input\",\n                                          \"id\": \"node_ocksfuhwhs8\",\n                                          \"props\": {\n                                            \"placeholder\": \"请输入ID\",\n                                            \"style\": {\n                                              \"width\": \"180px\"\n                                            },\n                                            \"bordered\": true,\n                                            \"size\": \"middle\"\n                                          }\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"componentName\": \"Form.Item\",\n                                      \"id\": \"node_ocks8dtt1mw\",\n                                      \"props\": {\n                                        \"wrapperCol\": {\n                                          \"offset\": 6\n                                        },\n                                        \"labelAlign\": \"right\",\n                                        \"colon\": true,\n                                        \"style\": {\n                                          \"flex\": \"1\",\n                                          \"textAlign\": \"right\"\n                                        }\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Button\",\n                                          \"id\": \"node_ocks8dtt1mx\",\n                                          \"props\": {\n                                            \"type\": \"primary\",\n                                            \"children\": \"查询\",\n                                            \"htmlType\": \"submit\",\n                                            \"shape\": \"default\",\n                                            \"size\": \"middle\"\n                                          }\n                                        }\n                                      ]\n                                    }\n                                  ]\n                                }\n                              ]\n                            },\n                            {\n                              \"componentName\": \"AliAutoDivDefault\",\n                              \"id\": \"node_ockt3t4q856b\",\n                              \"props\": {\n                                \"style\": {}\n                              },\n                              \"children\": [\n                                {\n                                  \"componentName\": \"Button\",\n                                  \"id\": \"node_ockt3t4q85y\",\n                                  \"props\": {\n                                    \"type\": \"link\",\n                                    \"children\": \"新增打包\",\n                                    \"htmlType\": \"button\",\n                                    \"shape\": \"default\",\n                                    \"size\": \"middle\"\n                                  },\n                                  \"condition\": true\n                                }\n                              ]\n                            }\n                          ]\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            },\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ockshc4ifn1b\",\n              \"props\": {\n                \"childTotalColumns\": 12,\n                \"mode\": \"inset\",\n                \"layoutmode\": \"O\",\n                \"autolayout\": \"(12|1)\"\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ockshc4ifn1c\",\n                  \"props\": {\n                    \"isAutoContainer\": true,\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1\n                  },\n                  \"title\": \"子区块\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ockshc4ifn1d\",\n                      \"props\": {\n                        \"wrap\": false,\n                        \"type\": \"body2\",\n                        \"verAlign\": \"middle\",\n                        \"textSpacing\": true,\n                        \"align\": \"left\",\n                        \"flex\": true\n                      },\n                      \"title\": \"段落\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"AliAutoSearchTableDefault\",\n                          \"id\": \"node_ocksfuhwhsx\",\n                          \"props\": {\n                            \"rowKey\": \"key\",\n                            \"dataSource\": {\n                              \"type\": \"JSExpression\",\n                              \"value\": \"this.state.pkgs\"\n                            },\n                            \"columns\": [\n                              {\n                                \"title\": \"ID\",\n                                \"dataIndex\": \"id\",\n                                \"key\": \"name\",\n                                \"width\": 80\n                              },\n                              {\n                                \"title\": \"渠道号\",\n                                \"dataIndex\": \"channels\",\n                                \"key\": \"age\",\n                                \"width\": 142,\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh2bq0428\",\n                                      \"props\": {\n                                        \"children\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.item\"\n                                        },\n                                        \"style\": {\n                                          \"display\": \"block\"\n                                        }\n                                      },\n                                      \"loop\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text.split(',')\"\n                                      }\n                                    }\n                                  ]\n                                }\n                              },\n                              {\n                                \"title\": \"版本号\",\n                                \"dataIndex\": \"dic_version\",\n                                \"key\": \"address\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Tooltip\",\n                                      \"id\": \"node_ocksts0jqgj\",\n                                      \"props\": {\n                                        \"title\": {\n                                          \"type\": \"JSSlot\",\n                                          \"value\": [\n                                            {\n                                              \"componentName\": \"Typography.Text\",\n                                              \"id\": \"node_ocksts0jqgn\",\n                                              \"props\": {\n                                                \"children\": {\n                                                  \"type\": \"JSExpression\",\n                                                  \"value\": \"this.item. channelId + ' / ' +  this.item.version\"\n                                                },\n                                                \"style\": {\n                                                  \"display\": \"block\",\n                                                  \"color\": \"#FFFFFF\"\n                                                }\n                                              },\n                                              \"loop\": {\n                                                \"type\": \"JSExpression\",\n                                                \"value\": \"this.text || []\"\n                                              }\n                                            }\n                                          ]\n                                        }\n                                      },\n                                      \"children\": [\n                                        {\n                                          \"componentName\": \"Typography.Text\",\n                                          \"id\": \"node_ocksts0jqgm\",\n                                          \"props\": {\n                                            \"children\": {\n                                              \"type\": \"JSExpression\",\n                                              \"value\": \"this.text[0].version\"\n                                            }\n                                          }\n                                        }\n                                      ]\n                                    }\n                                  ]\n                                },\n                                \"width\": 120\n                              },\n                              {\n                                \"title\": \"构建Job\",\n                                \"dataIndex\": \"job_name\",\n                                \"width\": 180\n                              },\n                              {\n                                \"title\": \"构建类型\",\n                                \"dataIndex\": \"packaging_type\",\n                                \"width\": 94\n                              },\n                              {\n                                \"title\": \"构建状态\",\n                                \"dataIndex\": \"status\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh3jkxzw\",\n                                      \"props\": {\n                                        \"children\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.statusDesc[this.text]\"\n                                        }\n                                      }\n                                    },\n                                    {\n                                      \"componentName\": \"Icon\",\n                                      \"id\": \"node_ocksh3jkxzx\",\n                                      \"props\": {\n                                        \"type\": \"SyncOutlined\",\n                                        \"size\": 16,\n                                        \"spin\": true,\n                                        \"style\": {\n                                          \"marginLeft\": \"10px\"\n                                        }\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text === 2\"\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 100\n                              },\n                              {\n                                \"title\": \"构建时间\",\n                                \"dataIndex\": \"start_time\",\n                                \"render\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                },\n                                \"width\": 148\n                              },\n                              {\n                                \"title\": \"构建人\",\n                                \"dataIndex\": \"user\",\n                                \"render\": {\n                                  \"type\": \"JSFunction\",\n                                  \"value\": \"function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                },\n                                \"width\": 80\n                              },\n                              {\n                                \"title\": \"Jenkins 链接\",\n                                \"dataIndex\": \"jenkins_link\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Link\",\n                                      \"id\": \"node_ocksh64kbx21\",\n                                      \"props\": {\n                                        \"href\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.text\"\n                                        },\n                                        \"target\": \"_blank\",\n                                        \"children\": \"查看\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text\"\n                                      }\n                                    },\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh64kbx22\",\n                                      \"props\": {\n                                        \"children\": \"暂无\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"!this.text\"\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 120\n                              },\n                              {\n                                \"title\": \"测试平台链接\",\n                                \"dataIndex\": \"is_run_testing\",\n                                \"width\": 120,\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Typography.Link\",\n                                      \"id\": \"node_ocksh3jkxz3e\",\n                                      \"props\": {\n                                        \"href\": \"http://rivermap.alibaba.net/dashboard/testExecute\",\n                                        \"target\": \"_blank\",\n                                        \"children\": \"查看\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"this.text\"\n                                      }\n                                    },\n                                    {\n                                      \"componentName\": \"Typography.Text\",\n                                      \"id\": \"node_ocksh3jkxz3f\",\n                                      \"props\": {\n                                        \"children\": \"暂无\"\n                                      },\n                                      \"condition\": {\n                                        \"type\": \"JSExpression\",\n                                        \"value\": \"!this.text\"\n                                      }\n                                    }\n                                  ]\n                                }\n                              },\n                              {\n                                \"title\": \"触发源\",\n                                \"dataIndex\": \"source\",\n                                \"width\": 120\n                              },\n                              {\n                                \"title\": \"详情\",\n                                \"dataIndex\": \"id\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Button\",\n                                      \"id\": \"node_ocksh8yryw7\",\n                                      \"props\": {\n                                        \"type\": \"link\",\n                                        \"children\": \"查看\",\n                                        \"size\": \"small\",\n                                        \"style\": {\n                                          \"padding\": \"0px\"\n                                        },\n                                        \"__events\": {\n                                          \"eventDataList\": [\n                                            {\n                                              \"type\": \"componentEvent\",\n                                              \"name\": \"onClick\",\n                                              \"relatedEventName\": \"handleDetail\"\n                                            }\n                                          ],\n                                          \"eventList\": [\n                                            {\n                                              \"name\": \"onClick\",\n                                              \"disabled\": true\n                                            }\n                                          ]\n                                        },\n                                        \"onClick\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        }\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 80,\n                                \"fixed\": \"right\"\n                              },\n                              {\n                                \"title\": \"结果\",\n                                \"dataIndex\": \"id\",\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Button\",\n                                      \"id\": \"node_ocksh9v6jw7\",\n                                      \"props\": {\n                                        \"type\": \"link\",\n                                        \"children\": \"查看\",\n                                        \"size\": \"small\",\n                                        \"style\": {\n                                          \"padding\": \"0px\"\n                                        },\n                                        \"__events\": {\n                                          \"eventDataList\": [\n                                            {\n                                              \"type\": \"componentEvent\",\n                                              \"name\": \"onClick\",\n                                              \"relatedEventName\": \"handleResult\",\n                                              \"paramStr\": \"this.text\"\n                                            }\n                                          ],\n                                          \"eventList\": [\n                                            {\n                                              \"name\": \"onClick\",\n                                              \"disabled\": true\n                                            }\n                                          ]\n                                        },\n                                        \"onClick\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        },\n                                        \"ghost\": false,\n                                        \"href\": {\n                                          \"type\": \"JSExpression\",\n                                          \"value\": \"this.text\"\n                                        }\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"width\": 80,\n                                \"fixed\": \"right\"\n                              },\n                              {\n                                \"title\": \"重新执行\",\n                                \"dataIndex\": \"id\",\n                                \"width\": 92,\n                                \"render\": {\n                                  \"type\": \"JSSlot\",\n                                  \"params\": [\"text\", \"record\", \"index\"],\n                                  \"value\": [\n                                    {\n                                      \"componentName\": \"Button\",\n                                      \"id\": \"node_ocksh96rad1g\",\n                                      \"props\": {\n                                        \"type\": \"text\",\n                                        \"children\": \"\",\n                                        \"icon\": {\n                                          \"type\": \"JSSlot\",\n                                          \"value\": [\n                                            {\n                                              \"componentName\": \"Icon\",\n                                              \"id\": \"node_ocksh96rad1j\",\n                                              \"props\": {\n                                                \"type\": \"ReloadOutlined\",\n                                                \"size\": 14,\n                                                \"color\": \"#0593d3\",\n                                                \"style\": {\n                                                  \"padding\": \"3px\",\n                                                  \"border\": \"1px solid #0593d3\",\n                                                  \"borderRadius\": \"14px\",\n                                                  \"cursor\": \"pointer\",\n                                                  \"height\": \"22px\"\n                                                },\n                                                \"spin\": false\n                                              }\n                                            }\n                                          ]\n                                        },\n                                        \"shape\": \"circle\",\n                                        \"__events\": {\n                                          \"eventDataList\": [\n                                            {\n                                              \"type\": \"componentEvent\",\n                                              \"name\": \"onClick\",\n                                              \"relatedEventName\": \"reload\"\n                                            }\n                                          ],\n                                          \"eventList\": [\n                                            {\n                                              \"name\": \"onClick\",\n                                              \"disabled\": true\n                                            }\n                                          ]\n                                        },\n                                        \"onClick\": {\n                                          \"type\": \"JSFunction\",\n                                          \"value\": \"function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                                        }\n                                      }\n                                    }\n                                  ]\n                                },\n                                \"fixed\": \"right\"\n                              }\n                            ],\n                            \"actions\": [],\n                            \"pagination\": {\n                              \"total\": {\n                                \"type\": \"JSExpression\",\n                                \"value\": \"this.state.total\"\n                              },\n                              \"defaultPageSize\": 10,\n                              \"onPageChange\": {\n                                \"type\": \"JSFunction\",\n                                \"value\": \"function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }\"\n                              },\n                              \"defaultPageIndex\": 1\n                            },\n                            \"scrollX\": 1200,\n                            \"isPagination\": true\n                          },\n                          \"condition\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)\"\n                          }\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            },\n            {\n              \"componentName\": \"NextBlock\",\n              \"id\": \"node_ocksk6f8fa3b\",\n              \"props\": {\n                \"childTotalColumns\": 12,\n                \"mode\": \"inset\",\n                \"layoutmode\": \"O\",\n                \"autolayout\": \"(12|1)\"\n              },\n              \"title\": \"区块\",\n              \"children\": [\n                {\n                  \"componentName\": \"NextBlockCell\",\n                  \"id\": \"node_ocksk6f8fa3c\",\n                  \"props\": {\n                    \"isAutoContainer\": true,\n                    \"colSpan\": 12,\n                    \"rowSpan\": 1\n                  },\n                  \"title\": \"子区块\",\n                  \"children\": [\n                    {\n                      \"componentName\": \"NextP\",\n                      \"id\": \"node_ocksk6f8fa3d\",\n                      \"props\": {\n                        \"wrap\": false,\n                        \"type\": \"body2\",\n                        \"verAlign\": \"middle\",\n                        \"textSpacing\": true,\n                        \"align\": \"left\",\n                        \"flex\": true\n                      },\n                      \"title\": \"段落\",\n                      \"children\": [\n                        {\n                          \"componentName\": \"Empty\",\n                          \"id\": \"node_ocksk6f8fa3e\",\n                          \"props\": {\n                            \"description\": \"暂无数据\"\n                          },\n                          \"condition\": {\n                            \"type\": \"JSExpression\",\n                            \"value\": \"this.state.pkgs.length < 1 && this.state.isSearch\"\n                          }\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"i18n\": {}\n}\n"
  },
  {
    "path": "modules/code-generator/tests/utils/schema/handleSubNodes.test.ts",
    "content": "import { IPublicTypeNodeData } from '@alilc/lowcode-types';\nimport { handleSubNodes } from '../../../src/utils/schema';\nimport SCHEMA_WITH_SLOT from './data/schema-with-slot.json';\n\ndescribe('utils/schema/handleSubNodes', () => {\n  it('should be able to visit nodes in JSSlot(1)', () => {\n    const nodes: IPublicTypeNodeData[] = [\n      {\n        componentName: 'Foo',\n        props: {\n          renderBar: {\n            type: 'JSSlot',\n            value: [\n              {\n                componentName: 'Bar',\n              },\n            ],\n          },\n        },\n      },\n    ];\n\n    const result = handleSubNodes(nodes, {\n      node: (node) => node.componentName,\n    });\n\n    expect(result).toEqual(['Foo', 'Bar']);\n  });\n\n  it('should be able to visit nodes in JSSlot(2)', () => {\n    const nodes: IPublicTypeNodeData[] = (SCHEMA_WITH_SLOT as any).componentsTree[0].children;\n\n    const result = handleSubNodes(nodes, {\n      node: (node) => node.componentName,\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      Array [\n        \"Modal\",\n        \"AliAutoDivDefault\",\n        \"AliAutoDivDefault\",\n        \"Button\",\n        \"AliAutoDivDefault\",\n        \"Typography.Text\",\n        \"Typography.Link\",\n        \"Typography.Link\",\n        \"Button\",\n        \"NextPage\",\n        \"NextBlock\",\n        \"NextBlockCell\",\n        \"NextP\",\n        \"AliAutoDivDefault\",\n        \"AliAutoDivDefault\",\n        \"Form\",\n        \"Form.Item\",\n        \"Select\",\n        \"Form.Item\",\n        \"Input\",\n        \"Form.Item\",\n        \"Select\",\n        \"Form.Item\",\n        \"Input\",\n        \"Form.Item\",\n        \"Button\",\n        \"AliAutoDivDefault\",\n        \"Button\",\n        \"NextBlock\",\n        \"NextBlockCell\",\n        \"NextP\",\n        \"AliAutoSearchTableDefault\",\n        \"Typography.Text\",\n        \"Tooltip\",\n        \"Typography.Text\",\n        \"Typography.Text\",\n        \"Typography.Text\",\n        \"Icon\",\n        \"Typography.Link\",\n        \"Typography.Text\",\n        \"Typography.Link\",\n        \"Typography.Text\",\n        \"Button\",\n        \"Button\",\n        \"Button\",\n        \"Icon\",\n        \"NextBlock\",\n        \"NextBlockCell\",\n        \"NextP\",\n        \"Empty\",\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/utils/validate.test.ts",
    "content": "import { isValidIdentifier } from '../../src/utils/validate';\ndescribe('utils/validate', () => {\n  it('isValidIdentifier should works for normal identifiers', () => {\n    expect(isValidIdentifier('foo')).toBeTruthy();\n    expect(isValidIdentifier('bar')).toBeTruthy();\n    expect(isValidIdentifier('hello123')).toBeTruthy();\n    expect(isValidIdentifier('helloWorld123')).toBeTruthy();\n    expect(isValidIdentifier('hello_world123')).toBeTruthy();\n    expect(isValidIdentifier('$hello_world123')).toBeTruthy();\n    expect(isValidIdentifier('姓名')).toBeTruthy();\n    expect(isValidIdentifier('电话号码')).toBeTruthy();\n  });\n\n  it('isValidIdentifier should works for invalid identifiers', () => {\n    expect(isValidIdentifier('ak dak')).toBeFalsy();\n    expect(isValidIdentifier('姓名 电话')).toBeFalsy();\n    expect(isValidIdentifier('123akk')).toBeFalsy();\n    expect(isValidIdentifier('a,b')).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "modules/code-generator/tests/utils/version.test.ts",
    "content": "import { calcCompatibleVersion } from '../../src/utils/version';\n\nconst NO_COMPATIBLE_VERSIONS = /no compatible versions/;\n\ntest.each([\n  ['*', '*', '*'],\n  ['1.0.0', '1.0.0', '1.0.0'],\n  ['^1.0.0', '^1.0.0', '^1.0.0'],\n  ['*', undefined, '*'],\n  [undefined, undefined, '*'],\n  ['^1.0.0', undefined, '^1.0.0'],\n  ['*', '^1.0.0', '^1.0.0'],\n  ['^1.0.0', '^1.0.2', '^1.0.2'],\n  ['^1.2.0', '^1.1.2', '^1.2.0'],\n  ['^1.0.0', '1.0.2', '1.0.2'],\n])('calc compatible versions \"%i\" & \"%i\" should be \"%i\"', (a, b, expected) => {\n  expect(calcCompatibleVersion(a, b)).toBe(expected);\n  expect(calcCompatibleVersion(b, a)).toBe(expected); // 应该满足交换律\n});\n\ntest.each([\n  ['^0.2.0', '^0.1.2', NO_COMPATIBLE_VERSIONS],\n  ['>0.2.0', '^0.1.2', NO_COMPATIBLE_VERSIONS],\n  ['1.0.1', '1.0.2', NO_COMPATIBLE_VERSIONS],\n])('calc compatible versions \"%i\" & \"%i\" should be no compatible versions', (a, b, expected) => {\n  expect(() => {\n    calcCompatibleVersion(a, b);\n  }).toThrow(expected);\n\n  expect(() => {\n    calcCompatibleVersion(b, a); // 应该满足交换律\n  }).toThrow(expected);\n});\n"
  },
  {
    "path": "modules/code-generator/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src/**/*.ts\"],\n  \"exclude\": [\"./tests\", \"tests/fixtures/test-cases\", \"../types\", \"node_modules\"]\n}\n"
  },
  {
    "path": "modules/material-parser/README.md",
    "content": "# @alilc/lowcode-material-parser\n\n> 入料模块\n\n本模块负责物料接入，能自动扫描、解析源码组件，并最终产出一份符合《中后台搭建组件描述协议》的 **JSON Schema**。\n\n详见[文档](https://lowcode-engine.cn/site/docs/guide/design/materialParser)。\n\n## demo\n\n```shell\ncd demo\n\n// parse jsx\nnode parse-jsx.js\n\n// parse tsx\nnode parse-tsx.js\n\n```\n\n## API\n"
  },
  {
    "path": "modules/material-parser/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}"
  },
  {
    "path": "modules/material-parser/demo/component.jsx",
    "content": "/* eslint-disable react/forbid-prop-types,react/no-unused-prop-types */\nimport React from 'react';\nimport PropTypes from 'prop-types';\n\nimport './main.scss';\n\nclass Demo extends React.Component {\n  render() {\n    return <div> Test </div>;\n  }\n}\n\nDemo.propTypes = {\n  optionalArray: PropTypes.array,\n  optionalBool: PropTypes.bool,\n  optionalFunc: PropTypes.func,\n  optionalNumber: PropTypes.number,\n  optionalObject: PropTypes.object,\n  optionalString: PropTypes.string,\n  optionalSymbol: PropTypes.symbol,\n\n  // Anything that can be rendered: numbers, strings, elements or an array\n  // (or fragment) containing these types.\n  optionalNode: PropTypes.node,\n\n  // A React element (ie. <MyComponent />).\n  optionalElement: PropTypes.element,\n\n  // A React element type (ie. MyComponent).\n  optionalElementType: PropTypes.elementType,\n\n  // You can also declare that a prop is an instance of a class. This uses\n  // JS's instanceof operator.\n  optionalMessage: PropTypes.instanceOf(Demo),\n\n  // You can ensure that your prop is limited to specific values by treating\n  // it as an enum.\n  optionalEnum: PropTypes.oneOf(['News', 'Photos']),\n\n  // An object that could be one of many types\n  optionalUnion: PropTypes.oneOfType([\n    PropTypes.string,\n    PropTypes.number,\n    PropTypes.instanceOf(Demo),\n  ]),\n\n  // An array of a certain type\n  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),\n\n  // An object with property values of a certain type\n  optionalObjectOf: PropTypes.objectOf(PropTypes.number),\n\n  // You can chain any of the above with `isRequired` to make sure a warning\n  // is shown if the prop isn't provided.\n\n  // An object taking on a particular shape\n  optionalObjectWithShape: PropTypes.shape({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }),\n\n  optionalObjectWithShape2: PropTypes.shape({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }).isRequired,\n\n  // An object with warnings on extra properties\n  optionalObjectWithStrictShape: PropTypes.exact({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }),\n\n  requiredFunc: PropTypes.func.isRequired,\n\n  // A value of any data type\n  requiredAny: PropTypes.any.isRequired,\n};\n\nDemo.defaultProps = {};\n\nexport default Demo;\n"
  },
  {
    "path": "modules/material-parser/demo/component.tsx",
    "content": "/* eslint-disable react/forbid-prop-types,react/no-unused-prop-types */\nimport React from 'react';\n\nimport './main.scss';\n\ninterface DemoProps {\n  optionalArray?: [],\n  optionalBool: boolean,\n  optionalFunc: Function,\n  optionalNumber: number,\n  optionalObject: object,\n  optionalString: string,\n  optionalSymbol: symbol,\n\n  // Anything that can be rendered: numbers, strings, elements or an array\n  // (or fragment) containing these types.\n  optionalNode: React.ReactNode,\n\n  // A React element (ie. <MyComponent />).\n  optionalElement: React.ReactElement,\n\n  // A React element type (ie. MyComponent).\n  optionalElementType: React.ElementType,\n\n  // You can also declare that a prop is an instance of a class. This uses\n  // JS's instanceof operator.\n  optionalMessage: React.ReactInstance,\n\n  // You can ensure that your prop is limited to specific values by treating\n  // it as an enum.\n  optionalEnum: 'News'|'Photos',\n\n  // An object that could be one of many types\n  optionalUnion: string|number|React.ReactInstance,\n\n  // An array of a certain type\n  optionalArrayOf: number[],\n\n  // An object with property values of a certain type\n  optionalObjectOf: Record<number, any>,\n\n  // You can chain any of the above with `isRequired` to make sure a warning\n  // is shown if the prop isn't provided.\n}\n\nconst Demo = (props: DemoProps) => {\n  return <div> Test </div>;\n}\n\nDemo.defaultProps = {\n  optionalString: 'optionalString'\n};\n\nexport default Demo;\n"
  },
  {
    "path": "modules/material-parser/demo/parse-jsx.js",
    "content": "const parse = require('../lib').default;\n\n(async () => {\n  const options = {\n    entry: './component.jsx',\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n  console.log(JSON.stringify(actual, null, 2));\n})();\n"
  },
  {
    "path": "modules/material-parser/demo/parse-tsx.js",
    "content": "const parse = require('../lib').default;\n\n(async () => {\n  const options = {\n    entry: './component.tsx',\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n  console.log(JSON.stringify(actual, null, 2));\n})();\n"
  },
  {
    "path": "modules/material-parser/jest.config.js",
    "content": "\nmodule.exports = {\n  transform: {\n    '^.+\\\\.(ts|tsx|js|jsx)$': 'ts-jest',\n  },\n  testEnvironment: 'node',\n  // testMatch: ['(/tests?/.*(test))\\\\.[jt]s$'],\n  testTimeout: 1000000,\n  testPathIgnorePatterns: [\n    '/node_modules/',\n    'test/fixtures',\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: true,\n  collectCoverageFrom: [\n    'src/**/*.{ts,tsx}',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n};"
  },
  {
    "path": "modules/material-parser/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-material-parser\",\n  \"version\": \"1.0.3\",\n  \"description\": \"material parser for Ali lowCode engine\",\n  \"main\": \"lib/index.js\",\n  \"files\": [\n    \"lib\",\n    \"schemas\"\n  ],\n  \"devDependencies\": {\n    \"@babel/runtime\": \"^7.11.2\",\n    \"@types/debug\": \"^4.1.5\",\n    \"@types/fs-extra\": \"^8.0.1\",\n    \"@types/jest\": \"^26.0.18\",\n    \"@types/js-yaml\": \"^3.12.2\",\n    \"@types/lodash\": \"^4.14.149\",\n    \"@types/node\": \"^14.6.0\",\n    \"@types/prop-types\": \"^15.7.3\",\n    \"copy-webpack-plugin\": \"^9.1.0\",\n    \"copyfiles\": \"^2.4.1\",\n    \"eslint\": \"^8.12.0\",\n    \"eslint-config-ali\": \"^14.0.0\",\n    \"jest\": \"^26.6.3\",\n    \"js-yaml\": \"^3.13.1\",\n    \"json-schema-to-typescript\": \"^8.2.0\",\n    \"ts-jest\": \"^26.0.0\",\n    \"ts-loader\": \"^9.2.6\",\n    \"ts-node\": \"^8.10.2\",\n    \"tslib\": \"^1.11.1\",\n    \"webpack\": \"^5.64.1\",\n    \"webpack-cli\": \"^4.9.1\",\n    \"webpack-node-externals\": \"^3.0.0\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"prebuild\": \"npm run schema && npm run bundle\",\n    \"postbuild\": \"copyfiles -u 1 \\\"src/**/*.json\\\" lib/\",\n    \"prepublishOnly\": \"npm run build\",\n    \"test\": \"jest --verbose\",\n    \"test:snapshot\": \"jest --updateSnapshot --verbose\",\n    \"schema\": \"node ./scripts/transform.js\",\n    \"bundle\": \"webpack\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"ajv\": \"^6.12.0\",\n    \"ast-types\": \"^0.13.3\",\n    \"cross-spawn-promise\": \"^0.10.2\",\n    \"debug\": \"^4.1.1\",\n    \"find-config\": \"^1.0.0\",\n    \"fs-extra\": \"^8.1.0\",\n    \"lodash\": \"^4.17.15\",\n    \"parse-prop-types\": \"^0.3.0\",\n    \"prop-types\": \"^15.7.2\",\n    \"react-docgen\": \"5.3.0\",\n    \"react-docgen-typescript\": \"^1.16.5\",\n    \"safe-eval\": \"^0.4.1\",\n    \"short-uuid\": \"^3.1.1\",\n    \"ts-polyfill\": \"^3.8.1-rc\",\n    \"typescript\": \"3.9.4\",\n    \"vm2\": \"^3.9.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"engines\": {\n    \"node\": \">=10.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/modules/material-parser\"\n  },\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "modules/material-parser/schemas/schema.json",
    "content": "{\n  \"$id\": \"@ali/low-code-component-protocol-schema\",\n  \"description\": \"json schema for low code component protocol\",\n  \"allOf\": [\n    {\n      \"$ref\": \"#/definitions/BasicSection\"\n    },\n    {\n      \"$ref\": \"#/definitions/PropsSection\"\n    },\n    {\n      \"$ref\": \"#/definitions/ConfigureSection\"\n    }\n  ],\n  \"definitions\": {\n    \"BasicSection\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"componentName\": {\n          \"type\": \"string\"\n        },\n        \"title\": {\n          \"type\": \"string\"\n        },\n        \"description\": {\n          \"type\": \"string\"\n        },\n        \"docUrl\": {\n          \"type\": \"string\"\n        },\n        \"screenshot\": {\n          \"type\": \"string\"\n        },\n        \"icon\": {\n          \"type\": \"string\"\n        },\n        \"tags\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"devMode\": {\n          \"enum\": [\n            \"proCode\",\n            \"lowCode\"\n          ]\n        },\n        \"npm\": {\n          \"$ref\": \"#/definitions/Npm\"\n        }\n      },\n      \"required\": [\n        \"componentName\",\n        \"title\",\n        \"npm\",\n        \"docUrl\",\n        \"screenshot\"\n      ]\n    },\n    \"PropsSection\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"props\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\"\n              },\n              \"propType\": {\n                \"$ref\": \"#/definitions/PropType\"\n              },\n              \"description\": {\n                \"type\": \"string\"\n              },\n              \"defaultValue\": {}\n            },\n            \"required\": [\n              \"name\",\n              \"propType\"\n            ]\n          }\n        }\n      }\n    },\n    \"ConfigureSection\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"configure\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"props\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/definitions/ConfigureProp\"\n              }\n            },\n            \"styles\": {\n              \"type\": \"object\",\n              \"properties\": {}\n            },\n            \"events\": {\n              \"type\": \"object\",\n              \"properties\": {}\n            },\n            \"component\": {\n              \"$ref\": \"#/definitions/ConfigureComponent\"\n            }\n          }\n        }\n      }\n    },\n    \"Npm\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"package\": {\n          \"type\": \"string\"\n        },\n        \"exportName\": {\n          \"type\": \"string\"\n        },\n        \"subName\": {\n          \"type\": \"string\"\n        },\n        \"main\": {\n          \"type\": \"string\"\n        },\n        \"destructuring\": {\n          \"type\": \"boolean\"\n        },\n        \"version\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"package\",\n        \"exportName\",\n        \"subName\",\n        \"main\",\n        \"destructuring\",\n        \"version\"\n      ]\n    },\n    \"PropType\": {\n      \"oneOf\": [\n        {\n          \"$ref\": \"#/definitions/BasicType\"\n        },\n        {\n          \"$ref\": \"#/definitions/RequiredType\"\n        },\n        {\n          \"$ref\": \"#/definitions/ComplexType\"\n        }\n      ]\n    },\n    \"BasicType\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"array\",\n        \"bool\",\n        \"func\",\n        \"number\",\n        \"object\",\n        \"string\",\n        \"node\",\n        \"element\",\n        \"any\"\n      ]\n    },\n    \"RequiredType\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"$ref\": \"#/definitions/BasicType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"required\": [\n        \"type\"\n      ]\n    },\n    \"ComplexType\": {\n      \"oneOf\": [\n        {\n          \"$ref\": \"#/definitions/OneOf\"\n        },\n        {\n          \"$ref\": \"#/definitions/OneOfType\"\n        },\n        {\n          \"$ref\": \"#/definitions/ArrayOf\"\n        },\n        {\n          \"$ref\": \"#/definitions/ObjectOf\"\n        },\n        {\n          \"$ref\": \"#/definitions/Shape\"\n        },\n        {\n          \"$ref\": \"#/definitions/Exact\"\n        }\n      ]\n    },\n    \"OneOf\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"oneOf\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"OneOfType\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"oneOfType\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/PropType\"\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ArrayOf\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"arrayOf\"\n          ]\n        },\n        \"value\": {\n          \"$ref\": \"#/definitions/PropType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ObjectOf\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"objectOf\"\n          ]\n        },\n        \"value\": {\n          \"$ref\": \"#/definitions/PropType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"Shape\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"shape\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\"\n              },\n              \"propType\": {\n                \"$ref\": \"#/definitions/PropType\"\n              }\n            },\n            \"additionalProperties\": false\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ShapeItem\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"name\",\n        \"propType\"\n      ],\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"propType\": {\n          \"$ref\": \"#/definitions/PropType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      },\n      \"additionalProperties\": false\n    },\n    \"Exact\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"exact\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\"\n              },\n              \"propType\": {\n                \"$ref\": \"#/definitions/PropType\"\n              }\n            },\n            \"additionalProperties\": false\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ConfigureProp\": {\n      \"type\": \"object\",\n      \"allOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"title\": {\n              \"type\": \"string\"\n            },\n            \"extraProps\": {\n              \"type\": \"object\",\n              \"properties\": {}\n            }\n          }\n        },\n        {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/definitions/ConfigureFieldProp\"\n            },\n            {\n              \"$ref\": \"#/definitions/ConfigureGroupProp\"\n            }\n          ]\n        }\n      ]\n    },\n    \"ConfigureFieldProp\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"field\"\n          ]\n        },\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"setter\": {\n          \"$ref\": \"#/definitions/ConfigureFieldSetter\"\n        }\n      }\n    },\n    \"ConfigureFieldSetter\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"componentName\"\n      ],\n      \"properties\": {\n        \"componentName\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"List\",\n            \"Object\",\n            \"Function\",\n            \"Node\",\n            \"Mixin\",\n            \"Expression\",\n            \"Switch\",\n            \"Number\",\n            \"Input\",\n            \"TextArea\",\n            \"Date\",\n            \"DateYear\",\n            \"DateMonth\",\n            \"DateRange\",\n            \"ColorPicker\",\n            \"CodeEditor\",\n            \"Select\",\n            \"RadioGroup\"\n          ]\n        },\n        \"props\": {\n          \"type\": \"object\",\n          \"properties\": {}\n        }\n      }\n    },\n    \"ConfigureGroupProp\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"items\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"group\"\n          ]\n        },\n        \"items\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/ConfigureProp\"\n          }\n        }\n      }\n    },\n    \"ConfigureComponent\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"isContainer\": {\n          \"type\": \"boolean\"\n        },\n        \"isModal\": {\n          \"type\": \"boolean\"\n        },\n        \"descriptor\": {\n          \"type\": \"string\"\n        },\n        \"nestingRule\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"childWhitelist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"parentWhitelist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"descendantBlacklist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"ancestorWhitelist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          }\n        },\n        \"isNullNode\": {\n          \"type\": \"boolean\"\n        },\n        \"isLayout\": {\n          \"type\": \"boolean\"\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "modules/material-parser/schemas/schema.yml",
    "content": "$id: \"@ali/low-code-component-protocol-schema\"\ndescription: json schema for low code component protocol\nallOf:\n  - $ref: \"#/definitions/BasicSection\"\n  - $ref: \"#/definitions/PropsSection\"\n  - $ref: \"#/definitions/ConfigureSection\"\ndefinitions:\n  BasicSection:\n    type: object\n    properties:\n      componentName:\n        type: string\n      title:\n        type: string\n      description:\n        type: string\n      docUrl:\n        type: string\n      screenshot:\n        type: string\n      icon:\n        type: string\n      tags:\n        type: array\n        items:\n          type: string\n      devMode:\n        enum:\n          - proCode\n          - lowCode\n      npm:\n        $ref: \"#/definitions/Npm\"\n    required:\n      - componentName\n      - title\n      - npm\n  PropsSection:\n    type: object\n    required:\n      - props\n    properties:\n      props:\n        type: array\n        items:\n          properties:\n            name:\n              type: string\n            propType:\n              $ref: \"#/definitions/PropType\"\n            description:\n              type: string\n            defaultValue: {}\n          required:\n            - name\n            - propType\n  ConfigureSection:\n    type: object\n    properties:\n      configure:\n        type: object\n        properties:\n          props:\n            type: array\n            items:\n              $ref: \"#/definitions/ConfigureProp\"\n          styles:\n            type: object\n            properties: {}\n          events:\n            type: object\n            properties: {}\n          component:\n            $ref: \"#/definitions/ConfigureComponent\"\n  Npm:\n    type: object\n    properties:\n      package:\n        type: string\n      exportName:\n        type: string\n      subName:\n        type: string\n      main:\n        type: string\n      destructuring:\n        type: boolean\n      version:\n        type: string\n    required:\n      - package\n      - exportName\n      - subName\n      - main\n      - destructuring\n      - version\n  PropType:\n    oneOf:\n      - $ref: \"#/definitions/BasicType\"\n      - $ref: \"#/definitions/RequiredType\"\n      - $ref: \"#/definitions/ComplexType\"\n  BasicType:\n    type: string\n    enum:\n      - array\n      - bool\n      - func\n      - number\n      - object\n      - string\n      - node\n      - element\n      - any\n  RequiredType:\n    type: object\n    properties:\n      type:\n        $ref: \"#/definitions/BasicType\"\n      isRequired:\n        type: boolean\n    additionalProperties: false\n    required:\n      - type\n  ComplexType:\n    oneOf:\n      - $ref: \"#/definitions/OneOf\"\n      - $ref: \"#/definitions/OneOfType\"\n      - $ref: \"#/definitions/ArrayOf\"\n      - $ref: \"#/definitions/ObjectOf\"\n      - $ref: \"#/definitions/Shape\"\n      - $ref: \"#/definitions/Exact\"\n  OneOf:\n    type: object\n    required:\n      - type\n      - value\n    properties:\n      type:\n        type: string\n        enum:\n          - oneOf\n      value:\n        type: array\n        items:\n          oneOf:\n            - type: string\n            - type: number\n            - type: boolean\n      isRequired:\n        type: boolean\n  OneOfType:\n    type: object\n    required:\n      - type\n      - value\n    properties:\n      type:\n        type: string\n        enum:\n          - oneOfType\n      value:\n        type: array\n        items:\n          $ref: \"#/definitions/PropType\"\n      isRequired:\n        type: boolean\n  ArrayOf:\n    type: object\n    required:\n      - type\n      - value\n    properties:\n      type:\n        type: string\n        enum:\n          - arrayOf\n      value:\n        $ref: \"#/definitions/PropType\"\n      isRequired:\n        type: boolean\n  ObjectOf:\n    type: object\n    required:\n      - type\n      - value\n    properties:\n      type:\n        type: string\n        enum:\n          - objectOf\n      value:\n        $ref: \"#/definitions/PropType\"\n      isRequired:\n        type: boolean\n  Shape:\n    type: object\n    required:\n      - type\n      - value\n    properties:\n      type:\n        type: string\n        enum:\n          - shape\n      value:\n        type: array\n        items:\n          type: object\n          properties:\n            name:\n              type: string\n            propType:\n              $ref: \"#/definitions/PropType\"\n          additionalProperties: false\n      isRequired:\n        type: boolean\n  ShapeItem:\n    type: object\n    required:\n      - name\n      - propType\n    properties:\n      name:\n        type: string\n      propType:\n        $ref: \"#/definitions/PropType\"\n      isRequired:\n        type: boolean\n    additionalProperties: false\n  Exact:\n    type: object\n    required:\n      - type\n      - value\n    properties:\n      type:\n        type: string\n        enum:\n          - exact\n      value:\n        type: array\n        items:\n          type: object\n          properties:\n            name:\n              type: string\n            propType:\n              $ref: \"#/definitions/PropType\"\n          additionalProperties: false\n      isRequired:\n        type: boolean\n  ConfigureProp:\n    type: object\n    allOf:\n      - type: object\n        properties:\n          title:\n            type: string\n          extraProps:\n            type: object\n            properties: {}\n      - oneOf:\n          - $ref: \"#/definitions/ConfigureFieldProp\"\n          - $ref: \"#/definitions/ConfigureGroupProp\"\n  ConfigureFieldProp:\n    type: object\n    required:\n      - type\n    properties:\n      type:\n        type: string\n        enum:\n          - field\n      name:\n        type: string\n      setter:\n        $ref: \"#/definitions/ConfigureFieldSetter\"\n  ConfigureFieldSetter:\n    type: object\n    required:\n      - componentName\n    properties:\n      componentName:\n        type: string\n        enum:\n          - List\n          - Object\n          - Function\n          - Node\n          - Mixin\n          - Expression\n          - Switch\n          - Number\n          - Input\n          - TextArea\n          - Date\n          - DateYear\n          - DateMonth\n          - DateRange\n          - ColorPicker\n          - CodeEditor\n          - Select\n          - RadioGroup\n      props:\n        type: object\n        properties: {} # 暂未校验每个控件的props，待控件入料后获取真实属性\n  ConfigureGroupProp:\n    type: object\n    required:\n      - type\n      - items\n    properties:\n      type:\n        type: string\n        enum:\n          - group\n      items:\n        type: array\n        items:\n          $ref: \"#/definitions/ConfigureProp\"\n  ConfigureComponent:\n    type: object\n    properties:\n      isContainer:\n        type: boolean\n      isModal:\n        type: boolean\n      descriptor:\n        type: string\n      nestingRule:\n        type: object\n        properties:\n          childWhitelist:\n            type: array\n            items:\n              type: string\n          parentWhitelist:\n            type: array\n            items:\n              type: string\n          descendantBlacklist:\n            type: array\n            items:\n              type: string\n          ancestorWhitelist:\n            type: array\n            items:\n              type: string\n      isNullNode:\n        type: boolean\n      isLayout:\n        type: boolean\n"
  },
  {
    "path": "modules/material-parser/scripts/transform.js",
    "content": "const yaml = require('js-yaml');\nconst fs = require('fs');\nconst path = require('path');\nconst Ajv = require('ajv');\nconst { compile } = require('json-schema-to-typescript');\nconst { ESLint } = require('eslint');\n\nconst ajv = new Ajv();\nconst eslint = new ESLint({ fix: true });\n\nconst YamlPath = path.resolve(__dirname, '../schemas/schema.yml');\nconst JsonPath = path.resolve(__dirname, '../src/validate/schema.json');\nconst tsPath = path.resolve(__dirname, '../src/core/schema/types.ts');\n// Get document, or throw exception on error\n\n(async function () {\n  try {\n    const schema = yaml.load(fs.readFileSync(YamlPath, 'utf8'));\n    ajv.compile(schema);\n    fs.writeFileSync(JsonPath, JSON.stringify(schema, null, 2), 'utf-8');\n    console.log('yaml file is successfully transformed into json');\n    const ts = await compile(schema, 'ComponentMeta');\n    fs.writeFileSync(tsPath, ts);\n    // Lint files. This doesn't modify target files.\n    const results = await eslint.lintFiles([tsPath]);\n\n    // Modify the files with the fixed code.\n    await ESLint.outputFixes(results);\n\n    console.log('schema/types.d.ts is successfully generated');\n  } catch (e) {\n    console.log(e);\n    process.exit(1);\n  }\n})();"
  },
  {
    "path": "modules/material-parser/src/core/index.ts",
    "content": "import _debug from 'debug';\n\nexport * from './schema/types';\n\n/**\n * Dev helper\n */\nexport const debug = _debug('lowcode:mat');\nexport const enableDebug = () => _debug.enable('lowcode:*');\nexport const disableDebug = () => _debug.disable();\n"
  },
  {
    "path": "modules/material-parser/src/core/schema/types.ts",
    "content": "/**\n * This file was automatically generated by json-schema-to-typescript.\n * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,\n * and run json-schema-to-typescript to regenerate this file.\n */\n\n/**\n * json schema for low code component protocol\n */\nexport type ComponentMeta = BasicSection & PropsSection & ConfigureSection;\nexport type PropType = BasicType | RequiredType | ComplexType;\nexport type BasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any';\nexport type ComplexType = OneOf | OneOfType | ArrayOf | ObjectOf | Shape | Exact;\nexport type ConfigureProp = {\n  title?: string;\n  extraProps?: {\n    [k: string]: any;\n  };\n  [k: string]: any;\n} & (ConfigureFieldProp | ConfigureGroupProp);\n\nexport interface BasicSection {\n  componentName: string;\n  title: string;\n  description?: string;\n  docUrl?: string;\n  screenshot?: string;\n  icon?: string;\n  tags?: string[];\n  devMode?: 'proCode' | 'lowCode';\n  npm: Npm;\n  [k: string]: any;\n}\nexport interface Npm {\n  package: string;\n  exportName: string;\n  subName: string;\n  main: string;\n  destructuring: boolean;\n  version: string;\n  [k: string]: any;\n}\nexport interface PropsSection {\n  props: Array<{\n    name: string;\n    propType: PropType;\n    description?: string;\n    defaultValue?: any;\n    [k: string]: any;\n  }>;\n  [k: string]: any;\n}\nexport interface RequiredType {\n  type: BasicType;\n  isRequired?: boolean;\n}\nexport interface OneOf {\n  type: 'oneOf';\n  value: Array<string | number | boolean>;\n  isRequired?: boolean;\n  [k: string]: any;\n}\nexport interface OneOfType {\n  type: 'oneOfType';\n  value: PropType[];\n  isRequired?: boolean;\n  [k: string]: any;\n}\nexport interface ArrayOf {\n  type: 'arrayOf';\n  value: PropType;\n  isRequired?: boolean;\n  [k: string]: any;\n}\nexport interface ObjectOf {\n  type: 'objectOf';\n  value: PropType;\n  isRequired?: boolean;\n  [k: string]: any;\n}\nexport interface Shape {\n  type: 'shape';\n  value: Array<{\n    name?: string;\n    propType?: PropType;\n  }>;\n  isRequired?: boolean;\n  [k: string]: any;\n}\nexport interface Exact {\n  type: 'exact';\n  value: Array<{\n    name?: string;\n    propType?: PropType;\n  }>;\n  isRequired?: boolean;\n  [k: string]: any;\n}\nexport interface ConfigureSection {\n  configure?: {\n    props?: ConfigureProp[];\n    styles?: {\n      [k: string]: any;\n    };\n    events?: {\n      [k: string]: any;\n    };\n    component?: ConfigureComponent;\n    [k: string]: any;\n  };\n  [k: string]: any;\n}\nexport interface ConfigureFieldProp {\n  type: 'field';\n  name?: string;\n  setter?: ConfigureFieldSetter;\n  [k: string]: any;\n}\nexport interface ConfigureFieldSetter {\n  componentName:\n    | 'List'\n    | 'Object'\n    | 'Function'\n    | 'Node'\n    | 'Mixin'\n    | 'Expression'\n    | 'Switch'\n    | 'Number'\n    | 'Input'\n    | 'TextArea'\n    | 'Date'\n    | 'DateYear'\n    | 'DateMonth'\n    | 'DateRange'\n    | 'ColorPicker'\n    | 'CodeEditor'\n    | 'Select'\n    | 'RadioGroup';\n  props?: {\n    [k: string]: any;\n  };\n  [k: string]: any;\n}\nexport interface ConfigureGroupProp {\n  type: 'group';\n  items: ConfigureProp[];\n  [k: string]: any;\n}\nexport interface ConfigureComponent {\n  isContainer?: boolean;\n  isModal?: boolean;\n  descriptor?: string;\n  nestingRule?: {\n    childWhitelist?: string[];\n    parentWhitelist?: string[];\n    descendantBlacklist?: string[];\n    ancestorWhitelist?: string[];\n    [k: string]: any;\n  };\n  isNullNode?: boolean;\n  isLayout?: boolean;\n  [k: string]: any;\n}\n"
  },
  {
    "path": "modules/material-parser/src/generate.ts",
    "content": "import * as path from 'path';\nimport { debug, ComponentMeta } from './core';\nimport { IMaterialParsedModel, IMaterialScanModel, IInternalMaterializeOptions } from './types';\n\nconst log = debug.extend('gen');\n\nexport default async function (\n  matScanModel: IMaterialScanModel,\n  matParsedModels: IMaterialParsedModel[],\n  options: IInternalMaterializeOptions,\n): Promise<ComponentMeta[]> {\n  const containerList = [];\n  for (const matParsedModel of matParsedModels) {\n    // 默认排除掉 defaultExportName 为空的组件\n    if (!matParsedModel.componentName) {\n      log('skip');\n      continue;\n    }\n    // 组装 manifest\n    const manifest: any = await genManifest(matScanModel, matParsedModel, options);\n\n    containerList.push(manifest);\n  }\n\n  return containerList;\n}\n\n/**\n * 生成 manifest\n *\n * @param {IMaterialParsedModel} matParsedModel\n * @returns {Promise<\n *     manifestObj: ComponentMeta, // 组件描述\n *   >}\n * @memberof LocalGenerator\n */\nexport async function genManifest(\n  matScanModel: IMaterialScanModel,\n  matParsedModel: IMaterialParsedModel,\n  options: IInternalMaterializeOptions,\n): Promise<ComponentMeta> {\n  const manifestObj: Partial<ComponentMeta> = {\n    componentName: matParsedModel.componentName,\n    title: matScanModel.pkgName,\n    docUrl: '',\n    screenshot: '',\n    devMode: 'proCode', // 需要入料的组件都是源码模式，低代码组件在平台上即可直接生成描述\n    npm: {\n      package: matScanModel.pkgName,\n      version: matScanModel.pkgVersion,\n      exportName: matParsedModel.meta?.exportName || matParsedModel.componentName,\n      main:\n        options.root && path.isAbsolute(matScanModel.mainFilePath)\n          ? path.relative(options.root, matScanModel.mainFilePath)\n          : matScanModel.mainFilePath,\n      destructuring: matParsedModel.meta?.exportName !== 'default',\n      subName: matParsedModel.meta?.subName || '',\n    },\n  };\n\n  // 填充 props\n  manifestObj.props = matParsedModel.props;\n  // 执行扩展点\n  return manifestObj as ComponentMeta;\n}\n"
  },
  {
    "path": "modules/material-parser/src/index.ts",
    "content": "import 'ts-polyfill';\nimport { remove, lstatSync } from 'fs-extra';\nimport { join, isAbsolute } from 'path';\nimport {\n  IMaterializeOptions,\n  IMaterializeLocalOptions,\n  IMaterializeOnlineOptions,\n  IInternalMaterializeOptions,\n} from './types';\nimport { ComponentMeta } from './core';\nimport scan from './scan';\nimport generate from './generate';\nimport parse from './parse';\nimport localize from './localize';\n\nexport { default as validate } from './validate';\nexport { default as schema } from './validate/schema.json';\n\nexport * from './types';\n\nexport default async function (options: IMaterializeOptions): Promise<ComponentMeta[]> {\n  const { accesser = 'local', dslType } = options;\n\n  let { entry = '' } = options;\n  const internalOptions: IInternalMaterializeOptions = {\n    ...options,\n    accesser,\n    entry: options.entry || '',\n    root: (options as IMaterializeLocalOptions)?.root || '',\n  } as IInternalMaterializeOptions;\n\n  if (accesser === 'local') {\n    const { root } = options as IMaterializeLocalOptions;\n    internalOptions.root = root;\n    if (!root) {\n      const stats = lstatSync(entry);\n      if (stats.isDirectory()) {\n        internalOptions.root = entry;\n      } else {\n        internalOptions.root = process.cwd();\n      }\n    } else if (!isAbsolute(entry)) {\n      internalOptions.entry = join(root, entry);\n    }\n  }\n\n  let workDir = internalOptions.root || '';\n  let moduleDir = '';\n  if (accesser === 'online') {\n    const result = await localize(internalOptions as IMaterializeOnlineOptions);\n    workDir = result.workDir;\n    moduleDir = result.moduleDir;\n    internalOptions.entry = result.entry ? join(moduleDir, result.entry) : moduleDir;\n    internalOptions.root = moduleDir;\n  }\n  const scanedModel = await scan(internalOptions);\n  const parsedModel = await parse({\n    ...scanedModel,\n    dslType,\n    accesser,\n    npmClient: internalOptions.npmClient,\n    workDir,\n    moduleDir,\n  });\n  const result = await generate(scanedModel, parsedModel, internalOptions);\n  if (workDir && accesser === 'online') {\n    await remove(workDir);\n  }\n  return result;\n}\n"
  },
  {
    "path": "modules/material-parser/src/localize.ts",
    "content": "import spawn from 'cross-spawn-promise';\nimport { ensureDir, ensureFile, writeFile } from 'fs-extra';\nimport { join, resolve } from 'path';\nimport uuid from 'short-uuid';\nimport { debug } from './core';\nimport { IMaterializeOnlineOptions, IMaterializeOnlinePackageAndVersionOptions } from './types';\n\nconst log = debug.extend('localize');\n\n/**\n * 创建组件包\n *\n * @private\n * @param {{\n *     pkgName: string;\n *     pkgVersion: string;\n *   }} params\n * @returns {Promise<void>}\n * @memberof OnlineAccesser\n */\nexport async function createFakePackage(params: {\n  workDir: string;\n  pkgName: string;\n  pkgVersion: string;\n  npmClient?: string;\n}): Promise<void> {\n  // 创建临时组件包\n  const { workDir } = params;\n  const pkgJsonFilePath = join(workDir, 'package.json');\n  await ensureFile(pkgJsonFilePath);\n  await writeFile(\n    pkgJsonFilePath,\n    JSON.stringify(\n      {\n        name: params.pkgName,\n        version: params.pkgVersion || '0.0.0',\n        dependencies: {\n          [params.pkgName]: params.pkgVersion || 'latest',\n          react: 'latest',\n          'react-dom': 'latest',\n          'parse-prop-types': '^0.3.0',\n          typesync: 'latest',\n        },\n      },\n      null,\n      2,\n    ),\n  );\n\n  // 安装依赖\n  const npmClient = params.npmClient || 'tnpm';\n  await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);\n}\n\n/**\n * 创建临时目录\n *\n * @private\n * @returns {Promise<string>} 返回临时文件夹路径\n * @memberof LocalGenerator\n */\nexport async function createworkDir(tempDir?: string): Promise<string> {\n  const workDirName = uuid.generate();\n  const workDir = resolve(tempDir || '../../node_modules/.temp/', workDirName);\n  await ensureDir(workDir);\n  log('create temp dir successfully', workDir);\n  return workDir;\n}\n\n/**\n * 分离物料组件名称和版本号\n *\n * @private\n * @param {string} pkgNameWithVersion\n * @returns {{ [key: string]: any }}\n * @memberof OnlineAccesser\n */\nexport function getPkgNameAndVersion(pkgNameWithVersion: string): { [key: string]: any } {\n  const matches = pkgNameWithVersion.match(/(@[^/]+)$/);\n  if (!matches) {\n    return {\n      name: pkgNameWithVersion,\n    };\n  }\n  const name = pkgNameWithVersion.replace(matches[0], '');\n  return {\n    version: matches[0].slice(1),\n    name,\n  };\n}\n\n// 将问题转化为本地物料化场景\nexport default async function localize(options: IMaterializeOnlineOptions): Promise<{\n  workDir: string;\n  moduleDir: string;\n  entry?: string;\n}> {\n  // 创建临时目录\n  const workDir = await createworkDir(options.tempDir);\n  await ensureDir(workDir);\n  let { name, version = 'latest' } = options as IMaterializeOnlinePackageAndVersionOptions;\n  if (!name) {\n    const pkgNameAndVersion = getPkgNameAndVersion(options.entry);\n    name = pkgNameAndVersion.name;\n    version = pkgNameAndVersion.version;\n  }\n  // 创建组件包\n  await createFakePackage({\n    pkgName: name,\n    pkgVersion: version,\n    workDir,\n    npmClient: options.npmClient,\n  });\n\n  const result = {\n    workDir,\n    moduleDir: join(workDir, 'node_modules', name),\n    entry: undefined,\n  };\n\n  if ((options as IMaterializeOnlinePackageAndVersionOptions)?.name) {\n    result.entry = options.entry;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/dynamic/index.ts",
    "content": "import { isEmpty } from 'lodash';\n// import * as path from 'path';\n// @ts-ignore\nimport parsePropTypes from 'parse-prop-types';\nimport PropTypes from 'prop-types';\nimport { transformItem } from '../transform';\nimport requireInSandbox from './requireInSandbox';\n\nexport interface IComponentInfo {\n  component: any;\n  meta: {\n    exportName: string;\n    subName?: string;\n  };\n}\n\nconst reservedKeys = [\n  'propTypes',\n  'defaultProps',\n  'name',\n  'arguments',\n  'caller',\n  'length',\n  'contextTypes',\n  'displayName',\n  '__esModule',\n  'version',\n];\n\nfunction getKeys(com: any) {\n  const keys = Object.keys(com).filter(x => {\n    return !reservedKeys.includes(x) && !x.startsWith('_');\n  });\n\n  return keys;\n}\n\nfunction isComponent(obj: any) {\n  return (\n    typeof obj === 'function' &&\n    (Object.prototype.hasOwnProperty.call(obj, 'propTypes') ||\n      Object.prototype.hasOwnProperty.call(obj, 'defaultProps'))\n  );\n}\n\nexport default function (filePath: string) {\n  // const { filePath } = arg;\n  // const modulePath = path.resolve(workDir, 'node_modules', 'parse-prop-types');\n  // const parsePropTypes = require(modulePath).default;\n  if (!filePath) return [];\n  const Com = requireInSandbox(filePath, PropTypes);\n  const components: IComponentInfo[] = [];\n  let index = 0;\n\n  if (Com.__esModule) {\n    const keys = getKeys(Com);\n    keys.forEach(k => {\n      if (isComponent(Com[k])) {\n        components.push({\n          component: Com[k],\n          meta: {\n            exportName: k,\n          },\n        });\n      }\n    });\n  } else if (isComponent(Com)) {\n    components.push({\n      component: Com,\n      meta: {\n        exportName: 'default',\n      },\n    });\n  }\n\n  // dps\n  while (index < components.length) {\n    const item = components[index++];\n\n    const keys = getKeys(item.component);\n    const subs = keys\n      .filter(k => isComponent(item.component[k]))\n      .map(k => ({\n        component: item.component[k],\n        meta: {\n          ...item.meta,\n          subName: k,\n        },\n      }));\n    if (subs.length) {\n      components.splice(index, 0, ...subs);\n    }\n  }\n\n  const result = components.reduce((acc: any, { meta, component }) => {\n    const componentInfo = parsePropTypes(component);\n    if (!isEmpty(componentInfo)) {\n      const props = Object.keys(componentInfo).reduce((acc2: any[], name) => {\n        try {\n          const item: any = transformItem(name, componentInfo[name]);\n          acc2.push(item);\n        } catch (e) {\n          // TODO\n        }\n        return acc2;\n      }, []);\n\n      return [\n        ...acc,\n        {\n          meta,\n          props,\n          componentName: meta.subName || meta.exportName || component.displayName,\n        },\n      ];\n    }\n    return acc;\n  }, []);\n\n  return result;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/dynamic/requireInSandbox.ts",
    "content": "import { readFileSync } from 'fs-extra';\nimport { NodeVM } from 'vm2';\n// import PropTypes from 'prop-types';\n\nconst cssPattern = /\\.(css|scss|sass|less)$/;\nfunction requireInSandbox(filePath: string, PropTypes: any) {\n  const vm = new NodeVM({\n    sandbox: {},\n    sourceExtensions: ['js', 'css', 'scss', 'sass', 'less'],\n    compiler: (code, filename) => {\n      if (filename.match(cssPattern)) {\n        return `\n              const handler = {\n                get() {\n                  return new Proxy({}, handler);\n                },\n              };\n              const proxiedObject = new Proxy({}, handler);\n              module.exports = proxiedObject;\n            `;\n      } else {\n        return code;\n      }\n    },\n    require: {\n      external: true,\n      context: 'sandbox',\n      mock: {\n        'prop-types': PropTypes,\n      },\n    },\n  });\n  const fileContent = readFileSync(filePath, { encoding: 'utf8' });\n  return vm.run(fileContent, filePath);\n}\n\nexport default requireInSandbox;\n"
  },
  {
    "path": "modules/material-parser/src/parse/index.ts",
    "content": "import parseDynamic from './dynamic';\nimport parseJS from './js';\nimport parseTS from './ts';\nimport { install, installPeerAndDevDeps, syncTypeModules, installTypeDTS } from '../utils';\nimport { IMaterialScanModel, DSLType } from '../types';\nimport { debug } from '../core';\n\nconst log = debug.extend('parse');\n\nexport interface IParseArgs extends IMaterialScanModel {\n  accesser?: 'online' | 'local';\n  dslType?: DSLType;\n  npmClient?: string;\n  workDir: string;\n  moduleDir: string;\n  typingsFileAbsolutePath?: string;\n  mainFileAbsolutePath: string;\n  moduleFileAbsolutePath?: string;\n}\n\nexport function isTSLike(str) {\n  return str.endsWith('ts') || str.endsWith('tsx');\n}\n\nexport default async (args: IParseArgs) => {\n  const {\n    typingsFileAbsolutePath,\n    mainFileAbsolutePath,\n    moduleFileAbsolutePath = mainFileAbsolutePath,\n    useEntry = false,\n  } = args;\n  if (args.accesser === 'local') {\n    if (isTSLike(mainFileAbsolutePath)) {\n      await install(args);\n      // in case the developer forgets to install types\n      await installTypeDTS(args);\n      return parseTS(mainFileAbsolutePath, args);\n    } else if (typingsFileAbsolutePath) {\n      await installTypeDTS(args);\n      return parseTS(typingsFileAbsolutePath, args);\n    } else {\n      try {\n        return parseJS(moduleFileAbsolutePath || mainFileAbsolutePath);\n      } catch (e) {\n        log(e);\n        await install(args);\n        const info = parseDynamic(mainFileAbsolutePath);\n        if (!info || !info.length) {\n          throw Error();\n        }\n        return info;\n      }\n    }\n  } else if (args.accesser === 'online') {\n    // ts\n    const entryPath = useEntry ? mainFileAbsolutePath : typingsFileAbsolutePath;\n    if (entryPath && isTSLike(entryPath)) {\n      await syncTypeModules(args);\n      await install(args);\n      await installTypeDTS(args);\n      await installPeerAndDevDeps(args);\n      return parseTS(entryPath, args);\n    }\n    // js\n    try {\n      // try dynamic parsing first\n      await installPeerAndDevDeps(args);\n      const info = parseDynamic(mainFileAbsolutePath);\n      if (!info || !info.length) {\n        throw Error();\n      }\n      return info;\n    } catch (e) {\n      log(e);\n      // if error, use static js parsing instead\n      return parseJS(moduleFileAbsolutePath || mainFileAbsolutePath);\n    }\n  }\n  return parseJS(moduleFileAbsolutePath || mainFileAbsolutePath);\n};\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/handlers/defaultPropsHandler.ts",
    "content": "import getComposedPath from '../utils/getComposedPath';\nimport evaluate from '../utils/evaluate';\n\nconst { namedTypes: t, NodePath, visit } = require('ast-types');\ntype NodePathType = typeof NodePath;\nconst {\n  getPropertyName,\n  isReactComponentClass,\n  getMemberValuePath,\n  isReactForwardRefCall,\n  printValue,\n  resolveToValue,\n} = require('react-docgen').utils;\nconst resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue');\n\nfunction getDefaultValue(path: NodePathType) {\n  let { node } = path;\n  let defaultValue;\n  if (t.Literal.check(node)) {\n    defaultValue = node.raw;\n  } else {\n    if (t.AssignmentPattern.check(path.node)) {\n      path = resolveToValue(path.get('right'));\n    } else {\n      path = resolveToValue(path);\n    }\n    if (t.ImportDeclaration.check(path.node)) {\n      defaultValue = node.name;\n    } else {\n      node = path.node;\n      try {\n        const result = evaluate(path);\n        if (result.confident) {\n          defaultValue = result.value;\n        }\n      } catch (e) {\n        // log(e);\n        // TODO\n      }\n    }\n  }\n  if (typeof defaultValue !== 'undefined') {\n    return {\n      value: defaultValue,\n      computed:\n        t.CallExpression.check(node) || t.MemberExpression.check(node) || t.Identifier.check(node),\n    };\n  }\n\n  return null;\n}\n\nfunction getStatelessPropsPath(componentDefinition: any) {\n  const value = resolveToValue(componentDefinition);\n  if (isReactForwardRefCall(value)) {\n    const inner = resolveToValue(value.get('arguments', 0));\n    return inner.get('params', 0);\n  }\n  return value.get('params', 0);\n}\n\nfunction getDefaultPropsPath(componentDefinition: any) {\n  let defaultPropsPath = getMemberValuePath(componentDefinition, 'defaultProps');\n  if (!defaultPropsPath) {\n    return null;\n  }\n\n  defaultPropsPath = resolveToValue(defaultPropsPath);\n  if (!defaultPropsPath) {\n    return null;\n  }\n\n  if (t.FunctionExpression.check(defaultPropsPath.node)) {\n    // Find the value that is returned from the function and process it if it is\n    // an object literal.\n    const returnValue = resolveFunctionDefinitionToReturnValue(defaultPropsPath);\n    if (returnValue && t.ObjectExpression.check(returnValue.node)) {\n      defaultPropsPath = returnValue;\n    }\n  }\n  return defaultPropsPath;\n}\n\nfunction getDefaultValuesFromProps(properties: any[], documentation: any, isStateless: boolean) {\n  properties\n    // Don't evaluate property if component is functional and the node is not an AssignmentPattern\n    .filter(\n      (propertyPath) => !isStateless || t.AssignmentPattern.check(propertyPath.get('value').node),\n    )\n    .forEach((propertyPath) => {\n      if (t.Property.check(propertyPath.node)) {\n        const propName = getPropertyName(propertyPath);\n        if (!propName) return;\n\n        const propDescriptor = documentation.getPropDescriptor(propName);\n        const defaultValue = getDefaultValue(\n          isStateless ? propertyPath.get('value', 'right') : propertyPath.get('value'),\n        );\n        if (defaultValue) {\n          propDescriptor.defaultValue = defaultValue;\n        }\n      } else if (t.SpreadElement.check(propertyPath.node)) {\n        const resolvedValuePath = resolveToValue(propertyPath.get('argument'));\n        if (t.ObjectExpression.check(resolvedValuePath.node)) {\n          getDefaultValuesFromProps(\n            resolvedValuePath.get('properties'),\n            documentation,\n            isStateless,\n          );\n        }\n      }\n    });\n}\n\nexport default function defaultPropsHandler(documentation: any, componentDefinition: any) {\n  let statelessProps = null;\n  let defaultPropsPath = getDefaultPropsPath(componentDefinition);\n  /**\n   * function, lazy, memo, forwardRef etc components can resolve default props as well\n   */\n  if (!isReactComponentClass(componentDefinition)) {\n    statelessProps = getStatelessPropsPath(componentDefinition);\n  }\n\n  // Do both statelessProps and defaultProps if both are available so defaultProps can override\n  if (statelessProps && t.ObjectPattern.check(statelessProps.node)) {\n    getDefaultValuesFromProps(statelessProps.get('properties'), documentation, true);\n  }\n  if (defaultPropsPath && !t.ObjectExpression.check(defaultPropsPath.node)) {\n    const composedPath = getComposedPath(documentation, 'defaultProps', defaultPropsPath);\n    if (composedPath) {\n      defaultPropsPath = composedPath;\n    }\n  }\n  if (defaultPropsPath && t.ObjectExpression.check(defaultPropsPath.node)) {\n    getDefaultValuesFromProps(defaultPropsPath.get('properties'), documentation, false);\n  }\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/handlers/index.ts",
    "content": "import { propTypeHandler, contextTypeHandler, childContextTypeHandler } from './propTypeHandler';\nimport defaultPropsHandler from './defaultPropsHandler';\nimport preProcessHandler from './preProcessHandler';\nimport propTypeJsDocHandler from './propTypeJsDocHandler';\n\nconst { handlers } = require('react-docgen');\n\nconst defaultHandlers = [\n  preProcessHandler,\n  handlers.propTypeCompositionHandler,\n  propTypeHandler,\n  contextTypeHandler,\n  childContextTypeHandler,\n  handlers.propDocBlockHandler,\n  propTypeJsDocHandler,\n  defaultPropsHandler,\n  handlers.componentDocblockHandler,\n  handlers.displayNameHandler,\n  handlers.componentMethodsJsDocHandler,\n];\n\nexport default defaultHandlers;\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/handlers/preProcessHandler.ts",
    "content": "export default function preProcessHandler(documentation: any, path: any) {\n  documentation.set('meta', path.__meta);\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/handlers/propTypeHandler.ts",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport { namedTypes as t, visit } from 'ast-types';\nimport fs from 'fs';\nimport path from 'path';\nimport getRoot from '../utils/getRoot';\nimport findJSFilePath from '../utils/findJSFilePath';\nimport getComposedPath from '../utils/getComposedPath';\nconst buildParser = require('react-docgen/dist/babelParser').default;\n\nconst {\n  resolveToValue,\n  isExportsOrModuleAssignment,\n  getPropType,\n  getPropertyName,\n  getMemberValuePath,\n  isReactModuleName,\n  printValue,\n  resolveToModule,\n} = require('react-docgen').utils;\n\nconst expressionTo = require('react-docgen/dist/utils/expressionTo');\nconst isRequiredPropType = require('react-docgen/dist/utils/isRequiredPropType')\n  .default;\n\nfunction isPropTypesExpression(path: any) {\n  const moduleName = resolveToModule(path);\n  if (moduleName) {\n    return isReactModuleName(moduleName) || moduleName === 'ReactPropTypes';\n  }\n  return false;\n}\n\nfunction amendPropTypes(getDescriptor: any, path: any, documentation, propName: string) {\n  if (!t.ObjectExpression.check(path.node)) {\n    const propTypesPath = getComposedPath(documentation, propName, path);\n    if (!propTypesPath) {\n      return;\n    } else {\n      path.replace(propTypesPath.node);\n    }\n  }\n\n  path.get('properties').each((propertyPath: any) => {\n    switch (propertyPath.node.type) {\n      // @ts-ignore\n      case t.Property.name: {\n        const propName = getPropertyName(propertyPath);\n        if (!propName) return;\n\n        const propDescriptor = getDescriptor(propName);\n        const valuePath = propertyPath.get('value');\n        const type = getPropType(valuePath);\n\n        if (type) {\n          propDescriptor.type = type;\n          propDescriptor.required =\n            type.name !== 'custom' && isRequiredPropType(valuePath);\n        }\n        break;\n      }\n      // @ts-ignore\n      case t.SpreadElement.name: {\n        const resolvedValuePath = resolveToValue(propertyPath.get('argument'));\n        switch (resolvedValuePath.node.type) {\n          // @ts-ignore\n          case t.ObjectExpression.name: // normal object literal\n            amendPropTypes(getDescriptor, resolvedValuePath, documentation, propName);\n            break;\n        }\n        break;\n      }\n    }\n  });\n}\n\nfunction getDefinePropertyValuePath(nodePath: any, propName: string) {\n  const program = getRoot(nodePath);\n  let resultPath = nodePath;\n  if (!nodePath.node.id) return;\n  const componentName = nodePath.node.id.name;\n\n  visit(program, {\n    visitCallExpression(path) {\n      const args = path.get('arguments');\n      const argsNodeList = args.value;\n      if (\n        argsNodeList.length === 3 &&\n        t.Identifier.check(argsNodeList[0]) &&\n        argsNodeList[0].name === componentName &&\n        t.Literal.check(argsNodeList[1]) &&\n        argsNodeList[1].value === propName\n      ) {\n        resultPath = args.get(2);\n      }\n      return false;\n    },\n  });\n  return resultPath;\n}\n\nfunction getPropTypeHandler(propName: string) {\n  return function (documentation: any, path: any) {\n    let propTypesPath = getMemberValuePath(path, propName);\n    if (!propTypesPath) {\n      propTypesPath = getDefinePropertyValuePath(path, propName);\n      if (!propTypesPath) {\n        return;\n      }\n    }\n    propTypesPath = resolveToValue(propTypesPath);\n    if (!propTypesPath) {\n      return;\n    }\n    let getDescriptor;\n    switch (propName) {\n      case 'childContextTypes':\n        getDescriptor = documentation.getChildContextDescriptor;\n        break;\n      case 'contextTypes':\n        getDescriptor = documentation.getContextDescriptor;\n        break;\n      default:\n        getDescriptor = documentation.getPropDescriptor;\n    }\n    amendPropTypes(getDescriptor.bind(documentation), propTypesPath, documentation, propName);\n  };\n}\n\nexport const propTypeHandler = getPropTypeHandler('propTypes');\nexport const contextTypeHandler = getPropTypeHandler('contextTypes');\nexport const childContextTypeHandler = getPropTypeHandler('childContextTypes');\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/handlers/propTypeJsDocHandler.ts",
    "content": "/* eslint-disable no-param-reassign */\nimport { set, get } from 'lodash';\nimport { debug } from '../../../core';\n\nconst log = debug.extend('parse:js');\n\nconst parseJsDoc = require('react-docgen/dist/utils/parseJsDoc').default;\nconst { getMemberValuePath, resolveToValue } = require('react-docgen').utils;\n\nfunction getType(type = 'void') {\n  const typeOfType = typeof type;\n  if (typeOfType === 'string') {\n    return typeOfType;\n  } else if (typeOfType === 'object') {\n    return get(type, 'name', 'void');\n  }\n  return 'void';\n}\n\nfunction generateRaw(params = [], returns = { type: 'void' }): string {\n  const raw = `(${params.filter(x => !!x).map(x => `${x.name}: ${getType(x.type)}`).join(', ')}) => ${returns ? getType(returns.type) : 'void'}`;\n  return raw;\n}\n\nfunction resolveDocumentation(documentation) {\n  documentation._props.forEach(propDescriptor => {\n    const { description } = propDescriptor;\n    if (description.includes('@') && propDescriptor?.type?.name === 'func') {\n      const jsDoc = parseJsDoc(description);\n      propDescriptor.description = jsDoc.description;\n      if (jsDoc.params) {\n        set(propDescriptor, ['type', 'params'], jsDoc.params);\n      }\n      if (jsDoc.returns) {\n        set(propDescriptor, ['type', 'returns'], jsDoc.returns);\n      }\n      try {\n        const raw = generateRaw(jsDoc.params, jsDoc.returns);\n        if (raw) {\n          set(propDescriptor, ['type', 'raw'], raw);\n        }\n      } catch (e) {\n        log(e);\n      }\n    }\n  });\n}\n\n/**\n * Extract info from the propType jsdoc blocks. Must be run after\n * propDocBlockHandler.\n */\nexport default function propTypeJsDocHandler(documentation, path) {\n  let propTypesPath = getMemberValuePath(path, 'propTypes');\n  if (!propTypesPath) {\n    return;\n  }\n  propTypesPath = resolveToValue(propTypesPath);\n  if (!propTypesPath) {\n    return;\n  }\n\n  resolveDocumentation(documentation);\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/index.ts",
    "content": "import { transformItem } from '../transform';\nimport { IMaterialParsedModel } from '../../types';\nimport { loadFile } from '../../utils';\nimport resolver from './resolver';\nimport handlers from './handlers';\n\nconst reactDocs = require('react-docgen');\n\nexport default function parse(filePath: string): IMaterialParsedModel[] {\n  if (!filePath) return [];\n  const fileContent = loadFile(filePath);\n  const result = reactDocs.parse(\n    fileContent,\n    (ast: any) => {\n      ast.__path = filePath;\n      return resolver(ast);\n    },\n    handlers,\n    {\n      filename: filePath,\n    },\n  );\n  const coms = result.reduce((res: any[], info: any) => {\n    if (!info || !info.props) return res;\n    const props = Object.keys(info.props).reduce((acc: any[], name) => {\n      try {\n        const item: any = transformItem(name, info.props[name]);\n        acc.push(item);\n      } catch (e) {\n        // TODO\n      }\n      return acc;\n    }, []);\n    res.push({\n      componentName: info.displayName,\n      props,\n      meta: info.meta || {},\n    });\n    return res;\n  }, []);\n  return coms;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/checkIsIIFE.ts",
    "content": "export default function checkIsIIFE(path: any) {\n  return (\n    path.value &&\n    path.value.callee &&\n    path.value.callee.type === 'FunctionExpression' &&\n    path.node.type === 'CallExpression'\n  );\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/findAssignedMethods.ts",
    "content": "import { namedTypes as t } from 'ast-types';\nimport isReactComponentStaticMember from './isReactComponentStaticMember';\n\nconst { match } = require('react-docgen').utils;\nconst { traverseShallow } = require('react-docgen/dist/utils/traverse');\n\nfunction findAssignedMethods(scope: any, idPath: any) {\n  const results: any[] = [];\n\n  if (!t.Identifier.check(idPath.node)) {\n    return results;\n  }\n\n  const { name } = idPath.node;\n  // const idScope = idPath.scope.lookup(idPath.node.name);\n\n  traverseShallow(scope.path, {\n    visitAssignmentExpression(path: any) {\n      const { node } = path;\n      if (\n        match(node.left, {\n          type: 'MemberExpression',\n          object: { type: 'Identifier', name },\n        })\n        // && path.scope.lookup(name) === idScope\n      ) {\n        results.push(path);\n        return false;\n      }\n      return this.traverse(path);\n    },\n  });\n\n  return results.filter((x) => !isReactComponentStaticMember(x.get('left')));\n}\n\nexport default findAssignedMethods;\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/index.ts",
    "content": "import { namedTypes as t, visit } from 'ast-types';\nimport { uniqBy } from 'lodash';\nimport checkIsIIFE from './checkIsIIFE';\nimport resolveHOC from './resolveHOC';\nimport resolveIIFE from './resolveIIFE';\nimport resolveImport from './resolveImport';\nimport resolveTranspiledClass from './resolveTranspiledClass';\nimport isStaticMethod from './isStaticMethod';\nimport findAssignedMethods from './findAssignedMethods';\nimport resolveExportDeclaration from './resolveExportDeclaration';\nimport makeProxy from '../utils/makeProxy';\nimport { get, set, has, ICache } from '../utils/cache';\nimport getName from '../utils/getName';\nimport getRoot from '../utils/getRoot';\n\nconst expressionTo = require('react-docgen/dist/utils/expressionTo');\n\nconst {\n  isExportsOrModuleAssignment,\n  isReactComponentClass,\n  isReactCreateClassCall,\n  isReactForwardRefCall,\n  isStatelessComponent,\n  normalizeClassDefinition,\n  resolveToValue,\n  getMemberValuePath,\n} = require('react-docgen').utils;\n\nfunction ignore() {\n  return false;\n}\n\nfunction isComponentDefinition(path: any) {\n  return (\n    isReactCreateClassCall(path) ||\n    isReactComponentClass(path) ||\n    isStatelessComponent(path) ||\n    isReactForwardRefCall(path)\n  );\n}\n\nfunction resolveDefinition(definition: any) {\n  if (isReactCreateClassCall(definition)) {\n    // return argument\n    const resolvedPath = resolveToValue(definition.get('arguments', 0));\n    if (t.ObjectExpression.check(resolvedPath.node)) {\n      return resolvedPath;\n    }\n  } else if (isReactComponentClass(definition)) {\n    normalizeClassDefinition(definition);\n    return definition;\n  } else if (isStatelessComponent(definition) || isReactForwardRefCall(definition)) {\n    return definition;\n  }\n  return null;\n}\n\nfunction getDefinition(definition: any, cache: ICache = {}): any {\n  const { __meta: exportMeta = {} } = definition;\n  if (checkIsIIFE(definition)) {\n    definition = resolveToValue(resolveIIFE(definition));\n    if (!isComponentDefinition(definition)) {\n      definition = resolveTranspiledClass(definition);\n    }\n  } else {\n    definition = resolveToValue(resolveHOC(definition));\n    if (isComponentDefinition(definition)) {\n      definition = makeProxy(definition, {\n        __meta: exportMeta,\n      });\n      return definition;\n    }\n    if (checkIsIIFE(definition)) {\n      definition = resolveToValue(resolveIIFE(definition));\n      if (!isComponentDefinition(definition)) {\n        definition = resolveTranspiledClass(definition);\n      }\n    } else if (t.SequenceExpression.check(definition.node)) {\n      const classNameNode = definition.parent.get('id').node;\n      const localNames: string[] = [];\n      let { node } = definition.get('expressions', 0);\n      while (t.AssignmentExpression.check(node)) {\n        // @ts-ignore\n        const { name } = node.left;\n        if (name) {\n          localNames.push(name);\n        }\n        node = node.right;\n      }\n      definition.get('expressions').each((x: any) => {\n        if (!x.name) return;\n        if (t.AssignmentExpression.check(x.node) && t.MemberExpression.check(x.node.left)) {\n          const objectName = x.node.left.object.name;\n          if (localNames.includes(objectName)) {\n            x.get('left', 'object').replace(classNameNode);\n          }\n        }\n      });\n      definition = getDefinition(resolveToValue(definition.get('expressions').get(0)), cache);\n    } else {\n      return resolveImport(definition, (ast: any, sourcePath: string, importMeta, mode) => {\n        let result;\n        if (has('ast-export', ast.__path)) {\n          result = get('ast-export', ast.__path);\n        } else {\n          result = findAllExportedComponentDefinition(ast);\n          set('ast-export', ast.__path, result);\n        }\n\n        const exportList: any[] = [];\n        const importList: any[] = [];\n        result.forEach((def: any) => {\n          const { __meta: meta = {} } = def;\n          let { exportName } = meta;\n          for (const item of importMeta) {\n            if (exportName === item.importedName) {\n              exportName = item.localName;\n              break;\n            }\n          }\n\n          if (exportName) {\n            importList.push(makeProxy(def, { __meta: { exportName } }));\n          }\n\n          const nextMeta: any = {\n            exportName,\n          };\n\n          if (exportName === exportMeta.localName) {\n            nextMeta.exportName = exportMeta.exportName;\n          } else if (mode === 'import') {\n            // } else {\n            return;\n          }\n\n          if (exportMeta.subName) {\n            nextMeta.subName = exportMeta.subName;\n          } else if (meta.subName) {\n            nextMeta.subName = meta.subName;\n          }\n          exportList.push(makeProxy(def, { __meta: nextMeta }));\n        });\n        cache[sourcePath] = importList;\n\n        // result = result.filter((x) => !x.__shouldDelete);\n        return exportList;\n      });\n    }\n  }\n  if (definition && (!definition.__meta || Object.keys(definition.__meta).length === 0)) {\n    definition.__meta = exportMeta;\n  }\n  return definition;\n}\n\nexport interface IMethodsPath {\n  subName: string;\n  localName: string;\n  value: any;\n}\n\n/**\n * Extract all flow types for the methods of a react component. Doesn't\n * return any react specific lifecycle methods.\n */\nfunction getSubComponents(path: any, scope: any, cache: ICache) {\n  // Extract all methods from the class or object.\n  let methodPaths = [];\n  if (isReactComponentClass(path)) {\n    methodPaths = path.get('body', 'body').filter(isStaticMethod);\n    methodPaths = [...methodPaths, ...findAssignedMethods(scope || path.scope, path.get('id'))];\n  } else if (t.ObjectExpression.check(path.node)) {\n    methodPaths = path.get('properties').filter(isStaticMethod);\n    methodPaths = [...methodPaths, ...findAssignedMethods(scope || path.scope, path.get('id'))];\n    // Add the statics object properties.\n    const statics = getMemberValuePath(path, 'statics');\n    if (statics) {\n      statics.get('properties').each((p: any) => {\n        if (isStaticMethod(p)) {\n          p.node.static = true;\n          methodPaths.push(p);\n        }\n      });\n    }\n  } else if (\n    t.VariableDeclarator.check(path.parent.node) &&\n    path.parent.node.init === path.node &&\n    t.Identifier.check(path.parent.node.id)\n  ) {\n    methodPaths = findAssignedMethods(scope || path.parent.scope, path.parent.get('id'));\n  } else if (\n    t.AssignmentExpression.check(path.parent.node) &&\n    path.parent.node.right === path.node &&\n    t.Identifier.check(path.parent.node.left)\n  ) {\n    methodPaths = findAssignedMethods(scope || path.parent.scope, path.parent.get('left'));\n  } else if (t.FunctionDeclaration.check(path.node)) {\n    methodPaths = findAssignedMethods(scope || path.parent.scope, path.get('id'));\n  } else if (t.ArrowFunctionExpression.check(path.node)) {\n    methodPaths = findAssignedMethods(scope || path.parent.scope, path.parent.get('id'));\n  }\n\n  return (\n    methodPaths\n      .map((x: any) => {\n        if (t.ClassProperty.check(x.node)) {\n          return {\n            value: x.get('value'),\n            subName: x.node.key.name,\n            localName: getName(x.get('value')),\n          };\n        }\n        return {\n          value: x,\n          subName: x.node.left.property.name,\n          localName: getName(x.get('right')),\n        };\n      })\n      .map(({ subName, localName, value }: IMethodsPath) => ({\n        subName,\n        localName,\n        value: resolveToValue(value),\n      }))\n      .map(({ subName, localName, value }: IMethodsPath) => {\n        let def = getDefinition(\n          makeProxy(value, {\n            __meta: {\n              localName,\n              subName,\n              exportName: path.__meta && path.__meta.exportName,\n            },\n          }),\n          cache,\n        );\n        if (!Array.isArray(def)) {\n          def = [def];\n        }\n        return {\n          subName,\n          localName,\n          value: def.flatMap((x: any) => x).filter((x: any) => isComponentDefinition(x)),\n        };\n      })\n      .map(({ subName, localName, value }: IMethodsPath) => {\n        return value.map((x: any) => ({\n          subName,\n          localName,\n          value: x,\n        }));\n      })\n      // @ts-ignore\n      .flatMap((x: any) => x)\n      .map(({ subName, value }: IMethodsPath) => {\n        const __meta = {\n          subName,\n          exportName: path.__meta && path.__meta.exportName,\n        };\n        return makeProxy(value, { __meta });\n      })\n  );\n}\n\n/**\n * Given an AST, this function tries to find the exported component definition.\n *\n * The component definition is either the ObjectExpression passed to\n * `React.createClass` or a `class` definition extending `React.Component` or\n * having a `render()` method.\n *\n * If a definition is part of the following statements, it is considered to be\n * exported:\n *\n * modules.exports = Definition;\n * exports.foo = Definition;\n * export default Definition;\n * export var Definition = ...;\n */\nexport default function findAllExportedComponentDefinition(ast: any) {\n  const components: any[] = [];\n  const cache: ICache = {};\n  let programScope: any;\n\n  function exportDeclaration(path: any) {\n    const definitions = resolveExportDeclaration(path)\n      .reduce((acc: any[], definition: any) => {\n        if (isComponentDefinition(definition)) {\n          acc.push(definition);\n        } else {\n          definition = getDefinition(definition, cache);\n          if (!Array.isArray(definition)) {\n            definition = [definition];\n          }\n          definition.forEach((def: any) => {\n            if (isComponentDefinition(def)) {\n              acc.push(def);\n            }\n          });\n        }\n        return acc;\n      }, [])\n      .map((definition: any) => {\n        const { __meta: meta } = definition;\n        const def = resolveDefinition(definition);\n        return makeProxy(def, { __meta: meta });\n      });\n\n    if (definitions.length === 0) {\n      return false;\n    }\n    definitions.forEach((definition: any) => {\n      if (definition && components.indexOf(definition) === -1) {\n        components.push(definition);\n      }\n    });\n    return false;\n  }\n\n  visit(ast, {\n    visitProgram(path) {\n      programScope = path.scope;\n      return this.traverse(path);\n    },\n    visitFunctionDeclaration: ignore,\n    visitFunctionExpression: ignore,\n    visitClassDeclaration: ignore,\n    visitClassExpression: ignore,\n    visitIfStatement: ignore,\n    visitWithStatement: ignore,\n    visitSwitchStatement: ignore,\n    visitWhileStatement: ignore,\n    visitDoWhileStatement: ignore,\n    visitForStatement: ignore,\n    visitForInStatement: ignore,\n    visitForOfStatement: ignore,\n    visitImportDeclaration: ignore,\n\n    visitExportNamedDeclaration: exportDeclaration,\n    visitExportDefaultDeclaration: exportDeclaration,\n    visitExportAllDeclaration(path) {\n      components.push(...resolveImport(path, findAllExportedComponentDefinition));\n      return false;\n    },\n\n    visitAssignmentExpression(path: any) {\n      // Ignore anything that is not `exports.X = ...;` or\n      // `module.exports = ...;`\n      if (!isExportsOrModuleAssignment(path)) {\n        return false;\n      }\n      const arr = expressionTo.Array(path.get('left'));\n      const meta: any = {\n        exportName: arr[1] === 'exports' ? 'default' : arr[1],\n      };\n      // Resolve the value of the right hand side. It should resolve to a call\n      // expression, something like React.createClass\n      path = resolveToValue(path.get('right'));\n      if (!isComponentDefinition(path)) {\n        path = getDefinition(path, cache);\n      }\n\n      if (!Array.isArray(path)) {\n        path = [path];\n      }\n\n      const definitions = path.map(resolveDefinition);\n\n      definitions.forEach((definition: any) => {\n        if (definition && components.indexOf(definition) === -1) {\n          // if (definition.__meta) {\n          definition = makeProxy(definition, {\n            __meta: meta,\n          });\n          // }\n          components.push(definition);\n        }\n      });\n      return false;\n    },\n  });\n\n  const result = components.reduce((acc, item) => {\n    let subModuleDefinitions = [];\n    subModuleDefinitions = getSubComponents(item, programScope, cache);\n    return [...acc, item, ...subModuleDefinitions];\n  }, []);\n\n  const res = uniqBy(result, (x: any) => {\n    return `${getRoot(x)?.node?.__path}/${x.__meta.exportName}/${x.__meta.subName}`;\n  });\n\n  return res;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/isReactComponentStaticMember.ts",
    "content": "import { namedTypes as t } from 'ast-types';\n\nconst { getPropertyName } = require('react-docgen').utils;\n\nconst reactStaticMembers = ['propTypes', 'defaultProps', 'contextTypes'];\nexport default function isReactComponentStaticMember(methodPath: any) {\n  let name;\n  if (t.MemberExpression.check(methodPath.node)) {\n    name = methodPath.node.property.name;\n  } else {\n    name = getPropertyName(methodPath);\n  }\n  return !!name && reactStaticMembers.indexOf(name) !== -1;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/isStaticMethod.ts",
    "content": "import { namedTypes as t } from 'ast-types';\nimport isReactComponentStaticMember from './isReactComponentStaticMember';\n\nconst { isReactComponentMethod } = require('react-docgen').utils;\n\n/**\n * judge if static method\n */\nfunction isStaticMethod(path: any) {\n  const isProbablyStaticMethod = t.ClassProperty.check(path.node) && path.node.static === true;\n\n  return isProbablyStaticMethod && !isReactComponentStaticMember(path) && !isReactComponentMethod(path);\n}\n\nexport default isStaticMethod;\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/resolveExportDeclaration.ts",
    "content": "import { namedTypes as t } from 'ast-types';\nimport makeProxy from '../utils/makeProxy';\nimport getName from '../utils/getName';\n\nexport default function resolveExportDeclaration(path: any) {\n  const definitions = [];\n  if (path.node.default || t.ExportDefaultDeclaration.check(path.node)) {\n    const def = path.get('declaration');\n    const meta: { [name: string]: string } = {\n      exportName: 'default',\n      localName: getName(def),\n    };\n\n    definitions.push(makeProxy(def, { __meta: meta }));\n  } else if (path.node.declaration) {\n    if (t.VariableDeclaration.check(path.node.declaration)) {\n      path.get('declaration', 'declarations').each((declarator: any) => {\n        definitions.push(\n          makeProxy(declarator, {\n            __meta: {\n              exportName: declarator.get('id').node.name,\n            },\n          }),\n        );\n      });\n    } else {\n      const def = path.get('declaration');\n      definitions.push(\n        makeProxy(def, {\n          __meta: {\n            exportName: 'default',\n          },\n        }),\n      );\n    }\n  } else if (path.node.specifiers) {\n    path.get('specifiers').each((specifier: any) => {\n      const def = specifier.node.id ? specifier.get('id') : specifier.get('local');\n      const exportName = specifier.get('exported').node.name;\n      const localName = def.get('local').node.name;\n\n      definitions.push(\n        makeProxy(def, {\n          __meta: {\n            exportName,\n            localName,\n          },\n        }),\n      );\n    });\n  }\n  return definitions;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/resolveHOC.ts",
    "content": "import { namedTypes as t } from 'ast-types';\n\nconst { isReactCreateClassCall, isReactForwardRefCall } = require('react-docgen').utils;\n\n/**\n * If the path is a call expression, it recursively resolves to the\n * rightmost argument, stopping if it finds a React.createClass call expression\n *\n * Else the path itself is returned.\n */\nexport default function resolveHOC(path: any): any {\n  const { node } = path;\n  if (\n    t.CallExpression.check(node) &&\n    !isReactCreateClassCall(path) &&\n    !isReactForwardRefCall(path)\n  ) {\n    if (node.arguments.length) {\n      const inner = path.get('arguments', 0);\n\n      // If the first argument is one of these types then the component might be the last argument\n      // If there are all identifiers then we cannot figure out exactly and have to assume it is the first\n      if (\n        node.arguments.length > 1 &&\n        (t.Literal.check(inner.node) ||\n          t.ObjectExpression.check(inner.node) ||\n          t.ArrayExpression.check(inner.node) ||\n          t.SpreadElement.check(inner.node))\n      ) {\n        return resolveHOC(\n          // resolveToValue(path.get('arguments', node.arguments.length - 1)),\n          path.get('arguments', node.arguments.length - 1),\n        );\n      }\n\n      // return resolveHOC(resolveToValue(inner));\n      return resolveHOC(inner);\n    }\n  }\n\n  return path;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/resolveIIFE.ts",
    "content": "import checkIsIIFE from './checkIsIIFE';\n\nconst resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue')\n  .default;\n/**\n * If the path is a call expression, it recursively resolves to the\n * rightmost argument, stopping if it finds a React.createClass call expression\n *\n * Else the path itself is returned.\n */\nexport default function resolveIIFE(path: any) {\n  if (!checkIsIIFE(path)) {\n    return path;\n  }\n  const returnValue = resolveFunctionDefinitionToReturnValue(\n    path.get('callee'),\n  );\n\n  return returnValue;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/resolveImport.ts",
    "content": "import { namedTypes as t } from 'ast-types';\nimport fs from 'fs';\nimport p from 'path';\nimport getRoot from '../utils/getRoot';\n\nconst { resolveToModule, resolveToValue, match } = require('react-docgen').utils;\n\nexport function isImportLike(path) {\n  const { node } = path;\n  return (\n    t.ImportDeclaration.check(node) ||\n    t.ExportAllDeclaration.check(node) ||\n    t.ExportNamedDeclaration.check(node)\n  );\n}\n\nexport function isRequireLike(path: any) {\n  if (\n    t.CallExpression.check(path.node) &&\n    t.Identifier.check(path.get('callee').node) &&\n    path.get('callee').node.name === 'require' &&\n    t.Literal.check(path.get('arguments', 0)?.node)\n  ) {\n    return true;\n  }\n\n  return false;\n}\n\nexport function resolveToImport(initialPath) {\n  const pathBuffer = [initialPath];\n\n  while (pathBuffer.length) {\n    let path = pathBuffer.shift();\n    const node = path.node;\n    switch (node.type) {\n      case 'VariableDeclarator':\n        if (node.init) {\n          pathBuffer.unshift(path.get('init'));\n        }\n        break;\n      case 'CallExpression': {\n        if (match(node.callee, { type: 'Identifier', name: 'require' })) {\n          return path;\n        }\n        const paths = [path.get('callee')];\n        const argumentsPath = path.get('arguments');\n        for (let index = 0; index < argumentsPath.value.length; index++) {\n          paths.push(argumentsPath.get(index));\n        }\n        pathBuffer.unshift(...paths);\n      }\n      // eslint-disable-next-line no-fallthrough\n      case 'Identifier':\n      case 'JSXIdentifier': {\n        const valuePath = resolveToValue(path);\n        if (valuePath !== path) {\n          pathBuffer.unshift(valuePath);\n        }\n        break;\n      }\n      case 'ImportDeclaration':\n        return path;\n      case 'MemberExpression':\n        while (path && t.MemberExpression.check(path.node)) {\n          path = path.get('object');\n        }\n        if (path) {\n          pathBuffer.unshift(path);\n        }\n    }\n  }\n\n  return null;\n}\n\nfunction getPath(path: any, name: any) {\n  const root = getRoot(path).node;\n  if (!root) return;\n  let { __path } = root;\n  __path = p.dirname(__path);\n  // is directory\n  if (fs.existsSync(p.resolve(__path, name))) {\n    name += '/index';\n  }\n  const suffix = suffixes.find((suf) => {\n    return fs.existsSync(p.resolve(__path, name + suf));\n  });\n  if (!suffix) return;\n  return p.resolve(__path, name + suffix);\n}\n\nconst buildParser = require('react-docgen/dist/babelParser').default;\n\nconst suffixes = ['.js', '.jsx', '.ts', '.tsx'];\n\nconst cache: {\n  [name: string]: any;\n} = {};\n\nexport default function resolveImport(path: any, callback: any) {\n  let name;\n  let mode: 'import' | 'require' = 'import';\n\n  let importPath;\n  if (path.name === 'local') {\n    name = path.parentPath.parentPath.parentPath.node.source.value;\n    importPath = path;\n  } else {\n    importPath = resolveToImport(path);\n    if (!importPath) {\n      return path;\n    }\n    if (isImportLike(importPath)) {\n      name = importPath.node.source.value;\n    } else if (isRequireLike(importPath)) {\n      const moduleName = resolveToModule(importPath);\n      if (typeof moduleName === 'string') {\n        mode = 'require';\n        name = moduleName;\n      }\n    } else {\n      return path;\n    }\n  }\n\n  if (name) {\n    const __path = getPath(path, name);\n    if (!__path) return path;\n    let ast;\n    if (!cache[__path]) {\n      const fileContent = fs.readFileSync(__path, 'utf8');\n      const parser = buildParser({ filename: __path });\n      ast = parser.parse(fileContent);\n      ast.__src = fileContent;\n      ast.__path = __path;\n      cache[__path] = ast;\n    } else {\n      ast = cache[__path];\n    }\n\n    const importMeta: any[] = [];\n    if (mode === 'import') {\n      if (t.ImportDeclaration.check(importPath.node)) {\n        // @ts-ignore\n        const specifiers = importPath.get('specifiers');\n        specifiers.each((spec: any) => {\n          const { node } = spec;\n          importMeta.push({\n            localName: node.local.name,\n            importedName: node.imported ? node.imported.name : 'default',\n          });\n        });\n      }\n    } else {\n      const idPath = importPath.parentPath.get('id');\n      if (t.Identifier.check(idPath.node)) {\n        importMeta.push({\n          localName: 'default',\n          importedName: idPath.node.name,\n        });\n      } else if (t.ObjectPattern.check(path.node)) {\n        path.get('properties').each((propertyPath) => {\n          const keyPath = propertyPath.get('key');\n          const valuePath = propertyPath.get('value');\n          if (t.Identifier.check(keyPath.node) && t.Identifier.check(valuePath.node)) {\n            importMeta.push({\n              localName: keyPath.node.name,\n              importedName: valuePath.node.name,\n            });\n          }\n        });\n      }\n    }\n\n    return callback(ast, __path, importMeta, mode);\n  }\n  return path;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/resolver/resolveTranspiledClass.ts",
    "content": "import { builders, NodePath, visit } from 'ast-types';\n/**\n * If the path is a call expression, it recursively resolves to the\n * rightmost argument, stopping if it finds a React.createClass call expression\n *\n * Else the path itself is returned.\n */\nexport default function resolveTranspiledClass(path: any) {\n  let classPath = path;\n  visit(path, {\n    visitFunctionDeclaration(arg) {\n      classPath = new NodePath(\n        builders.functionDeclaration(\n          // @ts-ignore\n          arg.node.id || 'Default',\n          [],\n          builders.blockStatement([\n            builders.returnStatement(\n              builders.jsxElement(\n                builders.jsxOpeningElement(builders.jsxIdentifier('div'), [], true),\n              ),\n            ),\n          ]),\n        ),\n        path.parent,\n      );\n      return false;\n    },\n  });\n  return classPath;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/utils/cache.ts",
    "content": "export interface ICache {\n  [name: string]: any;\n}\n\nconst cache: ICache = {};\n\nexport function set(scope: string, name: string, value: any) {\n  cache[scope] = cache[scope] || {};\n  cache[scope][name] = value;\n}\n\nexport function get(scope: string, name: string) {\n  return (cache[scope] || {})[name];\n}\n\nexport function has(scope: string, name: string) {\n  return cache[scope] && Object.prototype.hasOwnProperty.call(cache[scope], name);\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/utils/evaluate.ts",
    "content": "const { namedTypes: t } = require('ast-types');\n\nconst { resolveToValue } = require('react-docgen').utils;\n\nfunction isInfinity(path) {\n  return t.Identifier.check(path.node) && path.node.name === 'Infinity';\n}\n\nfunction wrapValue(value, confident = true) {\n  return {\n    value,\n    confident,\n  };\n}\n\nexport default function evaluate(path: any) {\n  if (t.UnaryExpression.check(path.node)) {\n    if (path.node.operator === 'void') {\n      return wrapValue(undefined);\n    }\n\n    const argument = path.get('argument');\n\n    const result = evaluate(argument);\n    if (!result.confident) {\n      return wrapValue(undefined, false);\n    }\n\n    const arg = result.value;\n    if (arg === undefined) {\n      return wrapValue(undefined);\n    }\n\n    switch (path.node.operator) {\n      case '!':\n        return wrapValue(!arg);\n      case '+':\n        return wrapValue(+arg);\n      case '-':\n        return wrapValue(-arg);\n      case '~':\n        return wrapValue(~arg);\n      case 'typeof':\n        return wrapValue(typeof arg);\n    }\n  }\n\n  if (t.Identifier.check(path.node)) {\n    const valuePath = resolveToValue(path);\n    if (isInfinity(valuePath)) {\n      return wrapValue(undefined);\n    }\n    return evaluate(valuePath);\n  }\n\n  if (t.Literal.check(path.node)) {\n    return wrapValue(path.node.value);\n  }\n\n  if (t.ObjectExpression.check(path.node)) {\n    const returnValue = {};\n    path.get('properties').each((propertyPath) => {\n      const { confident, value } = evaluate(propertyPath.get('value'));\n      if (!confident) {\n        return;\n      }\n      const keyPath = propertyPath.get('key');\n      let key;\n      if (keyPath.node.computed) {\n        const result = evaluate(keyPath);\n        if (!result.confident) {\n          return;\n        }\n        key = result.value;\n      } else {\n        key = keyPath.node.name;\n      }\n      returnValue[key] = value;\n    });\n\n    return wrapValue(returnValue);\n  }\n\n  if (t.ArrayExpression.check(path.node)) {\n    const value = [];\n    let isValid = true;\n    path.get('elements').each((x) => {\n      if (!isValid) return;\n      const result = evaluate(x);\n      if (!result.confident) {\n        isValid = false;\n      } else {\n        value.push(result.value);\n      }\n    });\n\n    if (isValid) {\n      return wrapValue(value);\n    }\n  }\n\n  return wrapValue(undefined, false);\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/utils/findJSFilePath.ts",
    "content": "import fs from 'fs';\n\nconst suffixes = ['js', 'jsx'];\nexport default function findJSFilePath(fileBasePath: string): string {\n  let filePath;\n  for (const suffix of suffixes) {\n    const fp = `${fileBasePath}.${suffix}`;\n    if (fs.existsSync(fp)) {\n      filePath = fp;\n      break;\n    }\n  }\n\n  return filePath;\n}"
  },
  {
    "path": "modules/material-parser/src/parse/js/utils/getComposedPath.ts",
    "content": "import { namedTypes as t, visit } from 'ast-types';\nimport fs from 'fs';\nimport path from 'path';\nimport getRoot from './getRoot';\nimport findJSFilePath from './findJSFilePath';\n\nconst buildParser = require('react-docgen/dist/babelParser').default;\nconst expressionTo = require('react-docgen/dist/utils/expressionTo');\n\nconst {\n  resolveToValue,\n  isExportsOrModuleAssignment,\n} = require('react-docgen').utils;\n\nexport default function getComposedPropTypesPath(documentation, propName, p) {\n  const composes: string[] = Array.from(documentation._composes);\n  let _path = null;\n  const root = getRoot(p).node;\n  for (const compose of composes) {\n    const composePath = findJSFilePath(path.resolve(path.dirname(root.__path), compose));\n    if (!composePath) continue;\n\n    const fileContent = fs.readFileSync(composePath, 'utf8');\n    const parser = buildParser({ filename: composePath });\n    const ast = parser.parse(fileContent);\n\n    visit(ast, {\n      // eslint-disable-next-line no-loop-func\n      visitAssignmentExpression(path: any) {\n        // Ignore anything that is not `exports.X = ...;` or\n        // `module.exports = ...;`\n        if (!isExportsOrModuleAssignment(path)) {\n          return false;\n        }\n        const arr = expressionTo.Array(path.get('left'));\n        if (!(arr[0] === 'exports' && arr[1] === propName)) return false;\n\n        // Resolve the value of the right hand side. It should resolve to a call\n        // expression, something like React.createClass\n        path = resolveToValue(path.get('right'));\n        _path = path;\n        return false;\n      },\n    });\n\n    if (_path) {\n      break;\n    }\n  }\n\n  return _path;\n}"
  },
  {
    "path": "modules/material-parser/src/parse/js/utils/getName.ts",
    "content": "import { namedTypes as t } from 'ast-types';\n\nexport default function (def: any) {\n  let name = '';\n  if (def.node.name) {\n    name = def.node.name;\n    // hoc\n  } else if (t.CallExpression.check(def.node)) {\n    if (def.node.arguments && def.node.arguments.length && t.Identifier.check(def.get('arguments', 0).node)) name = def.get('arguments', 0).node.name;\n  }\n\n  return name;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/utils/getRoot.ts",
    "content": "export default function getRoot(path: any) {\n  let root = path.parent;\n  while (root.parent) {\n    root = root.parent;\n  }\n  return root;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/js/utils/makeProxy.ts",
    "content": "function makeProxy(target: { [name: string]: any }, meta: any = {}): any {\n  if (target.__isProxy) {\n    const value = target.__getRaw();\n    const rawMeta = target.__getMeta();\n    return makeProxy(value, Object.assign({}, rawMeta, meta));\n  }\n  return new Proxy(target, {\n    get: (obj, prop: string | number) => {\n      if (prop === '__isProxy') return true;\n      if (prop === '__getRaw') return () => target;\n      if (prop === '__getMeta') return () => meta;\n      return Object.prototype.hasOwnProperty.call(meta, prop) ? meta[prop] : obj[prop];\n    },\n    has: (obj, prop) => {\n      return (\n        Object.prototype.hasOwnProperty.call(obj, prop) ||\n        Object.prototype.hasOwnProperty.call(meta, prop)\n      );\n    },\n  });\n}\n\nexport default makeProxy;\n"
  },
  {
    "path": "modules/material-parser/src/parse/transform.ts",
    "content": "import { omit, pick, isNil, uniq } from 'lodash';\nimport { safeEval, isEvaluable } from '../utils';\nimport { debug } from '../core';\n\nconst log = debug.extend('parse:transform');\n\nexport function transformType(itemType: any) {\n  if (typeof itemType === 'string') return itemType;\n  const {\n    name,\n    elements,\n    value = elements,\n    computed,\n    required,\n    type,\n    raw,\n    params,\n    returns,\n  } = itemType;\n  if (computed !== undefined && value) {\n    return safeEval(value);\n  }\n  const result: any = {\n    type: name,\n  };\n  if (required) {\n    result.isRequired = required;\n  }\n  switch (name) {\n    case 'number':\n    case 'string':\n    case 'bool':\n    case 'any':\n    case 'symbol':\n    case 'object':\n    case 'null':\n    case 'array':\n    case 'element':\n    case 'node':\n    case 'void':\n      break;\n    case 'func':\n      if (params) {\n        result.params = params.map((x) => {\n          const res: any = {\n            name: x.name,\n            propType: transformType(x.type || x.propType),\n          };\n          if (x.description) {\n            res.description = x.description;\n          }\n          return res;\n        });\n      }\n      if (returns) {\n        result.returns = {\n          propType: transformType(returns.type || returns.propType),\n        };\n      }\n      if (raw) {\n        result.raw = raw;\n      }\n      break;\n    case 'literal': {\n      result.type = 'oneOf';\n      try {\n        const literalValue = safeEval(value);\n        result.value = [literalValue];\n      } catch (e) {\n        result.value = [raw];\n      }\n      break;\n    }\n    case 'enum':\n    case 'oneOf':\n      result.type = 'oneOf';\n      result.value = value.map(transformType);\n      break;\n    case 'tuple':\n      result.type = 'tuple';\n      result.value = value.map(transformType);\n      break;\n    case 'union': {\n      if (itemType.raw) {\n        if (itemType.raw.match(/ReactNode$/)) {\n          result.type = 'node';\n          break;\n        } else if (itemType.raw.match(/Element$/)) {\n          result.type = 'element';\n          break;\n        }\n      }\n    }\n    // eslint-disable-next-line no-fallthrough\n    case 'oneOfType':\n      result.type = 'oneOfType';\n      result.value = value.map(transformType);\n      break;\n    case 'boolean':\n      result.type = 'bool';\n      break;\n    case 'Function':\n      result.type = 'func';\n      break;\n    case 'unknown':\n      result.type = 'any';\n      break;\n    case 'Array':\n    case 'arrayOf': {\n      result.type = 'arrayOf';\n      let _itemType = transformType(value[0]);\n      if (typeof _itemType === 'object') {\n        _itemType = omit(_itemType, ['isRequired']);\n      }\n\n      result.value = _itemType;\n      break;\n    }\n    case 'signature': {\n      if (typeof type === 'string') {\n        result.type = type;\n        break;\n      }\n      result.type = 'shape';\n      const properties = type?.signature?.properties || itemType?.signature?.properties || [];\n      if (properties.length === 0) {\n        if (raw?.includes('=>')) {\n          result.type = 'func';\n          result.raw = raw;\n        } else {\n          result.type = 'object';\n        }\n      } else if (properties.length === 1 && typeof properties[0].key === 'object') {\n        const v = transformType(properties[0].value);\n        if (v === 'any') {\n          result.type = 'object';\n        } else if (typeof v === 'string') {\n          result.value = v;\n          result.type = 'objectOf';\n        } else if (typeof v?.type === 'string') {\n          result.value = v.type;\n          result.type = 'objectOf';\n        } else {\n          result.type = 'object';\n        }\n      } else if (properties.length === 1 && properties[0].key === '__call') {\n        result.type = 'func';\n      } else {\n        result.value = properties\n          .filter((item: any) => typeof item.key !== 'object')\n          .map((prop: any) => {\n            const { key } = prop;\n            const typeItem = {\n              ...omit(prop.value, 'name'),\n              type: prop.value.type || {},\n            };\n            typeItem.type = {\n              ...typeItem.type,\n              ...pick(prop.value, ['name', 'value']),\n            };\n            return transformItem(key, typeItem);\n          });\n      }\n      break;\n    }\n    case 'objectOf':\n    case 'instanceOf':\n      result.value = transformType(value);\n      break;\n    case 'exact':\n    case 'shape':\n      result.value = Object.keys(value).map((n) => {\n        const { name: _name, ...others } = value[n];\n        return transformItem(n, {\n          ...others,\n          type: {\n            name: _name,\n          },\n        });\n      });\n      break;\n    case (name.match(/ReactNode$/) || {}).input:\n      result.type = 'node';\n      break;\n    case (name.match(/JSX\\.Element$/) || {}).input:\n      result.type = 'element';\n      break;\n    default:\n      result.type = 'object';\n      break;\n  }\n  if (Object.keys(result).length === 1) {\n    return result.type;\n  }\n  if (result?.type === 'oneOfType') {\n    return combineOneOfValues(result);\n  }\n  return result;\n}\n\nfunction combineOneOfValues(propType) {\n  if (propType.type !== 'oneOfType') {\n    return propType;\n  }\n  const newValue = [];\n  let oneOfItem = null;\n  let firstBooleanIndex = -1;\n  propType.value.forEach((item) => {\n    if (item?.type === 'oneOf') {\n      if (!oneOfItem) {\n        oneOfItem = {\n          type: 'oneOf',\n          value: [],\n        };\n      }\n      if (item.value.includes(true) || item.value.includes(false)) {\n        if (firstBooleanIndex !== -1) {\n          oneOfItem.value.splice(firstBooleanIndex, 1);\n          newValue.push('bool');\n        } else {\n          firstBooleanIndex = oneOfItem.value.length;\n          oneOfItem.value = oneOfItem.value.concat(item.value);\n        }\n      } else {\n        oneOfItem.value = oneOfItem.value.concat(item.value);\n      }\n    } else {\n      newValue.push(item);\n    }\n  });\n  let result = propType;\n  const oneOfItemLength = oneOfItem?.value?.length;\n  if (oneOfItemLength) {\n    newValue.push(oneOfItem);\n  }\n  if (firstBooleanIndex !== -1 || oneOfItemLength) {\n    result = {\n      ...propType,\n      value: newValue,\n    };\n  }\n  if (result.value.length === 1 && result.value[0]?.type === 'oneOf') {\n    result = {\n      ...result,\n      type: 'oneOf',\n      value: result.value[0].value,\n    };\n  }\n  result.value = uniq(result.value);\n  return result;\n}\n\nexport function transformItem(name: string, item: any) {\n  const {\n    description,\n    flowType,\n    tsType,\n    type = tsType || flowType,\n    optional,\n    required = optional,\n    defaultValue,\n    ...others\n  } = item;\n  const result: any = {\n    name,\n  };\n\n  if (type) {\n    result.propType = transformType({\n      ...type,\n      ...omit(others, ['name']),\n      required: !!required,\n    });\n  }\n  if (description) {\n    if (description.includes('\\n')) {\n      result.description = description.split('\\n')[0];\n    } else {\n      result.description = description;\n    }\n  }\n  if (!isNil(defaultValue) && typeof defaultValue === 'object' && isEvaluable(defaultValue)) {\n    if (defaultValue === null) {\n      result.defaultValue = defaultValue;\n    } else if ('computed' in defaultValue) {\n      // parsed data from react-docgen\n      try {\n        if (isEvaluable(defaultValue.value)) {\n          result.defaultValue = safeEval(defaultValue.value);\n        } else {\n          result.defaultValue = defaultValue.value;\n        }\n      } catch (e) {\n        log(e);\n      }\n    } else {\n      // parsed data from react-docgen-typescript\n      result.defaultValue = defaultValue.value;\n    }\n  }\n  if (result.propType === undefined) {\n    delete result.propType;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/ts/generateDTS.ts",
    "content": "import * as path from 'path';\nimport { writeFileSync, pathExistsSync, ensureDirSync, copySync } from 'fs-extra';\nimport { loadFile } from '../../utils';\n\nimport { debug } from '../../core';\n\nconst log = debug.extend('parse:ts:generate_dts');\n\n/**\n * Generate alias dts file by removing some needless interfaces.\n * Replace original file at present, which will cause type pollution, looking for better solution\n * @param {string} workDir - the dir containing the module to be parsed\n * @returns {string} - the path of generated xxx.d.ts\n */\nexport default function generateDTS({\n  workDir,\n  dslType = 'react',\n}: {\n  workDir: string;\n  dslType?: string;\n}): {\n  originalTypePath: string;\n  newTypePath: string;\n} {\n  const typeDir = path.join(workDir, 'node_modules', `@types/${dslType}`);\n  const typePath = path.join(typeDir, 'index.d.ts');\n  const fileContent = loadFile(typePath);\n  // const materialParserTypeDir = path.join(workDir, `node_modules/material-parser-types/${type}`);\n  // ensureDirSync(materialParserTypeDir);\n  const materialParserTypeDir = typeDir;\n  const newTypePath = path.join(materialParserTypeDir, 'index.d.ts');\n  // if (!pathExistsSync(newTypePath)) {\n  // copySync(\n  //   path.join(typeDir, 'global.d.ts'),\n  //   path.join(materialParserTypeDir, 'global.d.ts'),\n  // );\n  let newContent = fileContent.replace(\n    /(?<=interface HTMLAttributes[^e]+)(extends[^}]+)/,\n    `{\n    style?: CSSProperties;\n    className?: string;\n  `,\n  );\n  newContent = newContent.replace(/(?<=interface IntrinsicElements {)([^}]+)/, '');\n  newContent = newContent.replace(/type LibraryManagedAttributes[^;]+;/, '');\n  writeFileSync(newTypePath, newContent);\n  log('generate dts', newTypePath);\n  // } else {\n  //   log('found dts', newTypePath);\n  // }\n\n  return {\n    originalTypePath: typePath,\n    newTypePath,\n  };\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/ts/index.ts",
    "content": "import * as path from 'path';\nimport { Parser, ComponentDoc } from 'react-docgen-typescript';\nimport ts, { SymbolFlags, TypeFlags, SyntaxKind } from 'typescript';\nimport { isEmpty, isEqual } from 'lodash';\nimport { existsSync, readFileSync } from 'fs-extra';\nimport findConfig from 'find-config';\nimport { debug } from '../../core';\nimport { Json } from '../../types';\nimport { transformItem } from '../transform';\nimport generateDTS from './generateDTS';\nimport { IParseArgs } from '../index';\n\nconst log = debug.extend('parse:ts');\n\ntype ExtendedType = ts.Type & {\n  id: string;\n  typeArguments: any[];\n};\n\nfunction getNextParentIds(parentIds: number[], type: ts.Type) {\n  // @ts-ignore\n  const id = type?.symbol?.id;\n  if (id) {\n    return [...parentIds, id];\n  }\n  return parentIds;\n}\n\nfunction getSymbolName(symbol: ts.Symbol) {\n  // @ts-ignore\n  const prefix: string = symbol?.parent && getSymbolName(symbol.parent);\n  const name = symbol.getName();\n  if (prefix && prefix.length <= 20) {\n    return `${prefix}.${name}`;\n  }\n  return name;\n}\n\nfunction getFunctionParams(parameters: any[] = [], checker, parentIds, type) {\n  return parameters.map((node) => {\n    const typeObject = checker.getTypeOfSymbolAtLocation(node.symbol, node.symbol.valueDeclaration);\n    const v = getDocgenTypeHelper(checker, typeObject, false, getNextParentIds(parentIds, type));\n    const name = node.symbol.escapedName;\n    return {\n      name,\n      propType: v,\n    };\n  });\n}\n\nfunction getFunctionReturns(node: any, checker, parentIds, type) {\n  if (!node) return {};\n  const propType = getDocgenTypeHelper(\n    checker,\n    node.type,\n    false,\n    getNextParentIds(parentIds, type),\n  );\n  return {\n    propType,\n  };\n}\n\nconst blacklistNames = [\n  'prototype',\n  'getDerivedStateFromProps',\n  'propTypes',\n  'defaultProps',\n  'contextTypes',\n  'displayName',\n  'contextType',\n  'Provider',\n  'Consumer',\n];\n\nconst blacklistPatterns = [\n  /^HTML/,\n  /^React\\./,\n  /^Object$/,\n  /^Date$/,\n  /^Promise$/,\n  /^XML/,\n  /^Function$/,\n];\n\n// function hasTooManyTypes(type) {\n//   return type?.types?.length >= 20;\n// }\n\nfunction isComplexType(type) {\n  let isAliasSymbol = false;\n  let symbol = type?.symbol;\n  if (!symbol) {\n    symbol = type?.aliasSymbol;\n    isAliasSymbol = true;\n  }\n  if (!symbol) return false;\n  if (isAliasSymbol) {\n    return false;\n  }\n  const name = getSymbolName(symbol);\n  if (blacklistPatterns.some((patt) => patt.test(name))) {\n    return true;\n  }\n  return false;\n}\n\nfunction getDocgenTypeHelper(\n  checker: ts.TypeChecker,\n  type: ts.Type,\n  skipRequired = false,\n  parentIds: number[] = [],\n  isRequired = false,\n): any {\n  function isTuple(_type: ts.Type) {\n    // @ts-ignore use internal methods\n    return checker.isArrayLikeType(_type) && !checker.isArrayType(_type);\n  }\n  let required: boolean;\n  if (isRequired !== undefined) {\n    required = isRequired;\n  } else {\n    required = !(type.flags & SymbolFlags.Optional) || isRequired;\n  }\n\n  function makeResult(typeInfo: Json) {\n    if (skipRequired) {\n      return {\n        raw: checker.typeToString(type),\n        ...typeInfo,\n      };\n    } else {\n      return {\n        required,\n        raw: checker.typeToString(type),\n        ...typeInfo,\n      };\n    }\n  }\n\n  function getShapeFromArray(symbolArr: ts.Symbol[], _type: ts.Type) {\n    const shape: Array<{\n      key:\n        | {\n            name: string;\n          }\n        | string;\n      value: any;\n    }> = symbolArr.map((prop) => {\n      const propType = checker.getTypeOfSymbolAtLocation(\n        prop,\n        // @ts-ignore\n        prop.valueDeclaration || (prop.declarations && prop.declarations[0]) || {},\n      );\n      return {\n        key: prop.getName(),\n\n        value: getDocgenTypeHelper(\n          checker,\n          propType,\n          false,\n          // @ts-ignore\n          getNextParentIds(parentIds, _type),\n          // @ts-ignore\n          !prop?.valueDeclaration?.questionToken,\n        ),\n      };\n    });\n    // @ts-ignore use internal methods\n    if (checker.isArrayLikeType(_type)) {\n      return shape;\n    }\n    if (_type.getStringIndexType()) {\n      // @ts-ignore use internal methods\n      if (!_type.stringIndexInfo) {\n        return shape;\n      }\n      shape.push({\n        key: {\n          name: 'string',\n        },\n        value: getDocgenTypeHelper(\n          checker,\n          // @ts-ignore use internal methods\n          _type.stringIndexInfo.type,\n          false,\n          getNextParentIds(parentIds, _type),\n        ),\n      });\n    } else if (_type.getNumberIndexType()) {\n      // @ts-ignore use internal methods\n      if (!_type.numberIndexInfo) {\n        return shape;\n      }\n      shape.push({\n        key: {\n          name: 'number',\n        },\n\n        value: getDocgenTypeHelper(\n          checker,\n          // @ts-ignore use internal methods\n          _type.numberIndexInfo.type,\n          false,\n          getNextParentIds(parentIds, _type),\n        ),\n      });\n    }\n    return shape;\n  }\n\n  function getShape(_type: ts.Type) {\n    const { symbol } = _type;\n    if (symbol && symbol.members) {\n      // @ts-ignore\n      const props: ts.Symbol[] = Array.from(symbol.members.values());\n      // if (props.length >= 20) {\n      //   throw new Error('too many props');\n      // }\n      return getShapeFromArray(\n        props.filter((prop) => prop.getName() !== '__index'),\n        _type,\n      );\n    } else {\n      // @ts-ignore\n      const args = _type.resolvedTypeArguments || [];\n      const props = checker.getPropertiesOfType(_type);\n      // if (props.length >= 20) {\n      //   throw new Error('too many props');\n      // }\n      const shape = getShapeFromArray(props.slice(0, args.length), _type);\n      return shape;\n    }\n  }\n\n  // @ts-ignore\n  if (type?.kind === SyntaxKind.VoidExpression) {\n    return makeResult({\n      name: 'void',\n      raw: 'void',\n    });\n  }\n\n  const pattern = /^__global\\.(.+)$/;\n  // @ts-ignore\n  if (parentIds.includes(type?.symbol?.id)) {\n    return makeResult({\n      name: 'object', // checker.typeToString(type),\n    });\n  }\n  if (type.symbol) {\n    const symbolName = getSymbolName(type.symbol);\n    if (symbolName) {\n      const matches = pattern.exec(symbolName);\n      if (matches) {\n        return makeResult({\n          name: matches[1],\n        });\n      }\n    }\n  }\n\n  if (type.flags & TypeFlags.Number) {\n    return makeResult({\n      name: 'number',\n    });\n  } else if (type.flags & TypeFlags.String) {\n    return makeResult({\n      name: 'string',\n    });\n  } else if (type.flags & TypeFlags.NumberLiteral) {\n    return makeResult({\n      name: 'literal',\n      // @ts-ignore\n      value: type.value,\n    });\n  } else if (type.flags & TypeFlags.Literal) {\n    return makeResult({\n      name: 'literal',\n      value: checker.typeToString(type),\n    });\n  } else if (type.symbol?.flags & SymbolFlags.Enum) {\n    return makeResult({\n      name: 'union',\n      // @ts-ignore\n      value: type.types.map((t) => t.value),\n    });\n    // @ts-ignore\n  } else if (type.flags & TypeFlags.DisjointDomains) {\n    return makeResult({\n      name: checker.typeToString(type),\n    });\n  } else if (type.flags & TypeFlags.Any) {\n    return makeResult({\n      name: 'any',\n    });\n  } else if (type.flags & TypeFlags.Union && !isComplexType(type)) {\n    return makeResult({\n      name: 'union',\n      // @ts-ignore\n      value: type.types.map((t) =>\n        getDocgenTypeHelper(checker, t, true, getNextParentIds(parentIds, type))),\n    });\n  } else if (isComplexType(type)) {\n    return makeResult({\n      name: getSymbolName(type?.symbol || type?.aliasSymbol),\n    });\n  } else if (type.flags & (TypeFlags.Object | TypeFlags.Intersection)) {\n    if (isTuple(type)) {\n      try {\n        const props = getShape(type);\n        return makeResult({\n          name: 'tuple',\n          value: props.map((p) => p.value),\n        });\n      } catch (e) {\n        return makeResult({\n          name: 'object',\n        });\n      }\n\n      // @ts-ignore\n    } else if (checker.isArrayType(type)) {\n      return makeResult({\n        name: 'Array',\n        // @ts-ignore\n        elements: [\n          getDocgenTypeHelper(\n            checker,\n            (type as ExtendedType).typeArguments[0],\n            false,\n            getNextParentIds(parentIds, type),\n          ),\n        ],\n      });\n      // @ts-ignore\n    } else if (type?.symbol?.valueDeclaration?.parameters?.length) {\n      return makeResult({\n        name: 'func',\n        params: getFunctionParams(\n          // @ts-ignore\n          type?.symbol?.valueDeclaration?.parameters,\n          checker,\n          parentIds,\n          type,\n        ),\n        returns: getFunctionReturns(\n          checker.typeToTypeNode(type, type?.symbol?.valueDeclaration),\n          checker,\n          parentIds,\n          type,\n        ),\n      });\n    } else if (\n      // @ts-ignore\n      type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters?.length\n    ) {\n      return makeResult({\n        name: 'func',\n        params: getFunctionParams(\n          // @ts-ignore\n          type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters,\n          checker,\n          parentIds,\n          type,\n        ),\n      });\n    } else {\n      try {\n        const props = getShape(type);\n        return makeResult({\n          name: 'signature',\n          type: {\n            signature: {\n              properties: props,\n            },\n          },\n        });\n      } catch (e) {\n        return makeResult({\n          name: 'object',\n        });\n      }\n    }\n  } else {\n    return makeResult({\n      name: 'object',\n    });\n  }\n}\nclass MyParser extends Parser {\n  getDocgenType(propType: ts.Type): any {\n    const parentIds = [];\n    // @ts-ignore\n    const parentId = propType?.symbol?.parent?.id;\n    if (parentId) {\n      parentIds.push(parentId);\n    }\n    // @ts-ignore\n    const result = getDocgenTypeHelper(this.checker, propType, true, parentIds);\n    return result;\n  }\n\n  // override the builtin method, to avoid the false positive\n  public extractPropsFromTypeIfStatelessComponent(type: ts.Type): ts.Symbol | null {\n    const callSignatures = type.getCallSignatures();\n\n    if (callSignatures.length) {\n      // Could be a stateless component.  Is a function, so the props object we're interested\n      // in is the (only) parameter.\n\n      for (const sig of callSignatures) {\n        const params = sig.getParameters();\n        if (params.length === 0) {\n          continue;\n        }\n\n        // @ts-ignore\n        const returnSymbol = this.checker.getReturnTypeOfSignature(sig);\n        if (!returnSymbol) continue;\n        const symbol = returnSymbol?.symbol;\n        if (!symbol) continue;\n        // @ts-ignore\n        const typeString = this.checker.symbolToString(symbol);\n        if (\n          typeString.startsWith('ReactElement') ||\n          typeString.startsWith('Element') ||\n          typeString.startsWith('RaxElement')\n        ) {\n          const propsParam = params[0];\n          if (propsParam) {\n            return propsParam;\n          }\n        }\n      }\n    }\n\n    return null;\n  }\n}\n\nconst getCompilerOptions = (reactTypePath, originalReactTypePath) => {\n  const options: any = {\n    jsx: ts.JsxEmit.React,\n    module: ts.ModuleKind.CommonJS,\n    target: ts.ScriptTarget.Latest,\n    allowSyntheticDefaultImports: true,\n  };\n  // if (reactTypePath) {\n  //   options.paths = {\n  //     react: [reactTypePath],\n  //   };\n  //   options.exclude = [path.dirname(originalReactTypePath)];\n  //   options.types = [];\n  //   options.skipLibCheck = true;\n  // }\n  return options;\n};\n\ninterface SymbolWithMeta extends ts.Symbol {\n  meta?: {\n    exportName: string;\n    subName?: string;\n  };\n}\n\nfunction getComponentName(exportName, displayName) {\n  if (displayName) {\n    const firstCharCode = displayName.charCodeAt(0);\n    if (firstCharCode >= 65 && firstCharCode <= 90) {\n      return displayName || exportName;\n    }\n  }\n  return exportName;\n}\n\nconst defaultTsConfigPath = path.resolve(__dirname, './tsconfig.json');\n\nexport default function parseTS(filePath: string, args: IParseArgs): ComponentDoc[] {\n  if (!filePath) return [];\n\n  let basePath = args.moduleDir || args.workDir || path.dirname(filePath);\n  let tsConfigPath = findConfig('tsconfig.json', { cwd: basePath }); // path.resolve(basePath, 'tsconfig.json')\n  if (\n    !tsConfigPath ||\n    !existsSync(tsConfigPath) ||\n    (args.accesser === 'online' && tsConfigPath === 'tsconfig.json')\n  ) {\n    tsConfigPath = defaultTsConfigPath;\n  } else {\n    basePath = path.dirname(tsConfigPath);\n  }\n\n  log('ts config path is', tsConfigPath);\n  const { config, error } = ts.readConfigFile(tsConfigPath, (filename) =>\n    readFileSync(filename, 'utf8'));\n\n  if (error !== undefined) {\n    const errorText = `Cannot load custom tsconfig.json from provided path: ${tsConfigPath}, with error code: ${error.code}, message: ${error.messageText}`;\n    throw new Error(errorText);\n  }\n\n  const { options, errors } = ts.parseJsonConfigFileContent(\n    config,\n    ts.sys,\n    basePath,\n    {},\n    tsConfigPath,\n  );\n\n  if (errors && errors.length) {\n    throw errors[0];\n  }\n  log('ts config is', options);\n  // const filePaths = Array.isArray(filePathOrPaths) ? filePathOrPaths : [filePathOrPaths];\n  generateDTS(args);\n  const program = ts.createProgram([filePath], options);\n\n  const parser = new MyParser(program, {});\n\n  const checker = program.getTypeChecker();\n\n  const result = [filePath]\n    .map((fPath) => program.getSourceFile(fPath))\n    .filter((sourceFile) => typeof sourceFile !== 'undefined')\n    .reduce((docs: any[], sourceFile) => {\n      const moduleSymbol = checker.getSymbolAtLocation(sourceFile as ts.Node);\n\n      if (!moduleSymbol) {\n        return docs;\n      }\n\n      const exportSymbols = checker.getExportsOfModule(moduleSymbol);\n\n      for (let index = 0; index < exportSymbols.length; index++) {\n        const sym: SymbolWithMeta = exportSymbols[index];\n        const name = sym.getName();\n        if (blacklistNames.includes(name)) {\n          continue;\n        }\n\n        // polyfill valueDeclaration\n        sym.valueDeclaration =\n          sym.valueDeclaration || (Array.isArray(sym.declarations) && sym.declarations[0]);\n\n        if (!sym.valueDeclaration) {\n          continue;\n        }\n        const info = parser.getComponentInfo(sym, sourceFile);\n        if (info === null) {\n          continue;\n        }\n        const exportName = sym.meta && sym.meta.exportName;\n        const meta = {\n          subName: exportName ? name : '',\n          exportName: exportName || name,\n        };\n        if (docs.find((x) => isEqual(x.meta, meta))) {\n          continue;\n        }\n        docs.push({\n          ...info,\n          meta,\n        });\n        // find sub components\n        if (!!sym.declarations && sym.declarations.length === 0) {\n          continue;\n        }\n\n        const type = checker.getTypeOfSymbolAtLocation(\n          sym,\n          sym.valueDeclaration || sym.declarations[0],\n        );\n        Array.prototype.push.apply(\n          exportSymbols,\n          type.getProperties().map((x: SymbolWithMeta) => {\n            x.meta = { exportName: name };\n            return x;\n          }),\n        );\n      }\n\n      return docs;\n    }, []);\n  const coms = result.reduce((res: any[], info: any) => {\n    if (!info || !info.props || isEmpty(info.props)) return res;\n    const props = Object.keys(info.props).reduce((acc: any[], name) => {\n      // omit aria related properties temporarily\n      if (name.startsWith('aria-')) {\n        return acc;\n      }\n      try {\n        const item: any = transformItem(name, info.props[name]);\n        acc.push(item);\n      } catch (e) {\n        log(e);\n      }\n      return acc;\n    }, []);\n    const exportName = info?.meta?.exportName;\n    res.push({\n      componentName: getComponentName(exportName, info.displayName),\n      props,\n      meta: info.meta || {},\n    });\n    return res;\n  }, []);\n  return coms;\n}\n"
  },
  {
    "path": "modules/material-parser/src/parse/ts/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"jsx\": \"react\",\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"allowSyntheticDefaultImports\": true,\n    \"allowJs\": true\n  },\n  \"include\": [\"**/*\"],\n  \"exclude\": [\"\"]\n}\n"
  },
  {
    "path": "modules/material-parser/src/scan.ts",
    "content": "import {\n  IInternalMaterializeOptions,\n  IMaterializeOnlinePackageAndVersionOptions,\n  IMaterialScanModel,\n} from './types';\nimport { pathExists, lstatSync } from 'fs-extra';\nimport { join, isAbsolute, resolve } from 'path';\nimport { debug } from './core';\nimport { resolvePkgJson } from './utils';\n\nconst log = debug.extend('mat');\n\nexport default async function scan(\n  options: IInternalMaterializeOptions,\n): Promise<IMaterialScanModel> {\n  const model: IMaterialScanModel = {\n    pkgName: '',\n    pkgVersion: '',\n    mainFileAbsolutePath: '',\n    mainFilePath: '',\n  };\n  log('options', options);\n  // 入口文件路径\n  const entryFilePath = options.entry;\n  const stats = lstatSync(entryFilePath);\n  if (\n    (options.accesser === 'local' ||\n      (options.accesser === 'online' &&\n        (options as IMaterializeOnlinePackageAndVersionOptions).name &&\n        options.entry)) &&\n    stats.isFile()\n  ) {\n    if (options.accesser === 'online') {\n      model.useEntry = true;\n    }\n    if (isAbsolute(entryFilePath)) {\n      model.mainFilePath = entryFilePath;\n      model.mainFileAbsolutePath = entryFilePath;\n    } else {\n      model.mainFilePath = entryFilePath;\n      model.mainFileAbsolutePath = resolve(entryFilePath);\n    }\n  }\n  const pkgJsonPath = join(options.root, 'package.json');\n  if (await pathExists(pkgJsonPath)) {\n    const pkgJson = await resolvePkgJson(pkgJsonPath);\n    model.pkgName = pkgJson.name;\n    model.pkgVersion = pkgJson.version;\n    if (pkgJson.module) {\n      const moduleFileAbsolutePath = join(options.root, pkgJson.module);\n      if (await pathExists(moduleFileAbsolutePath)) {\n        model.moduleFilePath = pkgJson.module;\n        model.moduleFileAbsolutePath = moduleFileAbsolutePath;\n      }\n    }\n    model.mainFilePath = model.mainFilePath || pkgJson.main || './index.js';\n    model.mainFileAbsolutePath = model.mainFileAbsolutePath || join(entryFilePath, pkgJson.main);\n    const typingsPathCandidates = [\n      pkgJson.typings,\n      pkgJson.types,\n      './index.d.ts',\n      './lib/index.d.ts',\n    ];\n    for (let i = 0; i < typingsPathCandidates.length; i++) {\n      const typingsFilePath = typingsPathCandidates[i];\n      if (!typingsFilePath) continue;\n      const typingsFileAbsolutePath = join(options.root, typingsFilePath);\n      if (await pathExists(typingsFileAbsolutePath)) {\n        model.typingsFileAbsolutePath = typingsFileAbsolutePath;\n        model.typingsFilePath = typingsFilePath;\n        break;\n      }\n    }\n  }\n\n  log('model', model);\n  return model;\n}\n"
  },
  {
    "path": "modules/material-parser/src/types/Basic.ts",
    "content": "export interface Json {\n  [x: string]: string | number | boolean | Date | Json | JsonArray;\n}\nexport type JsonArray = Array<string | number | boolean | Date | Json | JsonArray>;\nexport type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;\n"
  },
  {
    "path": "modules/material-parser/src/types/ChannelType.ts",
    "content": "/**\n * 物料接入渠道\n */\nexport enum ChannelType {\n  /** 本地 */\n  LOCAL = 'local',\n  /** 在线 */\n  ONLINE = 'online',\n}\n"
  },
  {
    "path": "modules/material-parser/src/types/DSLType.ts",
    "content": "/**\n * DSL类型\n */\nexport type DSLType = 'react' | 'rax';\n"
  },
  {
    "path": "modules/material-parser/src/types/IAccesser.ts",
    "content": "import { ComponentMeta } from '../core';\n\n/**\n * 接入器接口（用于定义物料化组件的接入渠道）\n * @interface IAccesser\n */\nexport interface IAccesser {\n  /**\n   * 接入\n   * @returns {Promise<IMaterialinSchema>}\n   * @memberof IAccesser\n   */\n  access(): Promise<ComponentMeta[]>;\n}\n"
  },
  {
    "path": "modules/material-parser/src/types/IExtensionConfigManifest.ts",
    "content": "import { ComponentMeta } from '../core';\n/**\n * 扩展点：配置 manifest\n * （物料化场景）\n */\nexport type IExtensionConfigManifest = (params: {\n  manifestObj: ComponentMeta; // manifest 配置对象\n  manifestFilePath: string; // manifest 文件默认路径\n}) => Promise<{\n  manifestJSON: string; // manifest 文件内容\n  manifestFilePath: string; // manifest 文件路径\n  manifestObj: ComponentMeta; // manifest 文件对象\n}>;\n"
  },
  {
    "path": "modules/material-parser/src/types/IMaterialParsedModel.ts",
    "content": "import { PropsSection } from '../core';\n/**\n * 对应解析器分析出的一些关键信息\n */\nexport interface IPropType {\n  name: string;\n  type: string;\n  value?: IPropTypes;\n  required: boolean;\n}\n\nexport type IPropTypes = IPropType[];\n\nexport interface IMaterialParsedModel {\n  // filePath: string;\n  componentName: string;\n  props?: PropsSection['props'];\n  meta?: {\n    exportName?: string;\n    subName?: string;\n  };\n}\n"
  },
  {
    "path": "modules/material-parser/src/types/IMaterialScanModel.ts",
    "content": "/**\n * 对应扫描阶段的产物\n */\nexport interface IMaterialScanModel {\n  /** 当前包名 */\n  pkgName: string;\n  /** 当前包版本 */\n  pkgVersion: string;\n  /** 在ts场景下，使用entry */\n  useEntry?: boolean;\n  /** main文件相对路径 */\n  mainFilePath: string;\n  /** module文件相对路径 */\n  moduleFilePath?: string;\n  /** typings文件相对路径 */\n  typingsFilePath?: string;\n  /** main文件绝对路径 */\n  mainFileAbsolutePath: string;\n  /** module文件绝对路径 */\n  moduleFileAbsolutePath?: string;\n  /** typings文件绝对路径 */\n  typingsFileAbsolutePath?: string;\n}\n"
  },
  {
    "path": "modules/material-parser/src/types/IMaterializeOptions.ts",
    "content": "import { Expand } from './Basic';\nimport { DSLType } from './DSLType';\n/**\n * 通用入料配置项\n * @interface IMaterializeCommonOptions\n */\nexport interface IMaterializeCommonOptions {\n  /**\n   * 当 accesser=online 时，配置要使用的 npm client，如：tnpm、cnpm、yarn、npm\n   */\n  npmClient?: string;\n  /**\n   * 当前dsl类型，可选值包括'react' | 'rax'\n   */\n  dslType?: DSLType;\n}\n\n/**\n * 本地入料配置项\n * @interface IMaterializeOnlineOptions\n */\nexport interface IMaterializeLocalOptions extends IMaterializeCommonOptions {\n  /**\n   * 接入渠道\n   * （local：表示本地物料工作台方式接入，online：表示在线 npm 包接入）\n   * @type {('local' | 'online')}\n   * @memberof IMaterializeOptions\n   */\n  accesser: 'local';\n\n  /**\n   * 组件文件(夹)路径或包名\n   * 形如：\n   *  本地路径：/usr/project/src/container/DemoMaterial\n   *  包名：@ali/demo-material@0.0.1\n   */\n  entry: string;\n\n  /**\n   * 组件根目录，当entry为文件路径的时候，可以用root来指定根目录，当entry为文件夹时，root默认为entry\n   * 形如：\n   *  相对路径：./\n   *  绝对路径：/usr/project/src/container/DemoMaterial\n   */\n  root?: string;\n}\n\n/**\n * 在线入料配置项\n * @interface IMaterializeOnlineOptions\n */\nexport interface IMaterializeOnlineCommonOptions {\n  /**\n   * 接入渠道\n   * （local：表示本地物料工作台方式接入，online：表示在线 npm 包接入）\n   * @type {('local' | 'online')}\n   * @memberof IMaterializeOptions\n   */\n  accesser: 'online';\n  /**\n   * 临时工作目录，用来存放下载的npm包，可为绝对路径或相对路径\n   */\n  tempDir?: string;\n}\n\n/**\n * 只通过entry指定包名&版本号，无需内部路径\n */\nexport interface IMaterializeOnlineEntryOptions {\n  /**\n   * npm包名&版本号，此时无需指定内部路径，会从package.json自动解析\n   * 形如：\n   *   包名&版本号：@ali/demo-material@0.0.1\n   */\n  entry: string;\n}\n\nexport interface IMaterializeOnlinePackageAndVersionOptions {\n  /**\n   * npm包内部相对路径\n   * 形如：\n   *   相对路径：lib/index.js\n   */\n  entry?: string;\n\n  /**\n   * npm包名\n   * 形如:\n   *   react-color\n   */\n  name: string;\n\n  /**\n   * npm包版本号\n   * 形如:\n   *   latest/1.0.0/1.x.0\n   * @default latest\n   */\n  version?: string;\n}\n\nexport type IMaterializeOnlineOptions = Expand<\n  IMaterializeCommonOptions &\n    IMaterializeOnlineCommonOptions &\n    (IMaterializeOnlineEntryOptions | IMaterializeOnlinePackageAndVersionOptions)\n>;\n/**\n * 入料配置项\n * @interface IMaterializeOptions\n */\nexport type IMaterializeOptions = Expand<IMaterializeLocalOptions | IMaterializeOnlineOptions>;\n\nexport type IInternalMaterializeOptions = Expand<\n  IMaterializeOptions & {\n    root: string;\n  }\n>;\n"
  },
  {
    "path": "modules/material-parser/src/types/Meta.ts",
    "content": "import { Path } from 'ast-types';\n\nexport interface IFileMeta {\n  src: string;\n  path: string;\n  exports: IDefinitionMeta[];\n}\n\nexport interface IDefinitionMeta {\n  subDefinitions: IDefinitionMeta[];\n  nodePath: typeof Path;\n  exportName: string;\n  id: string;\n}\n"
  },
  {
    "path": "modules/material-parser/src/types/index.ts",
    "content": "export * from './ChannelType';\nexport * from './DSLType';\nexport * from './IAccesser';\nexport * from './IExtensionConfigManifest';\nexport * from './IMaterializeOptions';\nexport * from './IMaterialScanModel';\nexport * from './IMaterialParsedModel';\nexport * from './Basic';\n"
  },
  {
    "path": "modules/material-parser/src/utils.ts",
    "content": "import { pathExists, readFileSync, writeFile } from 'fs-extra';\nimport { isPlainObject } from 'lodash';\nimport originalSafeEval from 'safe-eval';\nimport * as path from 'path';\nimport spawn from 'cross-spawn-promise';\nimport { DSLType } from './types';\n\nexport async function isNPMInstalled(args: {\n  workDir: string;\n  moduleDir: string;\n  npmClient?: string;\n}) {\n  return pathExists(path.join(args.workDir, 'node_modules'));\n}\n\nexport async function isNPMModuleInstalled(\n  args: { workDir: string; moduleDir: string; npmClient?: string },\n  name: string,\n) {\n  const modulePkgJsonPath = path.resolve(args.workDir, 'node_modules', name, 'package.json');\n  return pathExists(modulePkgJsonPath);\n}\n\nexport async function install(args: { workDir: string; moduleDir: string; npmClient?: string }) {\n  if (await isNPMInstalled(args)) return;\n  const { workDir, npmClient = 'tnpm' } = args;\n  try {\n    await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);\n  } catch (e) {\n    // TODO\n  }\n}\n\nexport async function installModule(\n  args: { workDir: string; moduleDir: string; npmClient?: string },\n  name: string,\n) {\n  if (await isNPMModuleInstalled(args, name)) return;\n  const { workDir, npmClient = 'tnpm' } = args;\n  try {\n    await spawn(npmClient, ['i', name], { stdio: 'inherit', cwd: workDir } as any);\n  } catch (e) {\n    // TODO\n  }\n}\n\nexport function installTypeDTS(args: {\n  workDir: string;\n  moduleDir: string;\n  npmClient?: string;\n  dslType?: DSLType;\n}) {\n  return installModule(args, `@types/${args.dslType || 'react'}`);\n}\n\nexport async function installTypeScript(args: {\n  workDir: string;\n  moduleDir: string;\n  npmClient?: string;\n}) {\n  if (await pathExists(path.join(args.workDir, 'node_modules', '.bin', 'tsc'))) return;\n  const { workDir, npmClient = 'tnpm' } = args;\n  await spawn(npmClient, ['i', 'typescript'], { stdio: 'inherit', cwd: workDir } as any);\n}\n\nexport async function installPeerAndDevDeps(args: {\n  workDir: string;\n  moduleDir: string;\n  npmClient?: string;\n}) {\n  const { workDir, moduleDir, npmClient = 'tnpm' } = args;\n  const modulePkgJsonPath = path.resolve(moduleDir, 'package.json');\n  if (!(await pathExists(modulePkgJsonPath))) {\n    return;\n  }\n  const pkgJsonPath = path.resolve(workDir, 'package.json');\n  if (!(await pathExists(pkgJsonPath))) {\n    return;\n  }\n  const modulePkgJson = await resolvePkgJson(modulePkgJsonPath);\n  const pkgJson = await resolvePkgJson(pkgJsonPath);\n  const { peerDependencies = {}, devDependencies = {} } = modulePkgJson;\n  pkgJson.dependencies = pkgJson.dependencies || {};\n  pkgJson.dependencies = {\n    ...pkgJson.dependencies,\n    ...peerDependencies,\n    ...devDependencies,\n  };\n  await writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));\n  await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);\n}\n\nexport async function syncTypeModules(args: {\n  workDir: string;\n  moduleDir: string;\n  npmClient?: string;\n}) {\n  const { workDir, moduleDir, npmClient = 'tnpm' } = args;\n  const pkgJsonPath = path.resolve(moduleDir, 'package.json');\n  if (!(await pathExists(pkgJsonPath))) {\n    return;\n  }\n  await installModule(args, 'typesync');\n  await spawn(npmClient.replace('m', 'x'), ['typesync'], { stdio: 'inherit', cwd: workDir } as any);\n}\n\nexport async function resolvePkgJson(pkgJsonPath: string): Promise<{ [k: string]: any }> {\n  const content = await loadFile(pkgJsonPath);\n  const json = JSON.parse(content);\n  return json;\n}\n\nexport function loadFile(filePath: string): string {\n  const content: string | Buffer = readFileSync(filePath);\n  if (typeof content === 'string') {\n    return content;\n  }\n  return content.toString();\n}\n\nexport function isPrimitive(val) {\n  return !['object', 'function'].includes(typeof val) || val === null;\n}\n\nexport function isEvaluable(value) {\n  if (isPrimitive(value)) return true;\n  if (Array.isArray(value)) {\n    return value.every(isEvaluable);\n  } else if (isPlainObject(value)) {\n    return Object.keys(value).every((key) => isEvaluable(value[key]));\n  }\n  return false;\n}\n\nexport function safeEval(value: any) {\n  if (typeof value === 'string') return originalSafeEval(value);\n  return value;\n}\n"
  },
  {
    "path": "modules/material-parser/src/validate/index.ts",
    "content": "import Ajv from 'ajv';\nimport { Json } from '../types/Basic';\nimport schema from './schema.json';\n\nconst ajv = new Ajv({ jsonPointers: true });\nconst validate = ajv.compile(schema);\n\nexport default function validateSchema(json: Json) {\n  if (validate(json) === false) {\n    throw new Error(JSON.stringify(validate.errors, null, 2));\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "modules/material-parser/src/validate/schema.json",
    "content": "{\n  \"$id\": \"@ali/low-code-component-protocol-schema\",\n  \"description\": \"json schema for low code component protocol\",\n  \"allOf\": [\n    {\n      \"$ref\": \"#/definitions/BasicSection\"\n    },\n    {\n      \"$ref\": \"#/definitions/PropsSection\"\n    },\n    {\n      \"$ref\": \"#/definitions/ConfigureSection\"\n    }\n  ],\n  \"definitions\": {\n    \"BasicSection\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"componentName\": {\n          \"type\": \"string\"\n        },\n        \"title\": {\n          \"type\": \"string\"\n        },\n        \"description\": {\n          \"type\": \"string\"\n        },\n        \"docUrl\": {\n          \"type\": \"string\"\n        },\n        \"screenshot\": {\n          \"type\": \"string\"\n        },\n        \"icon\": {\n          \"type\": \"string\"\n        },\n        \"tags\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"devMode\": {\n          \"enum\": [\n            \"proCode\",\n            \"lowCode\"\n          ]\n        },\n        \"npm\": {\n          \"$ref\": \"#/definitions/Npm\"\n        }\n      },\n      \"required\": [\n        \"componentName\",\n        \"title\",\n        \"npm\"\n      ]\n    },\n    \"PropsSection\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"props\"\n      ],\n      \"properties\": {\n        \"props\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\"\n              },\n              \"propType\": {\n                \"$ref\": \"#/definitions/PropType\"\n              },\n              \"description\": {\n                \"type\": \"string\"\n              },\n              \"defaultValue\": {}\n            },\n            \"required\": [\n              \"name\",\n              \"propType\"\n            ]\n          }\n        }\n      }\n    },\n    \"ConfigureSection\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"configure\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"props\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/definitions/ConfigureProp\"\n              }\n            },\n            \"styles\": {\n              \"type\": \"object\",\n              \"properties\": {}\n            },\n            \"events\": {\n              \"type\": \"object\",\n              \"properties\": {}\n            },\n            \"component\": {\n              \"$ref\": \"#/definitions/ConfigureComponent\"\n            }\n          }\n        }\n      }\n    },\n    \"Npm\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"package\": {\n          \"type\": \"string\"\n        },\n        \"exportName\": {\n          \"type\": \"string\"\n        },\n        \"subName\": {\n          \"type\": \"string\"\n        },\n        \"main\": {\n          \"type\": \"string\"\n        },\n        \"destructuring\": {\n          \"type\": \"boolean\"\n        },\n        \"version\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"package\",\n        \"exportName\",\n        \"subName\",\n        \"main\",\n        \"destructuring\",\n        \"version\"\n      ]\n    },\n    \"PropType\": {\n      \"oneOf\": [\n        {\n          \"$ref\": \"#/definitions/BasicType\"\n        },\n        {\n          \"$ref\": \"#/definitions/RequiredType\"\n        },\n        {\n          \"$ref\": \"#/definitions/ComplexType\"\n        }\n      ]\n    },\n    \"BasicType\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"array\",\n        \"bool\",\n        \"func\",\n        \"number\",\n        \"object\",\n        \"string\",\n        \"node\",\n        \"element\",\n        \"any\"\n      ]\n    },\n    \"RequiredType\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"$ref\": \"#/definitions/BasicType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"required\": [\n        \"type\"\n      ]\n    },\n    \"ComplexType\": {\n      \"oneOf\": [\n        {\n          \"$ref\": \"#/definitions/OneOf\"\n        },\n        {\n          \"$ref\": \"#/definitions/OneOfType\"\n        },\n        {\n          \"$ref\": \"#/definitions/ArrayOf\"\n        },\n        {\n          \"$ref\": \"#/definitions/ObjectOf\"\n        },\n        {\n          \"$ref\": \"#/definitions/Shape\"\n        },\n        {\n          \"$ref\": \"#/definitions/Exact\"\n        }\n      ]\n    },\n    \"OneOf\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"oneOf\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"boolean\"\n              }\n            ]\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"OneOfType\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"oneOfType\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/PropType\"\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ArrayOf\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"arrayOf\"\n          ]\n        },\n        \"value\": {\n          \"$ref\": \"#/definitions/PropType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ObjectOf\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"objectOf\"\n          ]\n        },\n        \"value\": {\n          \"$ref\": \"#/definitions/PropType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"Shape\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"shape\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\"\n              },\n              \"propType\": {\n                \"$ref\": \"#/definitions/PropType\"\n              }\n            },\n            \"additionalProperties\": false\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ShapeItem\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"name\",\n        \"propType\"\n      ],\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"propType\": {\n          \"$ref\": \"#/definitions/PropType\"\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      },\n      \"additionalProperties\": false\n    },\n    \"Exact\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"value\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"exact\"\n          ]\n        },\n        \"value\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\"\n              },\n              \"propType\": {\n                \"$ref\": \"#/definitions/PropType\"\n              }\n            },\n            \"additionalProperties\": false\n          }\n        },\n        \"isRequired\": {\n          \"type\": \"boolean\"\n        }\n      }\n    },\n    \"ConfigureProp\": {\n      \"type\": \"object\",\n      \"allOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"title\": {\n              \"type\": \"string\"\n            },\n            \"extraProps\": {\n              \"type\": \"object\",\n              \"properties\": {}\n            }\n          }\n        },\n        {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/definitions/ConfigureFieldProp\"\n            },\n            {\n              \"$ref\": \"#/definitions/ConfigureGroupProp\"\n            }\n          ]\n        }\n      ]\n    },\n    \"ConfigureFieldProp\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"field\"\n          ]\n        },\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"setter\": {\n          \"$ref\": \"#/definitions/ConfigureFieldSetter\"\n        }\n      }\n    },\n    \"ConfigureFieldSetter\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"componentName\"\n      ],\n      \"properties\": {\n        \"componentName\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"List\",\n            \"Object\",\n            \"Function\",\n            \"Node\",\n            \"Mixin\",\n            \"Expression\",\n            \"Switch\",\n            \"Number\",\n            \"Input\",\n            \"TextArea\",\n            \"Date\",\n            \"DateYear\",\n            \"DateMonth\",\n            \"DateRange\",\n            \"ColorPicker\",\n            \"CodeEditor\",\n            \"Select\",\n            \"RadioGroup\"\n          ]\n        },\n        \"props\": {\n          \"type\": \"object\",\n          \"properties\": {}\n        }\n      }\n    },\n    \"ConfigureGroupProp\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"type\",\n        \"items\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"group\"\n          ]\n        },\n        \"items\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/ConfigureProp\"\n          }\n        }\n      }\n    },\n    \"ConfigureComponent\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"isContainer\": {\n          \"type\": \"boolean\"\n        },\n        \"isModal\": {\n          \"type\": \"boolean\"\n        },\n        \"descriptor\": {\n          \"type\": \"string\"\n        },\n        \"nestingRule\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"childWhitelist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"parentWhitelist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"descendantBlacklist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"ancestorWhitelist\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          }\n        },\n        \"isNullNode\": {\n          \"type\": \"boolean\"\n        },\n        \"isLayout\": {\n          \"type\": \"boolean\"\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "modules/material-parser/test/__snapshots__/dynamic.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`materialize dynamic component by online 1`] = `\nArray [\n  Object {\n    \"componentName\": \"BizAnchor\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"@alifd/biz-anchor\",\n      \"subName\": \"\",\n      \"version\": \"1.1.7\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": false,\n        \"name\": \"noHash\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"@alifd/biz-anchor\",\n  },\n]\n`;\n"
  },
  {
    "path": "modules/material-parser/test/__snapshots__/index.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`d.ts component by local 1`] = `\nArray [\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"src/index.jsx\",\n      \"package\": \"dts-component\",\n      \"subName\": \"\",\n      \"version\": \"1.2.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"description\": \"是否是财鲸主站，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"isMainSite\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"财鲸主站的 app 名称，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"mainSiteAppName\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"description\": \"主站中文名，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"mainSiteName\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"description\": \"主站英文名，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"mainSiteNameEn\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"description\": \"主站链接，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"mainSiteLink\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"description\": \"子站点的应用名，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"subSiteAppName\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n      Object {\n        \"description\": \"子站点的名称，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"subSiteName\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n      Object {\n        \"description\": \"子站点的英文名称，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"subSiteNameEn\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n      Object {\n        \"description\": \"子站点的链接，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"subSiteLink\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n      Object {\n        \"description\": \"子站访问相关接口时，属于buc 跨域请求，需要把 ssoTicket 带上，该字段由后端 vm 中吐出在 window.appConfig 中\",\n        \"name\": \"ssoTicket\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n      Object {\n        \"description\": \"是否使用 ak/sk 方案（用于登录）\",\n        \"name\": \"aksk\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"是否显示左侧导航\",\n        \"name\": \"sidebarVisible\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"是否显示顶部菜单栏\",\n        \"name\": \"topbarVisible\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"是否开启全屏\",\n        \"name\": \"isFullScreen\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"当前选中的导航 key\",\n        \"name\": \"navSelectedKeys\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            Object {\n              \"type\": \"arrayOf\",\n              \"value\": \"string\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"description\": \"history 对象\",\n        \"name\": \"history\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"左侧子导航数组\",\n        \"name\": \"nav\",\n        \"propType\": Object {\n          \"type\": \"arrayOf\",\n          \"value\": \"object\",\n        },\n      },\n      Object {\n        \"description\": \"Next Nav 组件本身的配置\",\n        \"name\": \"nextNavConfig\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"description\": \"切换语言的 Url\",\n        \"name\": \"setLanguageUrl\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"description\": \"顶部控件的扩展区渲染内容\",\n        \"name\": \"extra\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"description\": \"顶部导航站点名称后面的快速入口区域自定义渲染\",\n        \"name\": \"quickEntry\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"description\": \"水印配置项\",\n        \"name\": \"waterMarkOptions\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"description\": \"是否需要默认的登出行为\",\n        \"name\": \"needDefaultLogout\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"点击登出按钮后的回调函数\",\n        \"name\": \"onLogoutClick\",\n        \"propType\": \"func\",\n      },\n      Object {\n        \"description\": \"侧边栏收起展开回调函数\",\n        \"name\": \"onToggleMenu\",\n        \"propType\": \"func\",\n      },\n      Object {\n        \"description\": \"logo 的 style 覆盖\",\n        \"name\": \"logoStyle\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"description\": \"logo 点击事件，传入覆盖\",\n        \"name\": \"onLogoClick\",\n        \"propType\": \"func\",\n      },\n      Object {\n        \"description\": \"切换语言自定义事件\",\n        \"name\": \"onToggleLang\",\n        \"propType\": Object {\n          \"params\": Array [\n            Object {\n              \"name\": \"nextConfig\",\n              \"propType\": \"object\",\n            },\n            Object {\n              \"name\": \"appName\",\n              \"propType\": \"any\",\n            },\n          ],\n          \"raw\": \"(nextConfig: Record<string, any>, appName: any) => void\",\n          \"type\": \"func\",\n        },\n      },\n      Object {\n        \"description\": \"语言切换器显示切换\",\n        \"name\": \"langVisible\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"打开启用浏览器缩放警告\",\n        \"name\": \"scaleWarning\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"This event is fired whenever the application navigates to a new page.\",\n        \"name\": \"test\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"dts-component\",\n  },\n]\n`;\n\nexports[`materialize multiple exported component by local 1`] = `\nArray [\n  Object {\n    \"componentName\": \"AIMakeBlank\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"AIMakeBlank\",\n      \"main\": \"es/index.js\",\n      \"package\": \"multiple-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"styleBoxModel\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleLayout\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleBackground\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleFlexLayout\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"id\",\n        \"propType\": \"string\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"multiple-exported-component\",\n  },\n  Object {\n    \"componentName\": \"AIMakeIcon\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"AIMakeIcon\",\n      \"main\": \"es/index.js\",\n      \"package\": \"multiple-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"className\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"iconClassName\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"styleBoxModel\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleText\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleBackground\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"multiple-exported-component\",\n  },\n  Object {\n    \"componentName\": \"AIMakeImage\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"AIMakeImage\",\n      \"main\": \"es/index.js\",\n      \"package\": \"multiple-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"styleBoxModel\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"multiple-exported-component\",\n  },\n  Object {\n    \"componentName\": \"AIMakeLink\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"AIMakeLink\",\n      \"main\": \"es/index.js\",\n      \"package\": \"multiple-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"styleBoxModel\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleText\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleLayout\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleBackground\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"multiple-exported-component\",\n  },\n  Object {\n    \"componentName\": \"AIMakePlaceholder\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"AIMakePlaceholder\",\n      \"main\": \"es/index.js\",\n      \"package\": \"multiple-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"styleBoxModel\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleLayout\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"multiple-exported-component\",\n  },\n  Object {\n    \"componentName\": \"AIMakeText\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"AIMakeText\",\n      \"main\": \"es/index.js\",\n      \"package\": \"multiple-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"type\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"styleBoxModel\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleText\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleLayout\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"styleBackground\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"multiple-exported-component\",\n  },\n  Object {\n    \"componentName\": \"Root\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"Root\",\n      \"main\": \"es/index.js\",\n      \"package\": \"multiple-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"multiple-exported-component\",\n  },\n]\n`;\n\nexports[`materialize single exported component by local 1`] = `\nArray [\n  Object {\n    \"componentName\": \"Demo\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"src/index.js\",\n      \"package\": \"single-exported-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"optionalArray\",\n        \"propType\": \"array\",\n      },\n      Object {\n        \"name\": \"optionalBool\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"description\": \"desc\",\n        \"name\": \"optionalFunc\",\n        \"propType\": Object {\n          \"params\": Array [\n            Object {\n              \"description\": \"The title of the book.\",\n              \"name\": \"title\",\n              \"propType\": \"string\",\n            },\n            Object {\n              \"description\": \"The author of the book.\",\n              \"name\": \"author\",\n              \"propType\": \"string\",\n            },\n          ],\n          \"raw\": \"(title: string, author: string) => any\",\n          \"returns\": Object {\n            \"propType\": \"any\",\n          },\n          \"type\": \"func\",\n        },\n      },\n      Object {\n        \"defaultValue\": 123,\n        \"name\": \"optionalNumber\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"name\": \"optionalObject\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"optionalString\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"optionalSymbol\",\n        \"propType\": \"symbol\",\n      },\n      Object {\n        \"name\": \"optionalNode\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"optionalElement\",\n        \"propType\": \"element\",\n      },\n      Object {\n        \"name\": \"optionalElementType\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"optionalMessage\",\n        \"propType\": Object {\n          \"type\": \"instanceOf\",\n          \"value\": \"Demo\",\n        },\n      },\n      Object {\n        \"name\": \"optionalEnum\",\n        \"propType\": Object {\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"News\",\n            \"Photos\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"optionalUnion\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n            Object {\n              \"type\": \"instanceOf\",\n              \"value\": \"Demo\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"optionalObjectOf\",\n        \"propType\": Object {\n          \"type\": \"objectOf\",\n          \"value\": \"number\",\n        },\n      },\n      Object {\n        \"name\": \"optionalObjectWithShape\",\n        \"propType\": Object {\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"optionalProperty\",\n              \"propType\": \"string\",\n            },\n            Object {\n              \"name\": \"requiredProperty\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"number\",\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"optionalObjectWithShape2\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"optionalProperty\",\n              \"propType\": \"string\",\n            },\n            Object {\n              \"name\": \"requiredProperty\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"number\",\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"optionalObjectWithStrictShape\",\n        \"propType\": Object {\n          \"type\": \"exact\",\n          \"value\": Array [\n            Object {\n              \"name\": \"optionalProperty\",\n              \"propType\": \"string\",\n            },\n            Object {\n              \"name\": \"requiredProperty\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"number\",\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"requiredFunc\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"func\",\n        },\n      },\n      Object {\n        \"name\": \"requiredAny\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"any\",\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"single-exported-component\",\n  },\n]\n`;\n\nexports[`rax component by local 1`] = `\nArray [\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"src/index.tsx\",\n      \"package\": \"@ali/chaoshi-meta-example\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"a\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n      Object {\n        \"name\": \"ref\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"instance\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(instance: unknown) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"T\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"any\",\n                  },\n                },\n                Object {\n                  \"name\": \"current\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"object\",\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"key\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"@ali/chaoshi-meta-example\",\n  },\n  Object {\n    \"componentName\": \"Price\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"Price\",\n      \"main\": \"src/index.tsx\",\n      \"package\": \"@ali/chaoshi-meta-example\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"color\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"fontSize\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"name\": \"symbolSize\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"name\": \"decimalSize\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"name\": \"value\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"autoScale\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"name\": \"className\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"rest\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"@ali/chaoshi-meta-example\",\n  },\n  Object {\n    \"componentName\": \"Title\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"Title\",\n      \"main\": \"src/index.tsx\",\n      \"package\": \"@ali/chaoshi-meta-example\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"type\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"small\",\n            \"medium\",\n            \"large\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"doubleLine\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"name\": \"className\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"rest\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"@ali/chaoshi-meta-example\",\n  },\n]\n`;\n\nexports[`transpiled component by local 1`] = `\nArray [\n  Object {\n    \"componentName\": \"MyComponent\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"\\\\\"default\\\\\"\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"transpiled-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"description\": \"Description of prop \\\\\"foo\\\\\".\",\n        \"name\": \"foo\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"number\",\n        },\n      },\n      Object {\n        \"defaultValue\": 21,\n        \"description\": \"Description of prop \\\\\"bar\\\\\" (a custom validation function).\",\n        \"name\": \"bar\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"baz\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"number\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"optionalObjectWithShape2\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"optionalProperty\",\n              \"propType\": \"string\",\n            },\n            Object {\n              \"name\": \"requiredProperty\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"number\",\n              },\n            },\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"transpiled-component\",\n  },\n]\n`;\n\nexports[`ts component 2 by local 1`] = `\nArray [\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"src/index.tsx\",\n      \"package\": \"@alife/empty\",\n      \"subName\": \"\",\n      \"version\": \"1.0.1\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"className\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"imageStyle\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"image\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"description\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"type\",\n        \"propType\": Object {\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"default\",\n            \"custom\",\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"@alife/empty\",\n  },\n]\n`;\n\nexports[`ts component by local 1`] = `\nArray [\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"src/index.tsx\",\n      \"package\": \"ts-component\",\n      \"subName\": \"\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"error\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"params\": Array [\n            Object {\n              \"name\": \"a\",\n              \"propType\": \"string\",\n            },\n          ],\n          \"raw\": \"(a: string) => number\",\n          \"returns\": Object {\n            \"propType\": \"number\",\n          },\n          \"type\": \"func\",\n        },\n      },\n      Object {\n        \"name\": \"void\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"void\",\n        },\n      },\n      Object {\n        \"name\": \"object\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"trigger\",\n        \"propType\": Object {\n          \"type\": \"arrayOf\",\n          \"value\": Object {\n            \"type\": \"oneOf\",\n            \"value\": Array [\n              \"click\",\n              \"hover\",\n              \"contextMenu\",\n            ],\n          },\n        },\n      },\n      Object {\n        \"name\": \"str\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"num\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"number\",\n        },\n      },\n      Object {\n        \"name\": \"any\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"any\",\n        },\n      },\n      Object {\n        \"name\": \"bool\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"bool\",\n        },\n      },\n      Object {\n        \"name\": \"tuple\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"tuple\",\n          \"value\": Array [\n            Object {\n              \"isRequired\": true,\n              \"type\": \"number\",\n            },\n            Object {\n              \"isRequired\": true,\n              \"type\": \"string\",\n            },\n            Object {\n              \"isRequired\": true,\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                true,\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"enum\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"red\",\n            \"yellow\",\n            \"green\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"arr\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"arrayOf\",\n          \"value\": \"number\",\n        },\n      },\n      Object {\n        \"name\": \"halfEmptyObj\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"fun\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"a\",\n                    \"propType\": Object {\n                      \"type\": \"arrayOf\",\n                      \"value\": \"string\",\n                    },\n                  },\n                ],\n                \"raw\": \"(a: string[]) => void\",\n                \"returns\": Object {\n                  \"propType\": \"number\",\n                },\n                \"type\": \"func\",\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"emptyObj\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"func\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"params\": Array [\n            Object {\n              \"name\": \"arg\",\n              \"propType\": \"string\",\n            },\n          ],\n          \"raw\": \"(arg: string) => number\",\n          \"returns\": Object {\n            \"propType\": \"number\",\n          },\n          \"type\": \"func\",\n        },\n      },\n      Object {\n        \"name\": \"funcs\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"n\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"raw\": \"() => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"a\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"arg\",\n                    \"propType\": \"string\",\n                  },\n                  Object {\n                    \"name\": \"num\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(arg: string, num: number) => void\",\n                \"returns\": Object {\n                  \"propType\": \"number\",\n                },\n                \"type\": \"func\",\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"fuzzy\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"number\",\n            \"bool\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"a\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"any\",\n                  },\n                },\n                Object {\n                  \"name\": \"sa\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"arrayOf\",\n                    \"value\": \"string\",\n                  },\n                },\n              ],\n            },\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"number\",\n                \"object\",\n                \"test\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"oneOf\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"bool\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"s\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"string\",\n                  },\n                },\n                Object {\n                  \"name\": \"n\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"number\",\n                  },\n                },\n              ],\n            },\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"test\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"refFunc\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"params\": Array [\n            Object {\n              \"name\": \"p\",\n              \"propType\": \"object\",\n            },\n          ],\n          \"raw\": \"(p: Props) => void\",\n          \"returns\": Object {\n            \"propType\": \"number\",\n          },\n          \"type\": \"func\",\n        },\n      },\n      Object {\n        \"name\": \"elementOrOther\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"element\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"a\",\n                  \"propType\": \"string\",\n                },\n              ],\n              \"raw\": \"Func\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"obj\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"a\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"number\",\n              },\n            },\n            Object {\n              \"name\": \"arrOfStr\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"arrayOf\",\n                \"value\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"arrOfObj\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"arrayOf\",\n                \"value\": Object {\n                  \"type\": \"shape\",\n                  \"value\": Array [\n                    Object {\n                      \"name\": \"s\",\n                      \"propType\": Object {\n                        \"isRequired\": true,\n                        \"type\": \"string\",\n                      },\n                    },\n                    Object {\n                      \"name\": \"n\",\n                      \"propType\": Object {\n                        \"isRequired\": true,\n                        \"type\": \"number\",\n                      },\n                    },\n                  ],\n                },\n              },\n            },\n            Object {\n              \"name\": \"func\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"func\",\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"objOf\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"objectOf\",\n          \"value\": \"number\",\n        },\n      },\n      Object {\n        \"name\": \"exact\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"a\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"number\",\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"node\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"element\",\n        \"propType\": \"element\",\n      },\n      Object {\n        \"name\": \"elementType\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"symbol\",\n                \"object\",\n                \"html\",\n                \"loading\",\n                \"a\",\n                \"abbr\",\n                \"address\",\n                \"area\",\n                \"article\",\n                \"aside\",\n                \"audio\",\n                \"b\",\n                \"base\",\n                \"bdi\",\n                \"bdo\",\n                \"big\",\n                \"blockquote\",\n                \"body\",\n                \"br\",\n                \"button\",\n                \"canvas\",\n                \"caption\",\n                \"cite\",\n                \"code\",\n                \"col\",\n                \"colgroup\",\n                \"data\",\n                \"datalist\",\n                \"dd\",\n                \"del\",\n                \"details\",\n                \"dfn\",\n                \"dialog\",\n                \"div\",\n                \"dl\",\n                \"dt\",\n                \"em\",\n                \"embed\",\n                \"fieldset\",\n                \"figcaption\",\n                \"figure\",\n                \"footer\",\n                \"form\",\n                \"h1\",\n                \"h2\",\n                \"h3\",\n                \"h4\",\n                \"h5\",\n                \"h6\",\n                \"head\",\n                \"header\",\n                \"hgroup\",\n                \"hr\",\n                \"i\",\n                \"iframe\",\n                \"img\",\n                \"input\",\n                \"ins\",\n                \"kbd\",\n                \"keygen\",\n                \"label\",\n                \"legend\",\n                \"li\",\n                \"link\",\n                \"main\",\n                \"map\",\n                \"mark\",\n                \"menu\",\n                \"menuitem\",\n                \"meta\",\n                \"meter\",\n                \"nav\",\n                \"noindex\",\n                \"noscript\",\n                \"ol\",\n                \"optgroup\",\n                \"option\",\n                \"output\",\n                \"p\",\n                \"param\",\n                \"picture\",\n                \"pre\",\n                \"progress\",\n                \"q\",\n                \"rp\",\n                \"rt\",\n                \"ruby\",\n                \"s\",\n                \"samp\",\n                \"script\",\n                \"section\",\n                \"select\",\n                \"small\",\n                \"source\",\n                \"span\",\n                \"strong\",\n                \"style\",\n                \"sub\",\n                \"summary\",\n                \"sup\",\n                \"table\",\n                \"tbody\",\n                \"td\",\n                \"textarea\",\n                \"tfoot\",\n                \"th\",\n                \"thead\",\n                \"time\",\n                \"title\",\n                \"tr\",\n                \"track\",\n                \"u\",\n                \"ul\",\n                \"var\",\n                \"video\",\n                \"wbr\",\n                \"webview\",\n                \"svg\",\n                \"animate\",\n                \"animateMotion\",\n                \"animateTransform\",\n                \"circle\",\n                \"clipPath\",\n                \"defs\",\n                \"desc\",\n                \"ellipse\",\n                \"feBlend\",\n                \"feColorMatrix\",\n                \"feComponentTransfer\",\n                \"feComposite\",\n                \"feConvolveMatrix\",\n                \"feDiffuseLighting\",\n                \"feDisplacementMap\",\n                \"feDistantLight\",\n                \"feDropShadow\",\n                \"feFlood\",\n                \"feFuncA\",\n                \"feFuncB\",\n                \"feFuncG\",\n                \"feFuncR\",\n                \"feGaussianBlur\",\n                \"feImage\",\n                \"feMerge\",\n                \"feMergeNode\",\n                \"feMorphology\",\n                \"feOffset\",\n                \"fePointLight\",\n                \"feSpecularLighting\",\n                \"feSpotLight\",\n                \"feTile\",\n                \"feTurbulence\",\n                \"filter\",\n                \"foreignObject\",\n                \"g\",\n                \"image\",\n                \"line\",\n                \"linearGradient\",\n                \"marker\",\n                \"mask\",\n                \"metadata\",\n                \"mpath\",\n                \"path\",\n                \"pattern\",\n                \"polygon\",\n                \"polyline\",\n                \"radialGradient\",\n                \"rect\",\n                \"stop\",\n                \"switch\",\n                \"text\",\n                \"textPath\",\n                \"tspan\",\n                \"use\",\n                \"view\",\n                \"list\",\n                \"cell\",\n                \"refresh\",\n                \"recycle-list\",\n                \"scroller\",\n                \"slider\",\n                \"indicator\",\n                \"waterfall\",\n                \"web\",\n                \"richtext\",\n                \"slot\",\n                \"swiper\",\n                \"swiper-item\",\n                \"scroll-view\",\n                \"cover-view\",\n                \"cover-image\",\n                \"camera\",\n                \"movable-view\",\n                \"movable-area\",\n                \"match-media\",\n                \"icon\",\n                \"rich-text\",\n                \"radio\",\n                \"radio-group\",\n                \"picker-view\",\n                \"picker\",\n                \"navigator\",\n                \"web-view\",\n                \"lifestyle\",\n                \"contact-button\",\n                \"aria-component\",\n                \"functional-page-navigator\",\n                \"live-player\",\n                \"live-pusher\",\n                \"ad\",\n                \"ad-custom\",\n                \"open-data\",\n                \"voip-room\",\n                \"page-meta\",\n                \"picker-view-column\",\n                \"official-account\",\n                \"navigation-bar\",\n                \"template\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"union\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"a\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"string\",\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"func2\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"params\": Array [\n            Object {\n              \"name\": \"a\",\n              \"propType\": \"string\",\n            },\n          ],\n          \"raw\": \"Func\",\n          \"type\": \"func\",\n        },\n      },\n      Object {\n        \"name\": \"html\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"object\",\n        },\n      },\n      Object {\n        \"name\": \"loading\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"bool\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"delay\",\n                  \"propType\": \"number\",\n                },\n              ],\n            },\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"ts-component\",\n  },\n  Object {\n    \"componentName\": \"SubModule\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"src/index.tsx\",\n      \"package\": \"ts-component\",\n      \"subName\": \"SubModule\",\n      \"version\": \"1.0.0\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"name\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"string\",\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"ts-component\",\n  },\n]\n`;\n\nexports[`without display name by local 1`] = `Array []`;\n"
  },
  {
    "path": "modules/material-parser/test/__snapshots__/online.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`materialize mc-hello by online 1`] = `\nArray [\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"mc-hello\",\n      \"subName\": \"\",\n      \"version\": \"1.0.1\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"color\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"name\": \"background\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"defaultValue\": false,\n        \"name\": \"round\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"defaultValue\": 200,\n        \"name\": \"width\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"defaultValue\": 40,\n        \"name\": \"height\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"name\": \"children\",\n        \"propType\": \"node\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"mc-hello\",\n  },\n]\n`;\n\nexports[`materialize online rax module by path & specify workDir 1`] = `\nArray [\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"es/common/index.d.ts\",\n      \"package\": \"rax-view\",\n      \"subName\": \"\",\n      \"version\": \"2.2.1\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"ref\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"instance\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(instance: HTMLDivElement) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"T\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"any\",\n                  },\n                },\n                Object {\n                  \"name\": \"current\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"object\",\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"key\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"className\",\n        \"propType\": \"string\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"rax-view\",\n  },\n]\n`;\n\nexports[`materialize rc-picker by online 1`] = `\nArray [\n  Object {\n    \"componentName\": \"PickerPanel\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"PickerPanel\",\n      \"main\": \"./lib/index\",\n      \"package\": \"rc-picker\",\n      \"subName\": \"\",\n      \"version\": \"2.4.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"picker\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"time\",\n                \"date\",\n                \"week\",\n                \"month\",\n                \"quarter\",\n                \"year\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"prefixCls\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"className\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@deprecated Will be removed in next big version. Please use \\`mode\\` instead\",\n        \"name\": \"mode\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"time\",\n                \"date\",\n                \"week\",\n                \"month\",\n                \"quarter\",\n                \"year\",\n                \"decade\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"tabIndex\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"locale\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"locale\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthBeforeYear\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"bool\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"yearFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthFormat\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"quarterFormat\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"today\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"now\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"backToToday\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"ok\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"timeSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"weekSelect\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"clear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"month\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"year\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"yearSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"decadeSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dayFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateTimeFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousDecade\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextDecade\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousCentury\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextCentury\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"shortWeekDays\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  Object {\n                    \"type\": \"arrayOf\",\n                    \"value\": \"string\",\n                  },\n                ],\n              },\n            },\n            Object {\n              \"name\": \"shortMonths\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  Object {\n                    \"type\": \"arrayOf\",\n                    \"value\": \"string\",\n                  },\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"generateConfig\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"DateType\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"any\",\n              },\n            },\n            Object {\n              \"name\": \"getWeekDay\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getSecond\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getMinute\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getHour\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getNow\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getFixedDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"fixed\",\n                    \"propType\": \"string\",\n                  },\n                ],\n                \"raw\": \"(fixed: string) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getEndDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"year\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, year: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"month\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, month: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"date\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, date: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setHour\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"hour\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, hour: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setMinute\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"minute\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, minute: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setSecond\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"second\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, second: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"isAfter\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"date1\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"date2\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(date1: DateType, date2: DateType) => boolean\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"isValidate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"date\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(date: DateType) => boolean\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"locale\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"shape\",\n                \"value\": Array [\n                  Object {\n                    \"name\": \"getWeekFirstDay\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string) => number\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getWeekFirstDate\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"value\",\n                          \"propType\": \"object\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, value: DateType) => DateType\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getWeek\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"value\",\n                          \"propType\": \"object\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, value: DateType) => number\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"format\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"date\",\n                          \"propType\": \"object\",\n                        },\n                        Object {\n                          \"name\": \"format\",\n                          \"propType\": \"string\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, date: DateType, format: string) => string\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"parse\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"text\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"formats\",\n                          \"propType\": Object {\n                            \"type\": \"arrayOf\",\n                            \"value\": \"string\",\n                          },\n                        },\n                      ],\n                      \"raw\": \"(locale: string, text: string, formats: string[]) => DateType | null\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getShortWeekDays\",\n                    \"propType\": Object {\n                      \"type\": \"oneOfType\",\n                      \"value\": Array [\n                        \"object\",\n                        Object {\n                          \"params\": Array [\n                            Object {\n                              \"name\": \"locale\",\n                              \"propType\": \"string\",\n                            },\n                          ],\n                          \"raw\": \"(locale: string) => string[]\",\n                          \"type\": \"func\",\n                        },\n                      ],\n                    },\n                  },\n                  Object {\n                    \"name\": \"getShortMonths\",\n                    \"propType\": Object {\n                      \"type\": \"oneOfType\",\n                      \"value\": Array [\n                        \"object\",\n                        Object {\n                          \"params\": Array [\n                            Object {\n                              \"name\": \"locale\",\n                              \"propType\": \"string\",\n                            },\n                          ],\n                          \"raw\": \"(locale: string) => string[]\",\n                          \"type\": \"func\",\n                        },\n                      ],\n                    },\n                  },\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"value\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"null\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"defaultValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"[Legacy] Set default display picker view date\",\n        \"name\": \"pickerValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"[Legacy] Set default display picker view date\",\n        \"name\": \"defaultPickerValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledDate\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"dateRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"monthCellRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"renderExtraFooter\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"mode\",\n                  \"propType\": Object {\n                    \"type\": \"oneOf\",\n                    \"value\": Array [\n                      \"time\",\n                      \"date\",\n                      \"week\",\n                      \"month\",\n                      \"quarter\",\n                      \"year\",\n                      \"decade\",\n                    ],\n                  },\n                },\n              ],\n              \"raw\": \"(mode: PanelMode) => ReactNode\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onSelect\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onPanelChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseDown\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onOk\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"direction\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"ltr\",\n                \"rtl\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private This is internal usage. Do not use in your production env\",\n        \"name\": \"hideHeader\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private This is internal usage. Do not use in your production env\",\n        \"name\": \"onPickerValueChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private Internal usage. Do not use in your production env\",\n        \"name\": \"components\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"button\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"rangeItem\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showToday\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showNow\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showTime\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"DateType\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"any\",\n                  },\n                },\n                Object {\n                  \"name\": \"format\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showNow\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showHour\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showMinute\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showSecond\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"use12Hours\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"hourStep\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"number\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"minuteStep\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"number\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"secondStep\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"number\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"hideDisabledOptions\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"defaultValue\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledTime\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"format\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showHour\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showMinute\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showSecond\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"use12Hours\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"hourStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"minuteStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"secondStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"hideDisabledOptions\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledHours\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledMinutes\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"hour\",\n                  \"propType\": \"number\",\n                },\n              ],\n              \"raw\": \"(hour: number) => number[]\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledSeconds\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"hour\",\n                  \"propType\": \"number\",\n                },\n                Object {\n                  \"name\": \"minute\",\n                  \"propType\": \"number\",\n                },\n              ],\n              \"raw\": \"(hour: number, minute: number) => number[]\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"rc-picker\",\n  },\n  Object {\n    \"componentName\": \"RangePicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"RangePicker\",\n      \"main\": \"./lib/index\",\n      \"package\": \"rc-picker\",\n      \"subName\": \"\",\n      \"version\": \"2.4.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"id\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"value\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"null\",\n            Object {\n              \"type\": \"tuple\",\n              \"value\": Array [\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"oneOfType\",\n                  \"value\": Array [\n                    \"null\",\n                    \"object\",\n                  ],\n                },\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"oneOfType\",\n                  \"value\": Array [\n                    \"null\",\n                    \"object\",\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"defaultValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"null\",\n            Object {\n              \"type\": \"tuple\",\n              \"value\": Array [\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"oneOfType\",\n                  \"value\": Array [\n                    \"null\",\n                    \"object\",\n                  ],\n                },\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"oneOfType\",\n                  \"value\": Array [\n                    \"null\",\n                    \"object\",\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"defaultPickerValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"tuple\",\n              \"value\": Array [\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"object\",\n                },\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"object\",\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"placeholder\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"tuple\",\n              \"value\": Array [\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"string\",\n                },\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"string\",\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabled\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n            Object {\n              \"type\": \"tuple\",\n              \"value\": Array [\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"bool\",\n                },\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"bool\",\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledTime\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"ranges\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"objectOf\",\n              \"value\": \"oneOfType\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"separator\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"allowEmpty\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"tuple\",\n              \"value\": Array [\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"bool\",\n                },\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"bool\",\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"mode\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"tuple\",\n              \"value\": Array [\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"oneOf\",\n                  \"value\": Array [\n                    \"time\",\n                    \"date\",\n                    \"week\",\n                    \"month\",\n                    \"quarter\",\n                    \"year\",\n                    \"decade\",\n                  ],\n                },\n                Object {\n                  \"isRequired\": true,\n                  \"type\": \"oneOf\",\n                  \"value\": Array [\n                    \"time\",\n                    \"date\",\n                    \"week\",\n                    \"month\",\n                    \"quarter\",\n                    \"year\",\n                    \"decade\",\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onCalendarChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onPanelChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onFocus\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: FocusEvent<HTMLInputElement, Element>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onBlur\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: FocusEvent<HTMLInputElement, Element>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onOk\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"direction\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"ltr\",\n                \"rtl\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"autoComplete\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private Internal control of active picker. Do not use since it's private usage\",\n        \"name\": \"activePickerIndex\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                0,\n                1,\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"dateRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"panelRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"originPanel\",\n                  \"propType\": \"node\",\n                },\n              ],\n              \"raw\": \"(originPanel: ReactNode) => ReactNode\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"picker\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"time\",\n                \"date\",\n                \"week\",\n                \"month\",\n                \"quarter\",\n                \"year\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"prefixCls\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"className\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"tabIndex\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"locale\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"locale\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthBeforeYear\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"bool\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"yearFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthFormat\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"quarterFormat\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"today\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"now\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"backToToday\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"ok\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"timeSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"weekSelect\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"clear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"month\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"year\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"yearSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"decadeSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dayFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateTimeFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousDecade\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextDecade\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousCentury\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextCentury\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"shortWeekDays\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  Object {\n                    \"type\": \"arrayOf\",\n                    \"value\": \"string\",\n                  },\n                ],\n              },\n            },\n            Object {\n              \"name\": \"shortMonths\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  Object {\n                    \"type\": \"arrayOf\",\n                    \"value\": \"string\",\n                  },\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"generateConfig\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"DateType\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"any\",\n              },\n            },\n            Object {\n              \"name\": \"getWeekDay\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getSecond\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getMinute\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getHour\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getNow\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getFixedDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"fixed\",\n                    \"propType\": \"string\",\n                  },\n                ],\n                \"raw\": \"(fixed: string) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getEndDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"year\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, year: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"month\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, month: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"date\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, date: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setHour\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"hour\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, hour: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setMinute\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"minute\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, minute: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setSecond\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"second\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, second: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"isAfter\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"date1\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"date2\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(date1: DateType, date2: DateType) => boolean\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"isValidate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"date\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(date: DateType) => boolean\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"locale\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"shape\",\n                \"value\": Array [\n                  Object {\n                    \"name\": \"getWeekFirstDay\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string) => number\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getWeekFirstDate\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"value\",\n                          \"propType\": \"object\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, value: DateType) => DateType\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getWeek\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"value\",\n                          \"propType\": \"object\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, value: DateType) => number\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"format\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"date\",\n                          \"propType\": \"object\",\n                        },\n                        Object {\n                          \"name\": \"format\",\n                          \"propType\": \"string\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, date: DateType, format: string) => string\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"parse\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"text\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"formats\",\n                          \"propType\": Object {\n                            \"type\": \"arrayOf\",\n                            \"value\": \"string\",\n                          },\n                        },\n                      ],\n                      \"raw\": \"(locale: string, text: string, formats: string[]) => DateType | null\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getShortWeekDays\",\n                    \"propType\": Object {\n                      \"type\": \"oneOfType\",\n                      \"value\": Array [\n                        \"object\",\n                        Object {\n                          \"params\": Array [\n                            Object {\n                              \"name\": \"locale\",\n                              \"propType\": \"string\",\n                            },\n                          ],\n                          \"raw\": \"(locale: string) => string[]\",\n                          \"type\": \"func\",\n                        },\n                      ],\n                    },\n                  },\n                  Object {\n                    \"name\": \"getShortMonths\",\n                    \"propType\": Object {\n                      \"type\": \"oneOfType\",\n                      \"value\": Array [\n                        \"object\",\n                        Object {\n                          \"params\": Array [\n                            Object {\n                              \"name\": \"locale\",\n                              \"propType\": \"string\",\n                            },\n                          ],\n                          \"raw\": \"(locale: string) => string[]\",\n                          \"type\": \"func\",\n                        },\n                      ],\n                    },\n                  },\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledDate\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"monthCellRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"renderExtraFooter\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"mode\",\n                  \"propType\": Object {\n                    \"type\": \"oneOf\",\n                    \"value\": Array [\n                      \"time\",\n                      \"date\",\n                      \"week\",\n                      \"month\",\n                      \"quarter\",\n                      \"year\",\n                      \"decade\",\n                    ],\n                  },\n                },\n              ],\n              \"raw\": \"(mode: PanelMode) => ReactNode\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseDown\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private Internal usage. Do not use in your production env\",\n        \"name\": \"components\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"button\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"rangeItem\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"dropdownClassName\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"dropdownAlign\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"points\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"arrayOf\",\n                        \"value\": \"string\",\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"offset\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"arrayOf\",\n                        \"value\": \"number\",\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"targetOffset\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"arrayOf\",\n                        \"value\": \"number\",\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"overflow\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"shape\",\n                        \"value\": Array [\n                          Object {\n                            \"name\": \"adjustX\",\n                            \"propType\": Object {\n                              \"type\": \"oneOfType\",\n                              \"value\": Array [\n                                \"object\",\n                                \"number\",\n                                \"bool\",\n                              ],\n                            },\n                          },\n                          Object {\n                            \"name\": \"adjustY\",\n                            \"propType\": Object {\n                              \"type\": \"oneOfType\",\n                              \"value\": Array [\n                                \"object\",\n                                \"number\",\n                                \"bool\",\n                              ],\n                            },\n                          },\n                        ],\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"useCssRight\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"useCssBottom\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"useCssTransform\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"ignoreShake\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"popupStyle\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"transitionName\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"allowClear\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"autoFocus\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"open\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"defaultOpen\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"Make input readOnly to avoid popup keyboard in mobile\",\n        \"name\": \"inputReadOnly\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"format\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n            \"func\",\n            Object {\n              \"type\": \"arrayOf\",\n              \"value\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"string\",\n                  \"func\",\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"suffixIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"clearIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"prevIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"nextIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"superPrevIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"superNextIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"getPopupContainer\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"node\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(node: HTMLElement) => HTMLElement\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onOpenChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"open\",\n                  \"propType\": \"bool\",\n                },\n              ],\n              \"raw\": \"(open: boolean) => void\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseUp\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseEnter\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseLeave\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onClick\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onContextMenu\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private Internal usage, do not use in production mode!!!\",\n        \"name\": \"pickerRef\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"role\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"name\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showTime\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showNow\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"order\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showHour\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showMinute\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showSecond\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"use12Hours\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"hourStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"minuteStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"secondStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"hideDisabledOptions\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledHours\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledMinutes\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"hour\",\n                  \"propType\": \"number\",\n                },\n              ],\n              \"raw\": \"(hour: number) => number[]\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledSeconds\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"hour\",\n                  \"propType\": \"number\",\n                },\n                Object {\n                  \"name\": \"minute\",\n                  \"propType\": \"number\",\n                },\n              ],\n              \"raw\": \"(hour: number, minute: number) => number[]\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@deprecated Please use \\`defaultValue\\` directly instead\",\n        \"name\": \"defaultOpenValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"rc-picker\",\n  },\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"./lib/index\",\n      \"package\": \"rc-picker\",\n      \"subName\": \"\",\n      \"version\": \"2.4.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"dropdownClassName\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"dropdownAlign\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"points\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"arrayOf\",\n                        \"value\": \"string\",\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"offset\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"arrayOf\",\n                        \"value\": \"number\",\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"targetOffset\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"arrayOf\",\n                        \"value\": \"number\",\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"overflow\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      Object {\n                        \"type\": \"shape\",\n                        \"value\": Array [\n                          Object {\n                            \"name\": \"adjustX\",\n                            \"propType\": Object {\n                              \"type\": \"oneOfType\",\n                              \"value\": Array [\n                                \"object\",\n                                \"number\",\n                                \"bool\",\n                              ],\n                            },\n                          },\n                          Object {\n                            \"name\": \"adjustY\",\n                            \"propType\": Object {\n                              \"type\": \"oneOfType\",\n                              \"value\": Array [\n                                \"object\",\n                                \"number\",\n                                \"bool\",\n                              ],\n                            },\n                          },\n                        ],\n                      },\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"useCssRight\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"useCssBottom\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"useCssTransform\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"ignoreShake\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"popupStyle\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"transitionName\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"placeholder\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"allowClear\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"autoFocus\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabled\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"tabIndex\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"open\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"defaultOpen\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"Make input readOnly to avoid popup keyboard in mobile\",\n        \"name\": \"inputReadOnly\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"id\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"format\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n            \"func\",\n            Object {\n              \"type\": \"arrayOf\",\n              \"value\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"string\",\n                  \"func\",\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"suffixIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"clearIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"prevIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"nextIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"superPrevIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"superNextIcon\",\n        \"propType\": \"node\",\n      },\n      Object {\n        \"name\": \"getPopupContainer\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"node\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(node: HTMLElement) => HTMLElement\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"panelRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"originPanel\",\n                  \"propType\": \"node\",\n                },\n              ],\n              \"raw\": \"(originPanel: ReactNode) => ReactNode\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onOpenChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"open\",\n                  \"propType\": \"bool\",\n                },\n              ],\n              \"raw\": \"(open: boolean) => void\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onFocus\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: FocusEvent<HTMLInputElement, Element>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onBlur\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: FocusEvent<HTMLInputElement, Element>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseDown\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseUp\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseEnter\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onMouseLeave\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onClick\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onContextMenu\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"event\",\n                  \"propType\": \"object\",\n                },\n              ],\n              \"raw\": \"(event: MouseEvent<HTMLDivElement, MouseEvent>) => void\",\n              \"returns\": Object {\n                \"propType\": \"number\",\n              },\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private Internal usage, do not use in production mode!!!\",\n        \"name\": \"pickerRef\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"role\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"name\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"autoComplete\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"direction\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"ltr\",\n                \"rtl\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"value\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"null\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"defaultValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"[Legacy] Set default display picker view date\",\n        \"name\": \"defaultPickerValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@deprecated Will be removed in next big version. Please use \\`mode\\` instead\",\n        \"name\": \"mode\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"time\",\n                \"date\",\n                \"week\",\n                \"month\",\n                \"quarter\",\n                \"year\",\n                \"decade\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onSelect\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onPanelChange\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"onOk\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"dateRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"picker\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"oneOf\",\n              \"value\": Array [\n                \"time\",\n                \"date\",\n                \"week\",\n                \"month\",\n                \"quarter\",\n                \"year\",\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"prefixCls\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"className\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"string\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"style\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"locale\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"locale\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthBeforeYear\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"bool\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"yearFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthFormat\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"quarterFormat\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"today\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"now\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"backToToday\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"ok\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"timeSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"weekSelect\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  \"string\",\n                ],\n              },\n            },\n            Object {\n              \"name\": \"clear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"month\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"year\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"monthSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"yearSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"decadeSelect\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dayFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"dateTimeFormat\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousDecade\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextDecade\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"previousCentury\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"nextCentury\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"string\",\n              },\n            },\n            Object {\n              \"name\": \"shortWeekDays\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  Object {\n                    \"type\": \"arrayOf\",\n                    \"value\": \"string\",\n                  },\n                ],\n              },\n            },\n            Object {\n              \"name\": \"shortMonths\",\n              \"propType\": Object {\n                \"type\": \"oneOfType\",\n                \"value\": Array [\n                  \"object\",\n                  Object {\n                    \"type\": \"arrayOf\",\n                    \"value\": \"string\",\n                  },\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"generateConfig\",\n        \"propType\": Object {\n          \"isRequired\": true,\n          \"type\": \"shape\",\n          \"value\": Array [\n            Object {\n              \"name\": \"DateType\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"any\",\n              },\n            },\n            Object {\n              \"name\": \"getWeekDay\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getSecond\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getMinute\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getHour\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => number\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getNow\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getFixedDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"fixed\",\n                    \"propType\": \"string\",\n                  },\n                ],\n                \"raw\": \"(fixed: string) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"getEndDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(value: DateType) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"addDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"diff\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, diff: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setYear\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"year\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, year: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setMonth\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"month\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, month: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setDate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"date\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, date: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setHour\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"hour\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, hour: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setMinute\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"minute\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, minute: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"setSecond\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"value\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"second\",\n                    \"propType\": \"number\",\n                  },\n                ],\n                \"raw\": \"(value: DateType, second: number) => DateType\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"isAfter\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"date1\",\n                    \"propType\": \"object\",\n                  },\n                  Object {\n                    \"name\": \"date2\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(date1: DateType, date2: DateType) => boolean\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"isValidate\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"params\": Array [\n                  Object {\n                    \"name\": \"date\",\n                    \"propType\": \"object\",\n                  },\n                ],\n                \"raw\": \"(date: DateType) => boolean\",\n                \"type\": \"func\",\n              },\n            },\n            Object {\n              \"name\": \"locale\",\n              \"propType\": Object {\n                \"isRequired\": true,\n                \"type\": \"shape\",\n                \"value\": Array [\n                  Object {\n                    \"name\": \"getWeekFirstDay\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string) => number\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getWeekFirstDate\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"value\",\n                          \"propType\": \"object\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, value: DateType) => DateType\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getWeek\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"value\",\n                          \"propType\": \"object\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, value: DateType) => number\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"format\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"date\",\n                          \"propType\": \"object\",\n                        },\n                        Object {\n                          \"name\": \"format\",\n                          \"propType\": \"string\",\n                        },\n                      ],\n                      \"raw\": \"(locale: string, date: DateType, format: string) => string\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"parse\",\n                    \"propType\": Object {\n                      \"isRequired\": true,\n                      \"params\": Array [\n                        Object {\n                          \"name\": \"locale\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"text\",\n                          \"propType\": \"string\",\n                        },\n                        Object {\n                          \"name\": \"formats\",\n                          \"propType\": Object {\n                            \"type\": \"arrayOf\",\n                            \"value\": \"string\",\n                          },\n                        },\n                      ],\n                      \"raw\": \"(locale: string, text: string, formats: string[]) => DateType | null\",\n                      \"type\": \"func\",\n                    },\n                  },\n                  Object {\n                    \"name\": \"getShortWeekDays\",\n                    \"propType\": Object {\n                      \"type\": \"oneOfType\",\n                      \"value\": Array [\n                        \"object\",\n                        Object {\n                          \"params\": Array [\n                            Object {\n                              \"name\": \"locale\",\n                              \"propType\": \"string\",\n                            },\n                          ],\n                          \"raw\": \"(locale: string) => string[]\",\n                          \"type\": \"func\",\n                        },\n                      ],\n                    },\n                  },\n                  Object {\n                    \"name\": \"getShortMonths\",\n                    \"propType\": Object {\n                      \"type\": \"oneOfType\",\n                      \"value\": Array [\n                        \"object\",\n                        Object {\n                          \"params\": Array [\n                            Object {\n                              \"name\": \"locale\",\n                              \"propType\": \"string\",\n                            },\n                          ],\n                          \"raw\": \"(locale: string) => string[]\",\n                          \"type\": \"func\",\n                        },\n                      ],\n                    },\n                  },\n                ],\n              },\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledDate\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"monthCellRender\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"renderExtraFooter\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"mode\",\n                  \"propType\": Object {\n                    \"type\": \"oneOf\",\n                    \"value\": Array [\n                      \"time\",\n                      \"date\",\n                      \"week\",\n                      \"month\",\n                      \"quarter\",\n                      \"year\",\n                      \"decade\",\n                    ],\n                  },\n                },\n              ],\n              \"raw\": \"(mode: PanelMode) => ReactNode\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@private Internal usage. Do not use in your production env\",\n        \"name\": \"components\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"button\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"rangeItem\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledTime\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showToday\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showTime\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n            Object {\n              \"type\": \"shape\",\n              \"value\": Array [\n                Object {\n                  \"name\": \"DateType\",\n                  \"propType\": Object {\n                    \"isRequired\": true,\n                    \"type\": \"any\",\n                  },\n                },\n                Object {\n                  \"name\": \"format\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"string\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showNow\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showHour\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showMinute\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"showSecond\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"use12Hours\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"hourStep\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"number\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"minuteStep\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"number\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"secondStep\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"number\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"hideDisabledOptions\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                      \"bool\",\n                    ],\n                  },\n                },\n                Object {\n                  \"name\": \"defaultValue\",\n                  \"propType\": Object {\n                    \"type\": \"oneOfType\",\n                    \"value\": Array [\n                      \"object\",\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showNow\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"description\": \"@deprecated Please use \\`defaultValue\\` directly instead\",\n        \"name\": \"defaultOpenValue\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showHour\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showMinute\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"showSecond\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"use12Hours\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"hourStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"minuteStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"secondStep\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"hideDisabledOptions\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"bool\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledHours\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            \"func\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledMinutes\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"hour\",\n                  \"propType\": \"number\",\n                },\n              ],\n              \"raw\": \"(hour: number) => number[]\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n      Object {\n        \"name\": \"disabledSeconds\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"object\",\n            Object {\n              \"params\": Array [\n                Object {\n                  \"name\": \"hour\",\n                  \"propType\": \"number\",\n                },\n                Object {\n                  \"name\": \"minute\",\n                  \"propType\": \"number\",\n                },\n              ],\n              \"raw\": \"(hour: number, minute: number) => number[]\",\n              \"type\": \"func\",\n            },\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"rc-picker\",\n  },\n]\n`;\n\nexports[`materialize react-color by online 1`] = `\nArray [\n  Object {\n    \"componentName\": \"BlockPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"BlockPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 170,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"triangle\",\n        \"propType\": Object {\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"top\",\n            \"hide\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"CirclePicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"CirclePicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 252,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": 28,\n        \"name\": \"circleSize\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"defaultValue\": 14,\n        \"name\": \"circleSpacing\",\n        \"propType\": \"number\",\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"default\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": false,\n      \"exportName\": \"default\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 225,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": false,\n        \"name\": \"disableAlpha\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"defaultView\",\n        \"propType\": Object {\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"hex\",\n            \"rgb\",\n            \"hsl\",\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"ChromePicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"ChromePicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 225,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": false,\n        \"name\": \"disableAlpha\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"defaultView\",\n        \"propType\": Object {\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"hex\",\n            \"rgb\",\n            \"hsl\",\n          ],\n        },\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"CompactPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"CompactPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"GithubPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"GithubPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 200,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"triangle\",\n        \"propType\": Object {\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"hide\",\n            \"top-left\",\n            \"top-right\",\n            \"bottom-left\",\n            \"bottom-right\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"HuePicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"HuePicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"PhotoshopPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"PhotoshopPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"name\": \"header\",\n        \"propType\": \"string\",\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"SketchPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"SketchPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": false,\n        \"name\": \"disableAlpha\",\n        \"propType\": \"bool\",\n      },\n      Object {\n        \"defaultValue\": 200,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"SliderPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"SliderPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"SwatchesPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"SwatchesPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 320,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": 240,\n        \"name\": \"height\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"TwitterPicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"TwitterPicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 276,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"name\": \"triangle\",\n        \"propType\": Object {\n          \"type\": \"oneOf\",\n          \"value\": Array [\n            \"hide\",\n            \"top-left\",\n            \"top-right\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n  Object {\n    \"componentName\": \"GooglePicker\",\n    \"devMode\": \"proCode\",\n    \"docUrl\": \"\",\n    \"npm\": Object {\n      \"destructuring\": true,\n      \"exportName\": \"GooglePicker\",\n      \"main\": \"lib/index.js\",\n      \"package\": \"react-color\",\n      \"subName\": \"\",\n      \"version\": \"2.19.3\",\n    },\n    \"props\": Array [\n      Object {\n        \"defaultValue\": 652,\n        \"name\": \"width\",\n        \"propType\": Object {\n          \"type\": \"oneOfType\",\n          \"value\": Array [\n            \"string\",\n            \"number\",\n          ],\n        },\n      },\n      Object {\n        \"defaultValue\": Object {},\n        \"name\": \"styles\",\n        \"propType\": \"object\",\n      },\n      Object {\n        \"name\": \"header\",\n        \"propType\": \"string\",\n      },\n    ],\n    \"screenshot\": \"\",\n    \"title\": \"react-color\",\n  },\n]\n`;\n"
  },
  {
    "path": "modules/material-parser/test/dynamic.test.ts",
    "content": "import parse from '../src';\nimport { IMaterializeOptions } from '../src/types';\n\nconst dynamicComponent = '@alifd/biz-anchor@1.1.7';\n\ntest('materialize dynamic component by online', async () => {\n  const options: IMaterializeOptions = {\n    entry: dynamicComponent,\n    accesser: 'online',\n  };\n\n  const actual = await parse(options);\n  expect(actual).toMatchSnapshot();\n});"
  },
  {
    "path": "modules/material-parser/test/fixtures/dts-component/index.d.ts",
    "content": "import * as React from 'react';\n\n/**\n * 财鲸Layout属性配置\n */\nexport interface WhaleLayoutProps {\n  /**\n   * 是否是财鲸主站，该字段由后端 vm 中吐出在 window.appConfig 中\n   * @defaultValue false\n   */\n  isMainSite?: boolean;\n  /**\n   * 财鲸主站的 app 名称，该字段由后端 vm 中吐出在 window.appConfig 中\n   * @defaultValue 'caijing'\n   */\n  mainSiteAppName?: string;\n  /**\n   * 主站中文名，该字段由后端 vm 中吐出在 window.appConfig 中\n   * @defaultValue '财鲸'\n   */\n  mainSiteName?: string;\n  /**\n   * 主站英文名，该字段由后端 vm 中吐出在 window.appConfig 中\n   * @defaultValue 'Caijing'\n   */\n  mainSiteNameEn?: string;\n  /**\n   * 主站链接，该字段由后端 vm 中吐出在 window.appConfig 中\n   * @defaultValue '//caijing.alibaba-inc.com'\n   */\n  mainSiteLink?: string;\n  /**\n   * 子站点的应用名，该字段由后端 vm 中吐出在 window.appConfig 中\n   */\n  subSiteAppName: string;\n  /**\n   * 子站点的名称，该字段由后端 vm 中吐出在 window.appConfig 中\n   */\n  subSiteName: string;\n  /**\n   * 子站点的英文名称，该字段由后端 vm 中吐出在 window.appConfig 中\n   */\n  subSiteNameEn: string;\n  /**\n   * 子站点的链接，该字段由后端 vm 中吐出在 window.appConfig 中\n   */\n  subSiteLink: string;\n  /**\n   * 子站访问相关接口时，属于buc 跨域请求，需要把 ssoTicket 带上，该字段由后端 vm 中吐出在 window.appConfig 中\n   */\n  ssoTicket: string;\n  /**\n   * 是否使用 ak/sk 方案（用于登录）\n   * @defaultValue false\n   */\n  aksk?: boolean;\n  /**\n   * 是否显示左侧导航\n   * @defaultValue true\n   */\n  sidebarVisible?: boolean;\n  /**\n   * 是否显示顶部菜单栏\n   * @defaultValue true\n   */\n  topbarVisible?: boolean;\n  /**\n   * 是否开启全屏\n   * @defaultValue false\n   */\n  isFullScreen?: boolean;\n  /**\n   * 当前选中的导航 key\n   * @defaultValue 'home'\n   */\n  navSelectedKeys?: string | string[];\n  /**\n   * history 对象\n   * @defaultValue {}\n   */\n  history?: string | {};\n  /**\n   * 左侧子导航数组\n   * 参考：https://whale.fusion.alibaba-inc.com/73015/component/basic/nav#demo-api\n   * @defaultValue []\n   */\n  nav?: Array<{}>;\n  /**\n   * Next Nav 组件本身的配置\n   * @defaultValue {}\n   */\n  nextNavConfig?: {};\n  /**\n   * 切换语言的 Url\n   * @defaultValue null\n   */\n  setLanguageUrl?: string;\n  /**\n   * 顶部控件的扩展区渲染内容\n   * @defaultValue null\n   */\n  extra?: React.ReactNode;\n  /**\n   * 顶部导航站点名称后面的快速入口区域自定义渲染\n   * @defaultValue null\n   */\n  quickEntry?: React.ReactNode;\n  /**\n   * 水印配置项\n   * 配置文档参考：{@link https://npm.alibaba-inc.com/package/@alife/waterMark}\n   * @defaultValue null\n   */\n  waterMarkOptions?: {};\n  /**\n   * 是否需要默认的登出行为\n   * @defaultValue true\n   */\n  needDefaultLogout?: boolean;\n  /**\n   * 点击登出按钮后的回调函数\n   * @defaultValue null\n   */\n  onLogoutClick?: () => void;\n  /**\n   * 侧边栏收起展开回调函数\n   * @defaultValue null\n   */\n  onToggleMenu?: () => void;\n  /**\n   * logo 的 style 覆盖\n   * @defaultValue null\n   */\n  logoStyle?: React.CSSProperties;\n  /**\n   * logo 点击事件，传入覆盖\n   * @defaultValue null\n   */\n  onLogoClick?: () => void;\n  /**\n   * 切换语言自定义事件\n   *\n  */\n  onToggleLang?: (nextConfig: Record<string, any>, appName: any) => void;\n  /**\n   * 语言切换器显示切换\n   * @defaultValueValue true\n  */\n  langVisible?: boolean;\n  /**\n   * 打开启用浏览器缩放警告\n   * @defaultValue `true`\n  */\n  scaleWarning?: boolean;\n  /**\n    * This event is fired whenever the application navigates to a new page.\n    * @eventProperty\n  */\n  test: string;\n}\n\n/**\n * 财鲸Layout owner: 昔夜\n *\n * 查看组件文档: https://whale.fusion.alibaba-inc.com/73015/component/bizcomps/692\n */\ndeclare class WhaleLayout extends React.Component<WhaleLayoutProps, any> { }\n\nexport default WhaleLayout;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/dts-component/package.json",
    "content": "{\n    \"name\": \"dts-component\",\n    \"version\": \"1.2.3\",\n    \"main\": \"./src/index.jsx\"\n}"
  },
  {
    "path": "modules/material-parser/test/fixtures/dts-component/src/data.js",
    "content": "export default [\n  {\n    countryKey: 'CN',\n    value: '+86',\n    countryName_zh: '中国',\n    countryName: 'China',\n    flag: 'C',\n  },\n  {\n    countryKey: 'US',\n    value: '+1',\n    countryName_zh: '美国',\n    countryName: 'United States',\n    flag: 'U',\n  }, {\n    countryKey: 'JP',\n    value: '+81',\n    countryName_zh: '日本',\n    countryName: 'Japan',\n    flag: 'J',\n  }, {\n    countryKey: 'TW',\n    value: '+886',\n    countryName_zh: '中国台湾',\n    countryName: 'Taiwan',\n    flag: 'T',\n  }, {\n    countryKey: 'HK',\n    value: '+852',\n    countryName_zh: '中国香港',\n    countryName: 'Hong Kong',\n    flag: 'H',\n  }, {\n    countryKey: 'IN',\n    value: '+91',\n    countryName_zh: '印度',\n    countryName: 'India',\n    flag: 'I',\n  }, {\n    countryKey: 'AF',\n    value: '+93',\n    countryName_zh: '阿富汗',\n    countryName: 'Afghanistan',\n    flag: 'A',\n  }, {\n    countryKey: 'AL',\n    value: '+355',\n    countryName_zh: '阿尔巴尼亚',\n    countryName: 'Albania',\n    flag: 'A',\n  }, {\n    countryKey: 'DZ',\n    value: '+213',\n    countryName_zh: '阿尔及利亚',\n    countryName: 'Algeria',\n    flag: 'A',\n  }, {\n    countryKey: 'AD',\n    value: '+376',\n    countryName_zh: '安道尔',\n    countryName: 'Andorra',\n    flag: 'A',\n  }, {\n    countryKey: 'AO',\n    value: '+244',\n    countryName_zh: '安哥拉',\n    countryName: 'Angola',\n    flag: 'A',\n  }, {\n    countryKey: 'AI',\n    value: '+1264',\n    countryName_zh: '安圭拉岛',\n    countryName: 'Anguilla',\n    flag: 'A',\n  }, {\n    countryKey: 'AG',\n    value: '+1268',\n    countryName_zh: '安提瓜岛和巴布达',\n    countryName: 'Antigua and Barbuda',\n    flag: 'A',\n  }, {\n    countryKey: 'AR',\n    value: '+54',\n    countryName_zh: '阿根廷',\n    countryName: 'Argentina',\n    flag: 'A',\n  }, {\n    countryKey: 'AM',\n    value: '+374',\n    countryName_zh: '亚美尼亚',\n    countryName: 'Armenia',\n    flag: 'A',\n  }, {\n    countryKey: 'AW',\n    value: '+297',\n    countryName_zh: '阿鲁巴',\n    countryName: 'Aruba',\n    flag: 'A',\n  }, {\n    countryKey: 'AU',\n    value: '+61',\n    countryName_zh: '澳大利亚',\n    countryName: 'Australia',\n    flag: 'A',\n  }, {\n    countryKey: 'AT',\n    value: '+43',\n    countryName_zh: '奥地利',\n    countryName: 'Austria',\n    flag: 'A',\n  }, {\n    countryKey: 'AZ',\n    value: '+994',\n    countryName_zh: '阿塞拜疆',\n    countryName: 'Azerbaijan',\n    flag: 'A',\n  }, {\n    countryKey: 'BS',\n    value: '+1242',\n    countryName_zh: '巴哈马',\n    countryName: 'Bahamas',\n    flag: 'B',\n  }, {\n    countryKey: 'BH',\n    value: '+973',\n    countryName_zh: '巴林',\n    countryName: 'Bahrain',\n    flag: 'B',\n  }, {\n    countryKey: 'BD',\n    value: '+880',\n    countryName_zh: '孟加拉',\n    countryName: 'Bangladesh',\n    flag: 'B',\n  }, {\n    countryKey: 'BB',\n    value: '+1246',\n    countryName_zh: '巴巴多斯岛',\n    countryName: 'Barbados',\n    flag: 'B',\n  }, {\n    countryKey: 'BY',\n    value: '+375',\n    countryName_zh: '白俄罗斯',\n    countryName: 'Belarus',\n    flag: 'B',\n  }, {\n    countryKey: 'BE',\n    value: '+32',\n    countryName_zh: '比利时',\n    countryName: 'Belgium',\n    flag: 'B',\n  }, {\n    countryKey: 'BZ',\n    value: '+501',\n    countryName_zh: '伯利兹',\n    countryName: 'Belize',\n    flag: 'B',\n  }, {\n    countryKey: 'BJ',\n    value: '+229',\n    countryName_zh: '贝宁',\n    countryName: 'Benin',\n    flag: 'B',\n  }, {\n    countryKey: 'BM',\n    value: '+1441',\n    countryName_zh: '百慕大',\n    countryName: 'Bermuda',\n    flag: 'B',\n  }, {\n    countryKey: 'BT',\n    value: '+975',\n    countryName_zh: '不丹',\n    countryName: 'Bhutan',\n    flag: 'B',\n  }, {\n    countryKey: 'BO',\n    value: '+591',\n    countryName_zh: '玻利维亚',\n    countryName: 'Bolivia',\n    flag: 'B',\n  }, {\n    countryKey: 'BA',\n    value: '+387',\n    countryName_zh: '波斯尼亚和黑塞哥维那',\n    countryName: 'Bosnia And Herzegovina',\n    flag: 'B',\n  }, {\n    countryKey: 'BW',\n    value: '+267',\n    countryName_zh: '博茨瓦纳',\n    countryName: 'Botswana',\n    flag: 'B',\n  }, {\n    countryKey: 'BR',\n    value: '+55',\n    countryName_zh: '巴西',\n    countryName: 'Brazil',\n    flag: 'B',\n  }, {\n    countryKey: 'VG',\n    value: '+1284',\n    countryName_zh: '英属维尔京群岛',\n    countryName: 'British Virgin Islands',\n    flag: 'B',\n  }, {\n    countryKey: 'BN',\n    value: '+673',\n    countryName_zh: '文莱',\n    countryName: 'Brunei',\n    flag: 'B',\n  }, {\n    countryKey: 'BG',\n    value: '+359',\n    countryName_zh: '保加利亚',\n    countryName: 'Bulgaria',\n    flag: 'B',\n  }, {\n    countryKey: 'BF',\n    value: '+226',\n    countryName_zh: '布基纳法索',\n    countryName: 'Burkina Faso',\n    flag: 'B',\n  }, {\n    countryKey: 'BI',\n    value: '+257',\n    countryName_zh: '布隆迪',\n    countryName: 'Burundi',\n    flag: 'B',\n  }, {\n    countryKey: 'KH',\n    value: '+855',\n    countryName_zh: '柬埔寨',\n    countryName: 'Cambodia',\n    flag: 'C',\n  }, {\n    countryKey: 'CM',\n    value: '+237',\n    countryName_zh: '喀麦隆',\n    countryName: 'Cameroon',\n    flag: 'C',\n  }, {\n    countryKey: 'CA',\n    value: '+1',\n    countryName_zh: '加拿大',\n    countryName: 'Canada',\n    flag: 'C',\n  }, {\n    countryKey: 'CV',\n    value: '+238',\n    countryName_zh: '佛得角',\n    countryName: 'Cape verde',\n    flag: 'C',\n  }, {\n    countryKey: 'KY',\n    value: '+1345',\n    countryName_zh: '开曼群岛',\n    countryName: 'Cayman Islands',\n    flag: 'C',\n  }, {\n    countryKey: 'CF',\n    value: '+236',\n    countryName_zh: '中非共和国',\n    countryName: 'Central African Republic',\n    flag: 'C',\n  }, {\n    countryKey: 'TD',\n    value: '+235',\n    countryName_zh: '乍得',\n    countryName: 'Chad',\n    flag: 'C',\n  }, {\n    countryKey: 'CL',\n    value: '+56',\n    countryName_zh: '智利',\n    countryName: 'Chile',\n    flag: 'C',\n  }, {\n    countryKey: 'CN',\n    value: '+86',\n    countryName_zh: '中国',\n    countryName: 'China',\n    flag: 'C',\n  }, {\n    countryKey: 'CO',\n    value: '+57',\n    countryName_zh: '哥伦比亚',\n    countryName: 'Columbia',\n    flag: 'C',\n  }, {\n    countryKey: 'KM',\n    value: '+269',\n    countryName_zh: '科摩罗',\n    countryName: 'Comoros',\n    flag: 'C',\n  }, {\n    countryKey: 'CG',\n    value: '+242',\n    countryName_zh: '刚果民主共和国',\n    countryName: 'Congo-Kinshasa',\n    flag: 'C',\n  }, {\n    countryKey: 'CD',\n    value: '+243',\n    countryName_zh: '刚果共和国',\n    countryName: 'Congo-Brazzaville',\n    flag: 'C',\n  }, {\n    countryKey: 'CK',\n    value: '+682',\n    countryName_zh: '库克群岛',\n    countryName: 'Cook Islands',\n    flag: 'C',\n  }, {\n    countryKey: 'CR',\n    value: '+506',\n    countryName_zh: '哥斯达黎加',\n    countryName: 'Costa Rica',\n    flag: 'C',\n  }, {\n    countryKey: 'CI',\n    value: '+225',\n    countryName_zh: '科特迪瓦',\n    countryName: \"Cote d'lvoire\",\n    flag: 'C',\n  }, {\n    countryKey: 'HR',\n    value: '+385',\n    countryName_zh: '克罗地亚',\n    countryName: 'Croatia',\n    flag: 'C',\n  }, {\n    countryKey: 'CU',\n    value: '+53',\n    countryName_zh: '古巴',\n    countryName: 'Cuba',\n    flag: 'C',\n  }, {\n    countryKey: 'CY',\n    value: '+357',\n    countryName_zh: '塞浦路斯',\n    countryName: 'Cyprus',\n    flag: 'C',\n  }, {\n    countryKey: 'CZ',\n    value: '+420',\n    countryName_zh: '捷克共和国',\n    countryName: 'Czech Republic',\n    flag: 'C',\n  }, {\n    countryKey: 'DK',\n    value: '+45',\n    countryName_zh: '丹麦',\n    countryName: 'Denmark',\n    flag: 'D',\n  }, {\n    countryKey: 'DJ',\n    value: '+253',\n    countryName_zh: '吉布提',\n    countryName: 'Djibouti',\n    flag: 'D',\n  }, {\n    countryKey: 'DM',\n    value: '+1767',\n    countryName_zh: '多米尼加',\n    countryName: 'Domilica',\n    flag: 'D',\n  }, {\n    countryKey: 'DO',\n    value: '+1809',\n    countryName_zh: '多米尼加共和国',\n    countryName: 'Dominican Republic',\n    flag: 'D',\n  }, {\n    countryKey: 'EC',\n    value: '+593',\n    countryName_zh: '厄瓜多尔',\n    countryName: 'Ecuador',\n    flag: 'E',\n  }, {\n    countryKey: 'EG',\n    value: '+20',\n    countryName_zh: '埃及',\n    countryName: 'Egypt',\n    flag: 'E',\n  }, {\n    countryKey: 'SV',\n    value: '+503',\n    countryName_zh: '萨尔瓦多',\n    countryName: 'EI Salvador',\n    flag: 'E',\n  }, {\n    countryKey: 'GQ',\n    value: '+240',\n    countryName_zh: '赤道几内亚',\n    countryName: 'Equatorial Guinea',\n    flag: 'E',\n  }, {\n    countryKey: 'ER',\n    value: '+291',\n    countryName_zh: '厄立特里亚',\n    countryName: 'Eritrea',\n    flag: 'E',\n  }, {\n    countryKey: 'EE',\n    value: '+372',\n    countryName_zh: '爱沙尼亚',\n    countryName: 'Estonia',\n    flag: 'E',\n  }, {\n    countryKey: 'ET',\n    value: '+251',\n    countryName_zh: '埃塞俄比亚',\n    countryName: 'Ethiopia',\n    flag: 'E',\n  }, {\n    countryKey: 'FO',\n    value: '+298',\n    countryName_zh: '法罗群岛',\n    countryName: 'Faroe Islands',\n    flag: 'F',\n  }, {\n    countryKey: 'FJ',\n    value: '+679',\n    countryName_zh: '斐济',\n    countryName: 'Fiji Islands',\n    flag: 'F',\n  }, {\n    countryKey: 'FI',\n    value: '+358',\n    countryName_zh: '芬兰',\n    countryName: 'Finland',\n    flag: 'F',\n  }, {\n    countryKey: 'FR',\n    value: '+33',\n    countryName_zh: '法国',\n    countryName: 'France',\n    flag: 'F',\n  }, {\n    countryKey: 'PF',\n    value: '+689',\n    countryName_zh: '法属波利尼西亚',\n    countryName: 'French Polynesia',\n    flag: 'F',\n  }, {\n    countryKey: 'GA',\n    value: '+241',\n    countryName_zh: '加蓬',\n    countryName: 'Gabon',\n    flag: 'G',\n  }, {\n    countryKey: 'GM',\n    value: '+220',\n    countryName_zh: '冈比亚',\n    countryName: 'Gambia',\n    flag: 'G',\n  }, {\n    countryKey: 'GE',\n    value: '+995',\n    countryName_zh: '乔治亚',\n    countryName: 'Georgia',\n    flag: 'G',\n  }, {\n    countryKey: 'DE',\n    value: '+49',\n    countryName_zh: '德国',\n    countryName: 'Germany',\n    flag: 'G',\n  }, {\n    countryKey: 'GH',\n    value: '+233',\n    countryName_zh: '加纳',\n    countryName: 'Ghana',\n    flag: 'G',\n  }, {\n    countryKey: 'GI',\n    value: '+350',\n    countryName_zh: '直布罗陀',\n    countryName: 'Gibraltar',\n    flag: 'G',\n  }, {\n    countryKey: 'GR',\n    value: '+30',\n    countryName_zh: '希腊',\n    countryName: 'Greece',\n    flag: 'G',\n  }, {\n    countryKey: 'GL',\n    value: '+299',\n    countryName_zh: '格陵兰',\n    countryName: 'Greenland',\n    flag: 'G',\n  }, {\n    countryKey: 'GD',\n    value: '+1473',\n    countryName_zh: '格林纳达',\n    countryName: 'Grenada',\n    flag: 'G',\n  }, {\n    countryKey: 'GU',\n    value: '+1671',\n    countryName_zh: '关岛',\n    countryName: 'Guam',\n    flag: 'G',\n  }, {\n    countryKey: 'GT',\n    value: '+502',\n    countryName_zh: '危地马拉',\n    countryName: 'Guatemala',\n    flag: 'G',\n  }, {\n    countryKey: 'GN',\n    value: '+224',\n    countryName_zh: '几内亚',\n    countryName: 'Guinea',\n    flag: 'G',\n  }, {\n    countryKey: 'GW',\n    value: '+245',\n    countryName_zh: '几内亚比绍',\n    countryName: 'Guinea-Bissau',\n    flag: 'G',\n  }, {\n    countryKey: 'GY',\n    value: '+592',\n    countryName_zh: '圭亚那',\n    countryName: 'Guyana',\n    flag: 'G',\n  }, {\n    countryKey: 'HT',\n    value: '+509',\n    countryName_zh: '海地',\n    countryName: 'Haiti',\n    flag: 'H',\n  }, {\n    countryKey: 'HN',\n    value: '+504',\n    countryName_zh: '洪都拉斯',\n    countryName: 'Honduras',\n    flag: 'H',\n  }, {\n    countryKey: 'HK',\n    value: '+852',\n    countryName_zh: '中国香港',\n    countryName: 'Hong Kong',\n    flag: 'H',\n  }, {\n    countryKey: 'HU',\n    value: '+36',\n    countryName_zh: '匈牙利',\n    countryName: 'Hungary',\n    flag: 'H',\n  }, {\n    countryKey: 'IS',\n    value: '+354',\n    countryName_zh: '冰岛',\n    countryName: 'Iceland',\n    flag: 'I',\n  }, {\n    countryKey: 'IN',\n    value: '+91',\n    countryName_zh: '印度',\n    countryName: 'India',\n    flag: 'I',\n  }, {\n    countryKey: 'ID',\n    value: '+62',\n    countryName_zh: '印度尼西亚',\n    countryName: 'Indonesia',\n    flag: 'I',\n  }, {\n    countryKey: 'IR',\n    value: '+98',\n    countryName_zh: '伊朗',\n    countryName: 'Iran',\n    flag: 'I',\n  }, {\n    countryKey: 'IQ',\n    value: '+964',\n    countryName_zh: '伊拉克',\n    countryName: 'Iraq',\n    flag: 'I',\n  }, {\n    countryKey: 'IE',\n    value: '+353',\n    countryName_zh: '爱尔兰',\n    countryName: 'Ireland',\n    flag: 'I',\n  }, {\n    countryKey: 'IL',\n    value: '+972',\n    countryName_zh: '以色列',\n    countryName: 'Israel',\n    flag: 'I',\n  }, {\n    countryKey: 'IT',\n    value: '+39',\n    countryName_zh: '意大利',\n    countryName: 'Italy',\n    flag: 'I',\n  }, {\n    countryKey: 'JM',\n    value: '+1876',\n    countryName_zh: '牙买加',\n    countryName: 'Jamaica',\n    flag: 'J',\n  }, {\n    countryKey: 'JP',\n    value: '+81',\n    countryName_zh: '日本',\n    countryName: 'Japan',\n    flag: 'J',\n  }, {\n    countryKey: 'JE',\n    value: '+44',\n    countryName_zh: '泽西岛',\n    countryName: 'Jersey',\n    flag: 'J',\n  }, {\n    countryKey: 'JO',\n    value: '+962',\n    countryName_zh: '约旦',\n    countryName: 'Jordan',\n    flag: 'J',\n  }, {\n    countryKey: 'KZ',\n    value: '+7',\n    countryName_zh: '哈萨克斯坦',\n    countryName: 'Kazakhstan',\n    flag: 'K',\n  }, {\n    countryKey: 'KE',\n    value: '+254',\n    countryName_zh: '肯尼亚',\n    countryName: 'Kenya',\n    flag: 'K',\n  }, {\n    countryKey: 'KR',\n    value: '+82',\n    countryName_zh: '韩国',\n    countryName: 'Korea',\n    flag: 'K',\n  }, {\n    countryKey: 'KW',\n    value: '+965',\n    countryName_zh: '科威特',\n    countryName: 'Kuwait',\n    flag: 'K',\n  }, {\n    countryKey: 'KG',\n    value: '+996',\n    countryName_zh: '吉尔吉斯斯坦',\n    countryName: 'Kyrgyzstan',\n    flag: 'K',\n  }, {\n    countryKey: 'LA',\n    value: '+856',\n    countryName_zh: '老挝',\n    countryName: 'Laos',\n    flag: 'L',\n  }, {\n    countryKey: 'LV',\n    value: '+371',\n    countryName_zh: '拉脱维亚',\n    countryName: 'Latvia',\n    flag: 'L',\n  }, {\n    countryKey: 'LB',\n    value: '+961',\n    countryName_zh: '黎巴嫩',\n    countryName: 'Lebanon',\n    flag: 'L',\n  }, {\n    countryKey: 'LS',\n    value: '+266',\n    countryName_zh: '莱索托',\n    countryName: 'Lesotho',\n    flag: 'L',\n  }, {\n    countryKey: 'LR',\n    value: '+231',\n    countryName_zh: '利比里亚',\n    countryName: 'Liberia',\n    flag: 'L',\n  }, {\n    countryKey: 'LY',\n    value: '+218',\n    countryName_zh: '利比亚',\n    countryName: 'Libya',\n    flag: 'L',\n  }, {\n    countryKey: 'LI',\n    value: '+423',\n    countryName_zh: '列支敦士登',\n    countryName: 'Liechtenstein',\n    flag: 'L',\n  }, {\n    countryKey: 'LT',\n    value: '+370',\n    countryName_zh: '立陶宛',\n    countryName: 'Lithuania',\n    flag: 'L',\n  }, {\n    countryKey: 'LU',\n    value: '+352',\n    countryName_zh: '卢森堡',\n    countryName: 'Luxembourg',\n    flag: 'L',\n  }, {\n    countryKey: 'MO',\n    value: '+853',\n    countryName_zh: '中国澳门',\n    countryName: 'Macao',\n    flag: 'M',\n  }, {\n    countryKey: 'MK',\n    value: '+389',\n    countryName_zh: '马其顿',\n    countryName: 'Macedonia,Former Yugoslav Republic of',\n    flag: 'M',\n  }, {\n    countryKey: 'MG',\n    value: '+261',\n    countryName_zh: '马达加斯加',\n    countryName: 'Madagascar',\n    flag: 'M',\n  }, {\n    countryKey: 'MW',\n    value: '+265',\n    countryName_zh: '马拉维',\n    countryName: 'Malawi',\n    flag: 'M',\n  }, {\n    countryKey: 'MY',\n    value: '+60',\n    countryName_zh: '马来西亚',\n    countryName: 'Malaysia',\n    flag: 'M',\n  }, {\n    countryKey: 'MV',\n    value: '+960',\n    countryName_zh: '马尔代夫',\n    countryName: 'Maldives',\n    flag: 'M',\n  }, {\n    countryKey: 'ML',\n    value: '+223',\n    countryName_zh: '马里',\n    countryName: 'Mali',\n    flag: 'M',\n  }, {\n    countryKey: 'MT',\n    value: '+356',\n    countryName_zh: '马耳他',\n    countryName: 'Malta',\n    flag: 'M',\n  }, {\n    countryKey: 'MR',\n    value: '+222',\n    countryName_zh: '毛里塔尼亚',\n    countryName: 'Mauritania',\n    flag: 'M',\n  }, {\n    countryKey: 'MX',\n    value: '+52',\n    countryName_zh: '墨西哥',\n    countryName: 'Mexico',\n    flag: 'M',\n  }, {\n    countryKey: 'MD',\n    value: '+373',\n    countryName_zh: '摩尔多瓦',\n    countryName: 'Moldova',\n    flag: 'M',\n  }, {\n    countryKey: 'MC',\n    value: '+377',\n    countryName_zh: '摩纳哥',\n    countryName: 'Monaco',\n    flag: 'M',\n  }, {\n    countryKey: 'MN',\n    value: '+976',\n    countryName_zh: '蒙古',\n    countryName: 'Mongolia',\n    flag: 'M',\n  }, {\n    countryKey: 'ME',\n    value: '+382',\n    countryName_zh: '黑山共和国',\n    countryName: 'Montenegro',\n    flag: 'M',\n  }, {\n    countryKey: 'MA',\n    value: '+212',\n    countryName_zh: '摩洛哥',\n    countryName: 'Morocco',\n    flag: 'M',\n  }, {\n    countryKey: 'MZ',\n    value: '+258',\n    countryName_zh: '莫桑比克',\n    countryName: 'Mozambique',\n    flag: 'M',\n  }, {\n    countryKey: 'MM',\n    value: '+95',\n    countryName_zh: '缅甸',\n    countryName: 'Myanmar',\n    flag: 'M',\n  }, {\n    countryKey: 'NA',\n    value: '+264',\n    countryName_zh: '纳米比亚',\n    countryName: 'Namibia',\n    flag: 'N',\n  }, {\n    countryKey: 'NP',\n    value: '+977',\n    countryName_zh: '尼泊尔',\n    countryName: 'Nepal',\n    flag: 'N',\n  }, {\n    countryKey: 'NL',\n    value: '+31',\n    countryName_zh: '荷兰',\n    countryName: 'Netherlands',\n    flag: 'N',\n  }, {\n    countryKey: 'AN',\n    value: '+599',\n    countryName_zh: '荷属安的列斯群岛',\n    countryName: 'Netherlands Antilles',\n    flag: 'N',\n  }, {\n    countryKey: 'NC',\n    value: '+687',\n    countryName_zh: '新喀里多尼亚',\n    countryName: 'New Caledonia',\n    flag: 'N',\n  }, {\n    countryKey: 'NZ',\n    value: '+64',\n    countryName_zh: '新西兰',\n    countryName: 'New Zealand',\n    flag: 'N',\n  }, {\n    countryKey: 'NI',\n    value: '+505',\n    countryName_zh: '尼加拉瓜',\n    countryName: 'Nicaragua',\n    flag: 'N',\n  }, {\n    countryKey: 'NE',\n    value: '+227',\n    countryName_zh: '尼日尔',\n    countryName: 'Niger',\n    flag: 'N',\n  }, {\n    countryKey: 'NG',\n    value: '+234',\n    countryName_zh: '尼日利亚',\n    countryName: 'Nigeria',\n    flag: 'N',\n  }, {\n    countryKey: 'KP',\n    value: '+850',\n    countryName_zh: '朝鲜',\n    countryName: 'North Korea',\n    flag: 'N',\n  }, {\n    countryKey: 'NO',\n    value: '+47',\n    countryName_zh: '挪威',\n    countryName: 'Norway',\n    flag: 'N',\n  }, {\n    countryKey: 'OM',\n    value: '+968',\n    countryName_zh: '阿曼',\n    countryName: 'Oman',\n    flag: 'O',\n  }, {\n    countryKey: 'PK',\n    value: '+92',\n    countryName_zh: '巴基斯坦',\n    countryName: 'Pakistan',\n    flag: 'P',\n  }, {\n    countryKey: 'PA',\n    value: '+507',\n    countryName_zh: '巴拿马',\n    countryName: 'Panama',\n    flag: 'P',\n  }, {\n    countryKey: 'PG',\n    value: '+675',\n    countryName_zh: '巴布亚新几内亚',\n    countryName: 'Papua New Guinea',\n    flag: 'P',\n  }, {\n    countryKey: 'PY',\n    value: '+595',\n    countryName_zh: '巴拉圭',\n    countryName: 'Paraguay',\n    flag: 'P',\n  }, {\n    countryKey: 'PE',\n    value: '+51',\n    countryName_zh: '秘鲁',\n    countryName: 'Peru',\n    flag: 'P',\n  }, {\n    countryKey: 'PH',\n    value: '+63',\n    countryName_zh: '菲律宾',\n    countryName: 'Philippines',\n    flag: 'P',\n  }, {\n    countryKey: 'PL',\n    value: '+48',\n    countryName_zh: '波兰',\n    countryName: 'Poland',\n    flag: 'P',\n  }, {\n    countryKey: 'PT',\n    value: '+351',\n    countryName_zh: '葡萄牙',\n    countryName: 'Portugal',\n    flag: 'P',\n  }, {\n    countryKey: 'PR',\n    value: '+1',\n    countryName_zh: '波多黎各',\n    countryName: 'Puerto Rico',\n    flag: 'P',\n  }, {\n    countryKey: 'QA',\n    value: '+974',\n    countryName_zh: '卡塔尔',\n    countryName: 'Qatar',\n    flag: 'Q',\n  }, {\n    countryKey: 'RO',\n    value: '+40',\n    countryName_zh: '罗马尼亚',\n    countryName: 'Romania',\n    flag: 'R',\n  }, {\n    countryKey: 'RU',\n    value: '+7',\n    countryName_zh: '俄罗斯',\n    countryName: 'Russia',\n    flag: 'R',\n  }, {\n    countryKey: 'RW',\n    value: '+250',\n    countryName_zh: '卢旺达',\n    countryName: 'Rwanda',\n    flag: 'R',\n  }, {\n    countryKey: 'LC',\n    value: '+1758',\n    countryName_zh: '圣卢西亚',\n    countryName: 'Saint Lucia',\n    flag: 'S',\n  }, {\n    countryKey: 'PM',\n    value: '+508',\n    countryName_zh: '圣皮埃尔和密克隆',\n    countryName: 'Saint Pierre and Miquelon',\n    flag: 'S',\n  }, {\n    countryKey: 'VC',\n    value: '+1784',\n    countryName_zh: '圣文森特河格林纳丁斯',\n    countryName: 'Saint Vincent And the Grenadines',\n    flag: 'S',\n  }, {\n    countryKey: 'WS',\n    value: '+685',\n    countryName_zh: '萨摩亚',\n    countryName: 'Samoa',\n    flag: 'S',\n  }, {\n    countryKey: 'SM',\n    value: '+378',\n    countryName_zh: '圣马力诺',\n    countryName: 'San Marino',\n    flag: 'S',\n  }, {\n    countryKey: 'ST',\n    value: '+239',\n    countryName_zh: '圣多美和普林西比',\n    countryName: 'Sao Tome and Principe',\n    flag: 'S',\n  }, {\n    countryKey: 'SA',\n    value: '+966',\n    countryName_zh: '沙特阿拉伯',\n    countryName: 'Saudi Arabia',\n    flag: 'S',\n  }, {\n    countryKey: 'SN',\n    value: '+221',\n    countryName_zh: '塞内加尔',\n    countryName: 'Senegal',\n    flag: 'S',\n  }, {\n    countryKey: 'RS',\n    value: '+381',\n    countryName_zh: '塞尔维亚',\n    countryName: 'Serbia',\n    flag: 'S',\n  }, {\n    countryKey: 'SC',\n    value: '+248',\n    countryName_zh: '塞舌尔',\n    countryName: 'Seychelles',\n    flag: 'S',\n  }, {\n    countryKey: 'SL',\n    value: '+232',\n    countryName_zh: '塞拉利昂',\n    countryName: 'Sierra Leone',\n    flag: 'S',\n  }, {\n    countryKey: 'SG',\n    value: '+65',\n    countryName_zh: '新加坡',\n    countryName: 'Singapore',\n    flag: 'S',\n  }, {\n    countryKey: 'SK',\n    value: '+421',\n    countryName_zh: '斯洛伐克',\n    countryName: 'Slovakia',\n    flag: 'S',\n  }, {\n    countryKey: 'SI',\n    value: '+386',\n    countryName_zh: '斯洛文尼亚',\n    countryName: 'Slovenia',\n    flag: 'S',\n  }, {\n    countryKey: 'SO',\n    value: '+252',\n    countryName_zh: '索马里',\n    countryName: 'Somalia',\n    flag: 'S',\n  }, {\n    countryKey: 'ZA',\n    value: '+27',\n    countryName_zh: '南非',\n    countryName: 'South Africa',\n    flag: 'S',\n  }, {\n    countryKey: 'ES',\n    value: '+34',\n    countryName_zh: '西班牙',\n    countryName: 'Spain',\n    flag: 'S',\n  }, {\n    countryKey: 'LK',\n    value: '+94',\n    countryName_zh: '斯里兰卡',\n    countryName: 'Sri Lanka',\n    flag: 'S',\n  }, {\n    countryKey: 'KN',\n    value: '+1869',\n    countryName_zh: '圣基茨和尼维斯',\n    countryName: 'St.Kitts and Nevis',\n    flag: 'S',\n  }, {\n    countryKey: 'SD',\n    value: '+249',\n    countryName_zh: '苏丹',\n    countryName: 'Sudan',\n    flag: 'S',\n  }, {\n    countryKey: 'SR',\n    value: '+597',\n    countryName_zh: '苏里南',\n    countryName: 'Surinam',\n    flag: 'S',\n  }, {\n    countryKey: 'SZ',\n    value: '+268',\n    countryName_zh: '斯威士兰',\n    countryName: 'Swaziland',\n    flag: 'S',\n  }, {\n    countryKey: 'SE',\n    value: '+46',\n    countryName_zh: '瑞典',\n    countryName: 'Sweden',\n    flag: 'S',\n  }, {\n    countryKey: 'CH',\n    value: '+41',\n    countryName_zh: '瑞士',\n    countryName: 'Switzerland',\n    flag: 'S',\n  }, {\n    countryKey: 'SY',\n    value: '+963',\n    countryName_zh: '叙利亚',\n    countryName: 'Syria',\n    flag: 'S',\n  }, {\n    countryKey: 'TW',\n    value: '+886',\n    countryName_zh: '中国台湾',\n    countryName: 'Taiwan',\n    flag: 'T',\n  }, {\n    countryKey: 'TJ',\n    value: '+992',\n    countryName_zh: '塔吉克斯坦',\n    countryName: 'Tajikistan',\n    flag: 'T',\n  }, {\n    countryKey: 'TZ',\n    value: '+255',\n    countryName_zh: '坦桑尼亚',\n    countryName: 'Tanzania',\n    flag: 'T',\n  }, {\n    countryKey: 'TH',\n    value: '+66',\n    countryName_zh: '泰国',\n    countryName: 'Thailand',\n    flag: 'T',\n  }, {\n    countryKey: 'TL',\n    value: '+670',\n    countryName_zh: '东帝汶',\n    countryName: 'Timor-Leste',\n    flag: 'T',\n  }, {\n    countryKey: 'TG',\n    value: '+228',\n    countryName_zh: '多哥',\n    countryName: 'Togo',\n    flag: 'T',\n  }, {\n    countryKey: 'TO',\n    value: '+676',\n    countryName_zh: '汤加',\n    countryName: 'Tonga',\n    flag: 'T',\n  }, {\n    countryKey: 'TT',\n    value: '+1868',\n    countryName_zh: '特立尼达和多巴哥',\n    countryName: 'Trinidad and Tobago',\n    flag: 'T',\n  }, {\n    countryKey: 'TN',\n    value: '+216',\n    countryName_zh: '突尼斯',\n    countryName: 'Tunisia',\n    flag: 'T',\n  }, {\n    countryKey: 'TR',\n    value: '+90',\n    countryName_zh: '土耳其',\n    countryName: 'Turkey',\n    flag: 'T',\n  }, {\n    countryKey: 'TM',\n    value: '+993',\n    countryName_zh: '土库曼斯坦',\n    countryName: 'Turkmenistan',\n    flag: 'T',\n  }, {\n    countryKey: 'TC',\n    value: '+1649',\n    countryName_zh: '特克斯和凯科斯群岛',\n    countryName: 'Turks and Caicos Islands',\n    flag: 'T',\n  }, {\n    countryKey: 'UG',\n    value: '+256',\n    countryName_zh: '乌干达',\n    countryName: 'Uganda',\n    flag: 'U',\n  }, {\n    countryKey: 'UA',\n    value: '+380',\n    countryName_zh: '乌克兰',\n    countryName: 'Ukraine',\n    flag: 'U',\n  }, {\n    countryKey: 'AE',\n    value: '+971',\n    countryName_zh: '阿拉伯联合酋长国',\n    countryName: 'United Arab Emirates',\n    flag: 'U',\n  }, {\n    countryKey: 'GB',\n    value: '+44',\n    countryName_zh: '英国',\n    countryName: 'United Kingdom',\n    flag: 'U',\n  }, {\n    countryKey: 'US',\n    value: '+1',\n    countryName_zh: '美国',\n    countryName: 'United States',\n    flag: 'U',\n  }, {\n    countryKey: 'UY',\n    value: '+598',\n    countryName_zh: '乌拉圭',\n    countryName: 'Uruguay',\n    flag: 'U',\n  }, {\n    countryKey: 'UZ',\n    value: '+998',\n    countryName_zh: '乌兹别克斯坦',\n    countryName: 'Uzbekistan',\n    flag: 'U',\n  }, {\n    countryKey: 'VU',\n    value: '+678',\n    countryName_zh: '瓦努阿图',\n    countryName: 'Vanuatu',\n    flag: 'V',\n  }, {\n    countryKey: 'VE',\n    value: '+58',\n    countryName_zh: '委内瑞拉',\n    countryName: 'Venezuela',\n    flag: 'V',\n  }, {\n    countryKey: 'VN',\n    value: '+84',\n    countryName_zh: '越南',\n    countryName: 'Vietnam',\n    flag: 'V',\n  }, {\n    countryKey: 'YE',\n    value: '+967',\n    countryName_zh: '也门',\n    countryName: 'Yemen',\n    flag: 'Y',\n  }, {\n    countryKey: 'ZM',\n    value: '+260',\n    countryName_zh: '赞比亚',\n    countryName: 'Zambia',\n    flag: 'Z',\n  }, {\n    countryKey: 'ZW',\n    value: '+263',\n    countryName_zh: '津巴布韦',\n    countryName: 'Zimbabwe',\n    flag: 'Z',\n  },\n];\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/dts-component/src/i18n.js",
    "content": "/**\n * 组件内置的多语言文案\n */\n\nconst bundles = {\n  'zh-CN': {\n    dataSource: [\n      {\n        label: '+86',\n        value: '86',\n        country: '中国',\n        rule: /(?=(\\d{4})+$)/g,\n      },\n    ],\n  },\n  'en-US': {\n    dataSource: [\n      {\n        label: '+86',\n        value: '86',\n        country: 'china',\n        rule: /(?=(\\d{4})+$)/g,\n      },\n    ],\n  },\n};\nexport default bundles;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/dts-component/src/index.jsx",
    "content": "import React from 'react';\nimport { Select, Input } from '@alifd/next';\nimport i18n from '@alife/whale-i18n';\nimport classnames from 'classnames';\nimport PropTypes from 'prop-types';\nimport { getLanguage } from '@alife/whale-util';\n\nimport i18nBundles from './i18n';\nimport countryDataSource from './data';\n\nconst lang = getLanguage();\nconst isCN = ['ZH_CN', 'ZH-CN'].includes(lang && lang.toUpperCase());\n\nclass WhaleTelephone extends React.Component {\n  static displayName = 'WhaleTelephone';\n\n  static propTypes = {\n    style: PropTypes.object,\n    className: PropTypes.string,\n    disabled: PropTypes.bool,\n    value: PropTypes.object,\n    onChange: PropTypes.func,\n  };\n\n  static defaultProps = {\n    style: {},\n    className: '',\n    disabled: false,\n    onChange: undefined,\n    value: {\n      countryCode: '+86',\n      phoneNumber: '',\n    },\n  };\n\n  constructor(props) {\n    super(props);\n    this.state = {\n      popupStyle: {},\n      tmpSelectedItem: {},\n    };\n  }\n\n  componentDidMount() {\n    if (!this.props.readOnly) {\n      this.handleStyle();\n      window.addEventListener('resize', this.resizeEventFunction);\n    }\n  }\n\n  componentWillUnmount() {\n    if (!this.props.readOnly) {\n      window.removeEventListener('resize', this.resizeEventFunction);\n    }\n  }\n\n  resizeEventFunction = () => this.handleStyle();\n\n  handleStyle = () => {\n    const { el } = this;\n    const elWidth = el.offsetWidth;\n    this.setState({\n      popupStyle: {\n        width: elWidth,\n      },\n    });\n  };\n\n  selectChange=(val, actionType, tmpSelectedItem) => {\n    const { value, onChange } = this.props;\n    this.setState({ tmpSelectedItem });\n    onChange && onChange(Object.assign({}, value, { countryCode: val }), tmpSelectedItem, 'select');\n  };\n\n  inputChange = (val) => {\n    const { value, onChange } = this.props;\n    const { tmpSelectedItem } = this.state;\n    onChange && onChange(Object.assign({}, value, { phoneNumber: val }), tmpSelectedItem, 'input');\n  };\n\n  renderItem = (item) => {\n    const { countryName, countryName_zh: countryNameZh, value } = item;\n    return (\n      <div>\n        <span className=\"country-span\">{!isCN ? countryName : countryNameZh}</span>\n        <span className=\"code-span\">{value}</span>\n      </div>\n    );\n  };\n\n  render() {\n    // i18nBundle 是 i18n 包装后额外提供的 prop，表示组件当前实际使用的文案\n    const {\n      style,\n      className,\n      disabled,\n      value: { countryCode, phoneNumber },\n      readOnly,\n    } = this.props;\n    // 排除掉不需要透传下去的参数，特别地适用于直接把大部分特殊控制外的参数透传给 Fusion 等组件的用法\n    const cls = classnames({\n      'whale-telephone': true,\n      'whale-telephone-readonly': !!readOnly,\n      [className]: className,\n    });\n    const { popupStyle } = this.state;\n\n    if (readOnly) {\n      return (\n        <div className={cls} style={style}>\n          <span>{countryCode}</span>&nbsp;<span>{phoneNumber}</span>\n        </div>\n      );\n    }\n\n    return (\n      <div className={cls} style={style} ref={(ref) => { this.el = ref; }} data-name=\"WhaleTelephone\">\n        <Select\n          className=\"whale-telephone-select\"\n          disabled={disabled}\n          dataSource={countryDataSource}\n          itemRender={this.renderItem}\n          popupStyle={popupStyle}\n          popupClassName=\"whale-telephone-select-popup\"\n          defaultValue={countryCode}\n          onChange={this.selectChange}\n        />\n        <Input\n          className=\"whale-telephone-number-input\"\n          value={phoneNumber}\n          disabled={disabled}\n          onChange={this.inputChange}\n        />\n      </div>\n    );\n  }\n}\n\n// 默认 export 提供了内置多语言文案的组件\nexport default i18n(WhaleTelephone, i18nBundles);\n// 万一需有对组件进行扩展，为了避免 HOC 后无法直接继承，提供了导出组件内置多语言文案及未经 HOC 的组件\nexport { i18nBundles, WhaleTelephone as Pure };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/dts-component/src/main.scss",
    "content": " \n@import 'scss/variable';\n\n// put your code here\n\n.whale-telephone {\n  display: flex;\n  .whale-telephone-select {\n    min-width: 72px;\n    width: 72px;\n    .next-select-inner {\n      min-width: 72px;\n    }\n    .next-input.next-medium {\n      border-radius: 0;\n      border-right: none;\n    }\n  }\n  .whale-telephone-number-input {\n    flex-grow: 2;\n    border-radius: 0;\n    &.next-input.next-medium {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n  }\n\n  &.whale-telephone-readonly {\n    font-family: Roboto;\n    color: #262626;\n    font-size: 14px;\n    line-height: 1.7;\n  }\n}\n\n.whale-telephone-select-popup {\n  .code-span {\n    float: right;\n  }\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/dts-component/src/scss/variable.scss",
    "content": "////\n/// @module @alife/whale-telephone: 组件中文名\n/// @tag WhaleTelephone\n/// @category custom\n/// @family whale-telephone\n/// @varPrefix $whale-telephone\n/// @classPrefix whale-telephone\n////\n\n/// backgroud\n/// @namespace statement/normal\n$whale-telephone-color: $color-brand1-1 !default;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = function () {\n  return Promise.resolve(component);\n};\n\nexport default {\n  getComponent,\n  manifest: amManifest,\n};"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nfunction _update(Nygma, node) {\n  const attributes = node.get();\n  const display = attributes.display;\n      const flexDirection = attributes.flexDirection;\n      const alignItems = attributes.alignItems;\n      const justifyContent = attributes.justifyContent;\n      const flexWrap = attributes.flexWrap;\n  const isFlex = display === 'flex';\n  node.set({\n    display,\n    flexDirection: isFlex ? flexDirection : undefined,\n    alignItems: isFlex ? alignItems : undefined,\n    justifyContent: isFlex ? justifyContent : undefined,\n    flexWrap: isFlex ? flexWrap : undefined,\n  });\n}\n\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeBlank',\n  // The description of current component.\n  description: '空白卡片',\n  // The coverimage's url of current component.\n  coverImage: 'https://img.alicdn.com/tfs/TB1un9tqntYBeNjy1XdXXXXyVXa-366-124.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '布局',\n  // card.blank\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [{\n    alias: '空白卡片',\n    thumbnail: 'https://img.alicdn.com/tfs/TB1ucPNVsbpK1RjSZFyXXX_qFXa-198-120.png',\n    colSpan: 12,\n    customProps: {\n      id: '',\n      textAlign: 'left',\n      padding: '12px',\n      width: '100%',\n      backgroundColor: '#FFF',\n    },\n  }],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'container',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'tbrlv',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    lifeCycle: {\n      didMount (props) {\n        const Nygma = props.Nygma;\n            const dragInstance = props.dragInstance;\n        const Drager = dragInstance.NygmaNode;\n\n        _update(Nygma, Drager);\n      },\n      didUpdate (Nygma, node, args) {\n        const newvalue = args[1];\n        const oldvalue = args[2];\n\n        if (JSON.stringify(newvalue) !== JSON.stringify(oldvalue)) {\n          _update(Nygma, node);\n        }\n      },\n    },\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [{\n      name: 'id',\n      label: 'id',\n      defaultValue: '',\n      renderer: 'Input',\n    }, {\n      name: 'textAlign',\n      label: '水平对齐',\n      defaultValue: 'left',\n      renderer: 'TextAlign',\n    }, {\n      name: 'margin',\n      label: '外边距',\n      renderer: 'Quadrant',\n    }, {\n      name: 'padding',\n      label: '内边距',\n      renderer: 'Quadrant',\n      defaultValue: '12px',\n    }, {\n      name: 'width',\n      label: '宽度',\n      defaultValue: '100%',\n      renderer: 'Width',\n    }, {\n      name: 'height',\n      label: '高度',\n      renderer: 'Height',\n      defaultValue: undefined,\n    }, {\n      name: 'backgroundColor',\n      label: '背景颜色',\n      renderer: 'Color',\n      defaultValue: '#FFF',\n    }, {\n      name: 'border',\n      label: '边框',\n      renderer: 'BarBorder',\n    }, {\n      name: 'display',\n      label: '布局设置',\n      renderer: 'FlexLayout',\n    }],\n  },\n};\nexport default manifest;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/container.js",
    "content": "\n      import AIMakeBlank from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: AIMakeBlank, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/index.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\nimport HOCBackgroundProps from '../utils/HOCBackgroundProps';\nimport HOCFlexLayoutProps from '../utils/HOCFlexLayoutProps';\n\nconst AIMakeBlank =\n/* #__PURE__ */\nfunction (_Component) {\n  _inherits(AIMakeBlank, _Component);\n\n  function AIMakeBlank() {\n    _classCallCheck(this, AIMakeBlank);\n\n    return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeBlank).apply(this, arguments));\n  }\n\n  _createClass(AIMakeBlank, [{\n    key: \"render\",\n    value: function render() {\n      const merged = {};\n      const _this$props = this.props;\n          const children = _this$props.children;\n          const styleBoxModel = _this$props.styleBoxModel;\n          const styleLayout = _this$props.styleLayout;\n          const styleBackground = _this$props.styleBackground;\n          const styleFlexLayout = _this$props.styleFlexLayout;\n          const style = _this$props.style;\n          const id = _this$props.id;\n      const styles = { ...styleBoxModel,\n        ...styleLayout,\n        ...styleBackground,\n        ...styleFlexLayout,\n        ...style,\n      };\n\n      if (id) {\n        merged.id = id;\n      }\n\n      return React.createElement(\"div\", _extends({\n        style: styles,\n      }, merged), children);\n    },\n  }]);\n\n  return AIMakeBlank;\n}(Component);\n\n_defineProperty(AIMakeBlank, \"propTypes\", {\n  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),\n  styleBoxModel: PropTypes.object.isRequired,\n  styleLayout: PropTypes.object.isRequired,\n  styleBackground: PropTypes.object.isRequired,\n  styleFlexLayout: PropTypes.object.isRequired,\n  style: PropTypes.object,\n  id: PropTypes.string,\n});\n\n_defineProperty(AIMakeBlank, \"defaultProps\", {\n  children: [],\n  style: {},\n  id: '',\n});\n\nexport default HOCBoxModelProps(HOCLayoutProps(HOCBackgroundProps(HOCFlexLayoutProps(AIMakeBlank))));"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.js",
    "content": "{\"componentName\":\"AIMakeBlank\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"@ali/lowcode-engine-material-parser\",\"version\":\"0.1.0\",\"exportName\":\"AIMakeBlank\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleFlexLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"},{\"name\":\"id\",\"propType\":\"string\",\"description\":\"\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/IconFont.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types'; // 缓存已加载的字体文件\n\nconst customCache = new Set(); // 动态加载字体文件\n\nexport default function createFromIconfont(options) {\n  const scriptUrl = options.scriptUrl;\n\n  if (typeof document !== 'undefined' && typeof window !== 'undefined' && typeof document.createElement === 'function' && typeof scriptUrl === 'string' && scriptUrl.length && !customCache.has(scriptUrl)) {\n    const script = document.createElement('script');\n    script.setAttribute('src', scriptUrl);\n    script.setAttribute('data-namespace', scriptUrl);\n    customCache.add(scriptUrl);\n    document.body.appendChild(script);\n  }\n\n  const IconFont =\n  /* #__PURE__ */\n  function (_Component) {\n    _inherits(IconFont, _Component);\n\n    function IconFont() {\n      _classCallCheck(this, IconFont);\n\n      return _possibleConstructorReturn(this, _getPrototypeOf(IconFont).apply(this, arguments));\n    }\n\n    _createClass(IconFont, [{\n      key: \"render\",\n      value: function render() {\n        const _this$props = this.props;\n            const type = _this$props.type;\n            const restProps = _objectWithoutProperties(_this$props, [\"type\"]);\n\n        const innerSvgProps = {\n          width: '1em',\n          height: '1em',\n          fill: 'currentColor',\n          'aria-hidden': 'true',\n          focusable: 'false',\n        }; // 引用指定svg\n\n        const content = React.createElement(\"use\", {\n          xlinkHref: `#${type}`,\n        });\n        return React.createElement(\"i\", _extends({}, restProps, {\n          className: `iconfont ${type}`,\n        }), React.createElement(\"svg\", innerSvgProps, content));\n      },\n    }]);\n\n    return IconFont;\n  }(Component);\n\n  IconFont.propTypes = {\n    type: PropTypes.string.isRequired, // icon\n\n  };\n  return IconFont;\n}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\nimport createFromIconfont from './IconFont';\n\nconst getComponent = function () {\n  return Promise.resolve(component);\n};\n\nexport default {\n  getComponent,\n  manifest: amManifest,\n  createFromIconfont,\n};"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeIcon',\n  // The description of current component.\n  description: '图标',\n  // The coverimage's url of current component.\n  coverImage: '',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: 'AIMakeIcon',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'rl',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [{\n      name: 'margin',\n      label: '外边距',\n      renderer: 'Quadrant',\n    }, {\n      name: 'color',\n      label: '图标颜色',\n      renderer: 'Color',\n      defaultValue: '#333',\n    }, {\n      name: 'fontSize',\n      label: '图标大小',\n      renderer: 'FontSize',\n      defaultValue: '16px',\n    }, {\n      name: 'display',\n      label: '显示',\n      defaultValue: 'inline-block',\n    }, {\n      name: 'className',\n      label: '图标类型',\n      defaultValue: 'iconfont',\n      renderer: false,\n      params: {\n        placeholder: '请输入Iconfont名',\n      },\n    }],\n  },\n};\nexport default manifest;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/container.js",
    "content": "\n      import AIMakeIcon from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: AIMakeIcon, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/index.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport createFromIconfont from './IconFont';\n\nconst AIMakeIcon =\n/* #__PURE__ */\nfunction (_Component) {\n  _inherits(AIMakeIcon, _Component);\n\n  function AIMakeIcon() {\n    _classCallCheck(this, AIMakeIcon);\n\n    return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeIcon).apply(this, arguments));\n  }\n\n  _createClass(AIMakeIcon, [{\n    key: \"render\",\n    value: function render() {\n      const _this$props = this.props;\n          const className = _this$props.className;\n          const iconClassName = _this$props.iconClassName;\n          const children = _this$props.children;\n          const styleBoxModel = _this$props.styleBoxModel;\n          const styleText = _this$props.styleText;\n          const styleBackground = _this$props.styleBackground;\n          const style = _this$props.style;\n          const otherProps = _objectWithoutProperties(_this$props, [\"className\", \"iconClassName\", \"children\", \"styleBoxModel\", \"styleText\", \"styleBackground\", \"style\"]);\n\n      const styles = { ...styleBoxModel,\n        ...styleText,\n        ...styleBackground,\n        ...style,\n      };\n      return React.createElement(\"i\", _extends({}, otherProps, {\n        className: classNames(className, iconClassName),\n        style: styles,\n      }), children);\n    },\n  }]);\n\n  return AIMakeIcon;\n}(Component);\n\n_defineProperty(AIMakeIcon, \"propTypes\", {\n  className: PropTypes.string,\n  iconClassName: PropTypes.string,\n  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),\n  styleBoxModel: PropTypes.object.isRequired,\n  styleText: PropTypes.object.isRequired,\n  styleBackground: PropTypes.object.isRequired,\n  style: PropTypes.object,\n});\n\n_defineProperty(AIMakeIcon, \"defaultProps\", {\n  className: '',\n  iconClassName: 'iconfont',\n  children: '',\n  style: {},\n});\n\nAIMakeIcon.createFromIconfont = createFromIconfont;\nexport default AIMakeIcon;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.js",
    "content": "{\"componentName\":\"AIMakeIcon\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"@ali/lowcode-engine-material-parser\",\"version\":\"0.1.0\",\"exportName\":\"AIMakeIcon\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"className\",\"propType\":\"string\",\"description\":\"\"},{\"name\":\"iconClassName\",\"propType\":\"string\",\"description\":\"\"},{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleText\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = function () {\n  return Promise.resolve(component);\n};\n\nexport default {\n  getComponent,\n  manifest: amManifest,\n};"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeImage',\n  // The description of current component.\n  description: '图片',\n  // The coverimage's url of current component.\n  coverImage: 'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '线条图像',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [{\n    alias: '图片',\n    thumbnail: 'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',\n    colSpan: 12,\n    customProps: {\n      width: '224px',\n      height: '126px',\n      src: 'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',\n    },\n  }],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'rl',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [{\n      name: 'margin',\n      label: '外边距',\n      renderer: 'Quadrant',\n    }, {\n      name: 'width',\n      label: '宽度',\n      defaultValue: '224px',\n      renderer: 'Width',\n    }, {\n      name: 'height',\n      label: '高度',\n      defaultValue: '126px',\n      renderer: 'Height',\n    }, {\n      name: 'src',\n      label: '图片URL',\n      renderer: 'Uploader',\n      placeholder: 'eg: https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',\n      hint: '请填入图片的URL',\n      defaultValue: 'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',\n    }],\n  },\n};\nexport default manifest;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/container.js",
    "content": "\n      import AIMakeImage from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: AIMakeImage, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/index.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\n\nconst AIMakeImage =\n/* #__PURE__ */\nfunction (_Component) {\n  _inherits(AIMakeImage, _Component);\n\n  function AIMakeImage() {\n    _classCallCheck(this, AIMakeImage);\n\n    return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeImage).apply(this, arguments));\n  }\n\n  _createClass(AIMakeImage, [{\n    key: \"render\",\n    value: function render() {\n      const _this$props = this.props;\n          const styleBoxModel = _this$props.styleBoxModel;\n          const style = _this$props.style;\n          const otherProps = _objectWithoutProperties(_this$props, [\"styleBoxModel\", \"style\"]);\n\n      const styles = { ...styleBoxModel,\n        ...style,\n      };\n      return React.createElement(\"img\", _extends({}, otherProps, {\n        style: styles,\n        alt: \"AIMakeImage\",\n      }));\n    },\n  }]);\n\n  return AIMakeImage;\n}(Component);\n\n_defineProperty(AIMakeImage, \"propTypes\", {\n  styleBoxModel: PropTypes.object.isRequired,\n  style: PropTypes.object,\n});\n\n_defineProperty(AIMakeImage, \"defaultProps\", {\n  style: {},\n});\n\nexport default HOCBoxModelProps(AIMakeImage);"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.js",
    "content": "{\"componentName\":\"AIMakeImage\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"@ali/lowcode-engine-material-parser\",\"version\":\"0.1.0\",\"exportName\":\"AIMakeImage\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = function () {\n  return Promise.resolve(component);\n};\n\nexport default {\n  getComponent,\n  manifest: amManifest,\n};"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeLink',\n  // The description of current component.\n  description: '链接',\n  // The coverimage's url of current component.\n  coverImage: 'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '文本',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [{\n    alias: '链接',\n    thumbnail: 'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',\n    colSpan: 12,\n    customProps: {\n      color: '#3788FF',\n      fontSize: '12px',\n      fontWeight: 'normal',\n      href: '#',\n      children: '链接',\n    },\n  }],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'lrv',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [{\n      name: 'margin',\n      label: '外边距',\n      renderer: 'Quadrant',\n    }, {\n      name: 'color',\n      label: '文字颜色',\n      renderer: 'Color',\n      defaultValue: '#3788FF',\n    }, {\n      name: 'fontSize',\n      label: '字号',\n      renderer: 'FontSize',\n      defaultValue: '12px',\n    }, {\n      name: 'fontWeight',\n      label: '字重',\n      renderer: 'FontWeight',\n      defaultValue: 'normal',\n    }, {\n      name: 'lineHeight',\n      label: '行高',\n      defaultValue: undefined,\n      renderer: 'LineHeight',\n    }, {\n      name: 'href',\n      label: '链接URL',\n      renderer: 'Input',\n      placeholder: '请输入链接URL',\n      defaultValue: '#',\n    }, {\n      name: 'children',\n      label: '内容',\n      defaultValue: '链接',\n      renderer: 'TextArea',\n    }],\n  },\n};\nexport default manifest;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/container.js",
    "content": "\n      import AIMakeLink from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: AIMakeLink, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/index.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCTextProps from '../utils/HOCTextProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\nimport HOCBackgroundProps from '../utils/HOCBackgroundProps';\n\nconst AIMakeLink =\n/* #__PURE__ */\nfunction (_Component) {\n  _inherits(AIMakeLink, _Component);\n\n  function AIMakeLink() {\n    _classCallCheck(this, AIMakeLink);\n\n    return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeLink).apply(this, arguments));\n  }\n\n  _createClass(AIMakeLink, [{\n    key: \"render\",\n    value: function render() {\n      const _this$props = this.props;\n          const children = _this$props.children;\n          const styleBoxModel = _this$props.styleBoxModel;\n          const styleText = _this$props.styleText;\n          const styleLayout = _this$props.styleLayout;\n          const styleBackground = _this$props.styleBackground;\n          const style = _this$props.style;\n          const otherProps = _objectWithoutProperties(_this$props, [\"children\", \"styleBoxModel\", \"styleText\", \"styleLayout\", \"styleBackground\", \"style\"]);\n\n      const styles = { ...styleBoxModel,\n        ...styleText,\n        ...styleLayout,\n        ...styleBackground,\n        ...style,\n      };\n\n      if (typeof children !== 'string') {\n        styles.display = 'inline-block';\n      }\n\n      return React.createElement(\"a\", _extends({}, otherProps, {\n        style: styles,\n      }), [children]);\n    },\n  }]);\n\n  return AIMakeLink;\n}(Component);\n\n_defineProperty(AIMakeLink, \"propTypes\", {\n  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),\n  styleBoxModel: PropTypes.object.isRequired,\n  styleText: PropTypes.object.isRequired,\n  styleLayout: PropTypes.object.isRequired,\n  styleBackground: PropTypes.object.isRequired,\n  style: PropTypes.object,\n});\n\n_defineProperty(AIMakeLink, \"defaultProps\", {\n  children: '',\n  style: {},\n});\n\nexport default HOCBoxModelProps(HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeLink))));"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.js",
    "content": "{\"componentName\":\"AIMakeLink\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"@ali/lowcode-engine-material-parser\",\"version\":\"0.1.0\",\"exportName\":\"AIMakeLink\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleText\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = function () {\n  return Promise.resolve(component);\n};\n\nexport default {\n  getComponent,\n  manifest: amManifest,\n};"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakePlaceholder',\n  // The description of current component.\n  description: '占位图',\n  // The coverimage's url of current component.\n  coverImage: 'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '占位图',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [{\n    alias: '占位图',\n    thumbnail: 'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',\n    colSpan: 24,\n    customProps: {\n      width: '224px',\n      height: '126px',\n      backgroundColor: '#FFF6E0',\n      textAlign: 'center',\n      border: '1px dashed rgb(170, 170, 170)',\n      children: '暂不支持此组件',\n    },\n  }],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'lr',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [{\n      name: 'margin',\n      label: '外边距',\n      renderer: 'Quadrant',\n    }, {\n      name: 'width',\n      label: '宽度',\n      defaultValue: '224px',\n      renderer: 'Width',\n    }, {\n      name: 'height',\n      label: '高度',\n      defaultValue: '126px',\n      renderer: 'Height',\n    }, {\n      name: 'backgroundColor',\n      label: '背景色',\n      defaultValue: '#FFF6E0',\n      renderer: false,\n    }, {\n      name: 'textAlign',\n      label: '对齐',\n      defaultValue: 'center',\n      renderer: false,\n    }, {\n      name: 'border',\n      label: '边框',\n      defaultValue: '1px dashed rgb(170, 170, 170)',\n      renderer: false,\n    }, {\n      name: 'children',\n      label: '内容',\n      defaultValue: '暂不支持此组件',\n      renderer: false,\n    }],\n  },\n};\nexport default manifest;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/container.js",
    "content": "\n      import AIMakePlaceholder from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: AIMakePlaceholder, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/index.js",
    "content": "import _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\n\nconst AIMakePlaceholder =\n/* #__PURE__ */\nfunction (_Component) {\n  _inherits(AIMakePlaceholder, _Component);\n\n  function AIMakePlaceholder() {\n    _classCallCheck(this, AIMakePlaceholder);\n\n    return _possibleConstructorReturn(this, _getPrototypeOf(AIMakePlaceholder).apply(this, arguments));\n  }\n\n  _createClass(AIMakePlaceholder, [{\n    key: \"render\",\n    value: function render() {\n      const _this$props = this.props;\n          const children = _this$props.children;\n          const styleBoxModel = _this$props.styleBoxModel;\n          const styleLayout = _this$props.styleLayout;\n          const style = _this$props.style;\n      const styles = { ...styleBoxModel,\n        ...styleLayout,\n        ...style,\n      };\n      const placeholderStyle = {\n        display: 'inline-block',\n        border: '1px dashed #aaa',\n        lineHeight: styles.height,\n        backgroundColor: '#F5E075',\n        overflow: 'hidden',\n        textAlign: 'center',\n        ...styles,\n      };\n      return React.createElement(\"div\", {\n        style: placeholderStyle,\n      }, children);\n    },\n  }]);\n\n  return AIMakePlaceholder;\n}(Component);\n\n_defineProperty(AIMakePlaceholder, \"propTypes\", {\n  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),\n  styleBoxModel: PropTypes.object.isRequired,\n  styleLayout: PropTypes.object.isRequired,\n  style: PropTypes.object,\n});\n\n_defineProperty(AIMakePlaceholder, \"defaultProps\", {\n  children: '',\n  style: {},\n});\n\nexport default HOCBoxModelProps(HOCLayoutProps(AIMakePlaceholder));"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.js",
    "content": "{\"componentName\":\"AIMakePlaceholder\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"@ali/lowcode-engine-material-parser\",\"version\":\"0.1.0\",\"exportName\":\"AIMakePlaceholder\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = function () {\n  return Promise.resolve(component);\n};\n\nexport default {\n  getComponent,\n  manifest: amManifest,\n};"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeText',\n  // The description of current component.\n  description: '富文本',\n  // The coverimage's url of current component.\n  coverImage: 'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '文本',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [{\n    alias: '富文本',\n    thumbnail: 'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',\n    colSpan: 12,\n    customProps: {\n      type: 'label',\n      fontSize: '12px',\n      fontWeight: 'normal',\n      children: '文本内容',\n    },\n  }],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'tbrl',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [{\n      name: 'type',\n      label: '类型',\n      renderer: 'Select',\n      defaultValue: 'label',\n      params: [{\n        label: '一级标题',\n        value: 'h1',\n      }, {\n        label: '二级标题',\n        value: 'h2',\n      }, {\n        label: '三级标题',\n        value: 'h3',\n      }, {\n        label: '段落',\n        value: 'p',\n      }, {\n        label: '标签',\n        value: 'label',\n      }],\n    }, {\n      name: 'margin',\n      label: '外边距',\n      renderer: 'Quadrant',\n    }, {\n      name: 'color',\n      label: '文字颜色',\n      renderer: 'Color',\n    }, {\n      name: 'fontSize',\n      label: '字号',\n      renderer: 'FontSize',\n      defaultValue: '12px',\n    }, {\n      name: 'fontWeight',\n      label: '字重',\n      renderer: 'FontWeight',\n      defaultValue: 'normal',\n    }, {\n      name: 'lineHeight',\n      label: '行高',\n      defaultValue: undefined,\n      renderer: 'LineHeight',\n    }, {\n      name: 'children',\n      label: '内容',\n      defaultValue: '文本内容',\n      renderer: 'TextArea',\n    }],\n  },\n};\nexport default manifest;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/container.js",
    "content": "\n      import AIMakeText from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: AIMakeText, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/index.js",
    "content": "import _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _assertThisInitialized from \"@babel/runtime/helpers/assertThisInitialized\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCTextProps from '../utils/HOCTextProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\nimport HOCBackgroundProps from '../utils/HOCBackgroundProps';\n\nconst AIMakeText =\n/* #__PURE__ */\nfunction (_Component) {\n  _inherits(AIMakeText, _Component);\n\n  function AIMakeText() {\n    let _this;\n\n    _classCallCheck(this, AIMakeText);\n\n    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n      args[_key] = arguments[_key];\n    }\n\n    _this = _possibleConstructorReturn(this, _getPrototypeOf(AIMakeText).call(this, ...args));\n\n    _defineProperty(_assertThisInitialized(_this), \"generateComponentType\", function (componentType) {\n      const componentNameMap = {\n        h1: 'h1',\n        h2: 'h2',\n        h3: 'h3',\n        h4: 'h4',\n        h5: 'h5',\n        paragraph: 'p',\n        label: 'label',\n      };\n      return componentNameMap[componentType] || 'div';\n    });\n\n    return _this;\n  }\n\n  _createClass(AIMakeText, [{\n    key: \"render\",\n    value: function render() {\n      const _this$props = this.props;\n          const children = _this$props.children;\n          const type = _this$props.type;\n          const styleBoxModel = _this$props.styleBoxModel;\n          const styleText = _this$props.styleText;\n          const styleLayout = _this$props.styleLayout;\n          const styleBackground = _this$props.styleBackground;\n          const style = _this$props.style;\n      const styles = { ...styleBoxModel,\n        ...styleText,\n        ...styleLayout,\n        ...styleBackground,\n        ...style,\n      };\n      const Comp = this.generateComponentType(type);\n      const labelStyle = Comp === 'label' ? {\n        display: 'inline-block',\n      } : {};\n      return React.createElement(Comp, {\n        className: \"AIMakeText\",\n        style: Object.assign(labelStyle, styles),\n      }, [children]);\n    },\n  }]);\n\n  return AIMakeText;\n}(Component);\n\n_defineProperty(AIMakeText, \"propTypes\", {\n  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node, PropTypes.string]),\n  type: PropTypes.string,\n  styleBoxModel: PropTypes.object.isRequired,\n  styleText: PropTypes.object.isRequired,\n  styleLayout: PropTypes.object.isRequired,\n  styleBackground: PropTypes.object.isRequired,\n  style: PropTypes.object,\n});\n\n_defineProperty(AIMakeText, \"defaultProps\", {\n  children: '',\n  type: '',\n  // paragraph || label\n  style: {},\n});\n\nexport default HOCBoxModelProps(HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeText))));"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.js",
    "content": "{\"componentName\":\"AIMakeText\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"@ali/lowcode-engine-material-parser\",\"version\":\"0.1.0\",\"exportName\":\"AIMakeText\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"type\",\"propType\":\"string\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleText\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = function () {\n  return Promise.resolve(component);\n};\n\nexport default {\n  getComponent,\n  manifest: amManifest,\n};"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amManifest.js",
    "content": "const manifest = {\n  name: 'Root',\n  description: '底板',\n  coverImage: '',\n  category: '',\n  presets: [],\n  settings: {\n    type: 'container',\n    insertionModes: 'v',\n    handles: ['paste'],\n    shouldActive: true,\n    shouldDrag: false,\n    props: [{\n      name: 'padding',\n      label: '内边距',\n      renderer: 'Quadrant',\n    }, {\n      name: 'backgroundColor',\n      label: '背景颜色',\n      defaultValue: '#F5F6FA',\n      renderer: 'Color',\n    }],\n  },\n};\nexport default manifest;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/container.js",
    "content": "\n      import Root from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: Root, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/index.js",
    "content": "import _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React from 'react';\nimport PropTypes from 'prop-types';\n\nconst Root =\n/* #__PURE__ */\nfunction (_React$Component) {\n  _inherits(Root, _React$Component);\n\n  function Root() {\n    _classCallCheck(this, Root);\n\n    return _possibleConstructorReturn(this, _getPrototypeOf(Root).apply(this, arguments));\n  }\n\n  _createClass(Root, [{\n    key: \"render\",\n    value: function render() {\n      const _this$props = this.props;\n          const style = _this$props.style;\n          const children = _this$props.children;\n      const newStyle = Object.assign({}, Root.defaultProps.style, style);\n      return React.createElement(\"div\", {\n        style: newStyle,\n      }, children);\n    },\n  }]);\n\n  return Root;\n}(React.Component);\n\n_defineProperty(Root, \"propTypes\", {\n  style: PropTypes.object,\n  children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),\n});\n\n_defineProperty(Root, \"defaultProps\", {\n  style: {\n    padding: 0,\n    backgroundColor: '#f0f2f5',\n    minHeight: '100%',\n  },\n  children: null,\n});\n\nexport default Root;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.js",
    "content": "{\"componentName\":\"Root\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"@ali/lowcode-engine-material-parser\",\"version\":\"0.1.0\",\"exportName\":\"Root\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{\\n  padding: 0,\\n  backgroundColor: '#f0f2f5',\\n  minHeight: '100%'\\n}\"},{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.css",
    "content": ".text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.js",
    "content": "import \"./index.css\";"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.less",
    "content": "// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n.text-nowrap         { white-space: nowrap; }\n\n// BoxModel"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBackgroundProps.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _assertThisInitialized from \"@babel/runtime/helpers/assertThisInitialized\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n/**\n * (HOC)注入背景相关属性配置\n * 包含 'backgroundColor'\n * @param {*} WrappedComponent\n */\n\nconst HOCBackgroundProps = function (WrappedComponent) {\n  let _class; let _temp;\n\n  const PROPS = {\n    backgroundColor: 'backgroundColor',\n  };\n  return _temp = _class =\n  /* #__PURE__ */\n  function (_Component) {\n    _inherits(_class, _Component);\n\n    function _class() {\n      let _this;\n\n      _classCallCheck(this, _class);\n\n      for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {\n        _args[_key] = arguments[_key];\n      }\n\n      _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));\n\n      _defineProperty(_assertThisInitialized(_this), \"parseStyle\", function (args) {\n        const style = {};\n        Object.keys(PROPS).forEach(function (item) {\n          // if props isn't false\n          if (!args[item]) return;\n          style[PROPS[item]] = args[item];\n        });\n        return style;\n      });\n\n      return _this;\n    }\n\n    _createClass(_class, [{\n      key: \"render\",\n      value: function render() {\n        const _this$props = this.props;\n            const backgroundColor = _this$props.backgroundColor;\n            const otherProps = _objectWithoutProperties(_this$props, [\"backgroundColor\"]);\n\n        return React.createElement(WrappedComponent, _extends({}, otherProps, {\n          styleBackground: this.parseStyle(this.props),\n        }));\n      },\n    }]);\n\n    return _class;\n  }(Component), _defineProperty(_class, \"propTypes\", {\n    backgroundColor: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n  }), _defineProperty(_class, \"defaultProps\", {\n    backgroundColor: false,\n  }), _temp;\n};\n\nexport default HOCBackgroundProps;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBoxModelProps.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _assertThisInitialized from \"@babel/runtime/helpers/assertThisInitialized\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nconst parseJoin = function (value) {\n  return value.join(' ');\n};\n/**\n * (HOC)注入盒子模型相关属性配置\n * 包含 'display', 'margin', 'border', 'padding', 'width', 'height', 'borderRadius'\n * @param {*} WrappedComponent\n */\n\n\nconst HOCBoxModelProps = function (WrappedComponent) {\n  let _class; let _temp;\n\n  const PROPS = {\n    display: 'display',\n    margin: 'margin',\n    border: 'border',\n    padding: 'padding',\n    width: 'width',\n    height: 'height',\n    borderRadius: 'borderRadius',\n  };\n  return _temp = _class =\n  /* #__PURE__ */\n  function (_Component) {\n    _inherits(_class, _Component);\n\n    function _class() {\n      let _this;\n\n      _classCallCheck(this, _class);\n\n      for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {\n        _args[_key] = arguments[_key];\n      }\n\n      _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));\n\n      _defineProperty(_assertThisInitialized(_this), \"parseStyle\", function (args) {\n        const style = {};\n        Object.keys(PROPS).forEach(function (item) {\n          // if props isn't false\n          if (!args[item]) return;\n          style[PROPS[item]] = Array.isArray(args[item]) ? parseJoin(args[item]) : args[item];\n        });\n        return style;\n      });\n\n      return _this;\n    }\n\n    _createClass(_class, [{\n      key: \"render\",\n      value: function render() {\n        const _this$props = this.props;\n            const display = _this$props.display;\n            const margin = _this$props.margin;\n            const border = _this$props.border;\n            const padding = _this$props.padding;\n            const width = _this$props.width;\n            const height = _this$props.height;\n            const borderRadius = _this$props.borderRadius;\n            const otherProps = _objectWithoutProperties(_this$props, [\"display\", \"margin\", \"border\", \"padding\", \"width\", \"height\", \"borderRadius\"]);\n\n        return React.createElement(WrappedComponent, _extends({}, otherProps, {\n          styleBoxModel: this.parseStyle(this.props),\n        }));\n      },\n    }]);\n\n    return _class;\n  }(Component), _defineProperty(_class, \"propTypes\", {\n    display: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    margin: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),\n    border: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),\n    padding: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),\n    width: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    height: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    borderRadius: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n  }), _defineProperty(_class, \"defaultProps\", {\n    display: false,\n    margin: false,\n    border: false,\n    padding: false,\n    width: false,\n    height: false,\n    borderRadius: false,\n  }), _temp;\n};\n\nexport default HOCBoxModelProps;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCFlexLayoutProps.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _assertThisInitialized from \"@babel/runtime/helpers/assertThisInitialized\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n/**\n * (HOC)注入flex布局相关属性配置\n * 包含 'alignItems', 'justifyContent', 'flexDirection'\n * @param {*} WrappedComponent\n */\n\nconst HOCFlexLayoutProps = function (WrappedComponent) {\n  let _class; let _temp;\n\n  const PROPS = {\n    alignItems: 'alignItems',\n    justifyContent: 'justifyContent',\n    flexDirection: 'flexDirection',\n    flexWrap: 'flexWrap',\n  };\n  return _temp = _class =\n  /* #__PURE__ */\n  function (_Component) {\n    _inherits(_class, _Component);\n\n    function _class() {\n      let _this;\n\n      _classCallCheck(this, _class);\n\n      for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {\n        _args[_key] = arguments[_key];\n      }\n\n      _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));\n\n      _defineProperty(_assertThisInitialized(_this), \"parseStyle\", function (args) {\n        const style = {};\n\n        if (args.style && args.style.display === 'flex') {\n          Object.keys(PROPS).forEach(function (item) {\n            // if props isn't false\n            if (!args[item]) return;\n            style[PROPS[item]] = args[item];\n          });\n        }\n\n        return style;\n      });\n\n      return _this;\n    }\n\n    _createClass(_class, [{\n      key: \"render\",\n      value: function render() {\n        const _this$props = this.props;\n            const alignItems = _this$props.alignItems;\n            const justifyContent = _this$props.justifyContent;\n            const flexDirection = _this$props.flexDirection;\n            const flexWrap = _this$props.flexWrap;\n            const otherProps = _objectWithoutProperties(_this$props, [\"alignItems\", \"justifyContent\", \"flexDirection\", \"flexWrap\"]);\n\n        return React.createElement(WrappedComponent, _extends({}, otherProps, {\n          styleFlexLayout: this.parseStyle(this.props),\n        }));\n      },\n    }]);\n\n    return _class;\n  }(Component), _defineProperty(_class, \"propTypes\", {\n    alignItems: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    justifyContent: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    flexDirection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    flexWrap: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n  }), _defineProperty(_class, \"defaultProps\", {\n    alignItems: false,\n    justifyContent: false,\n    flexDirection: false,\n    flexWrap: false,\n  }), _temp;\n};\n\nexport default HOCFlexLayoutProps;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCLayoutProps.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _assertThisInitialized from \"@babel/runtime/helpers/assertThisInitialized\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n/**\n * (HOC)注入布局相关属性配置\n * 包含 'align', 'lineHeight', 'verticalAlign'\n * @param {*} WrappedComponent\n */\n\nconst HOCLayoutProps = function (WrappedComponent) {\n  let _class; let _temp;\n\n  const PROPS = {\n    align: 'textAlign',\n    lineHeight: 'lineHeight',\n    verticalAlign: 'verticalAlign',\n  };\n  return _temp = _class =\n  /* #__PURE__ */\n  function (_Component) {\n    _inherits(_class, _Component);\n\n    function _class() {\n      let _this;\n\n      _classCallCheck(this, _class);\n\n      for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {\n        _args[_key] = arguments[_key];\n      }\n\n      _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));\n\n      _defineProperty(_assertThisInitialized(_this), \"parseStyle\", function (args) {\n        const style = {};\n        Object.keys(PROPS).forEach(function (item) {\n          // if props isn't false\n          if (!args[item]) return;\n          style[PROPS[item]] = args[item];\n        });\n        return style;\n      });\n\n      return _this;\n    }\n\n    _createClass(_class, [{\n      key: \"render\",\n      value: function render() {\n        const _this$props = this.props;\n            const align = _this$props.align;\n            const lineHeight = _this$props.lineHeight;\n            const verticalAlign = _this$props.verticalAlign;\n            const otherProps = _objectWithoutProperties(_this$props, [\"align\", \"lineHeight\", \"verticalAlign\"]);\n\n        return React.createElement(WrappedComponent, _extends({}, otherProps, {\n          styleLayout: this.parseStyle(this.props),\n        }));\n      },\n    }]);\n\n    return _class;\n  }(Component), _defineProperty(_class, \"propTypes\", {\n    align: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    lineHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    verticalAlign: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n  }), _defineProperty(_class, \"defaultProps\", {\n    align: false,\n    lineHeight: false,\n    verticalAlign: false,\n  }), _temp;\n};\n\nexport default HOCLayoutProps;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCTextProps.js",
    "content": "import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutProperties from \"@babel/runtime/helpers/objectWithoutProperties\";\nimport _classCallCheck from \"@babel/runtime/helpers/classCallCheck\";\nimport _createClass from \"@babel/runtime/helpers/createClass\";\nimport _possibleConstructorReturn from \"@babel/runtime/helpers/possibleConstructorReturn\";\nimport _getPrototypeOf from \"@babel/runtime/helpers/getPrototypeOf\";\nimport _assertThisInitialized from \"@babel/runtime/helpers/assertThisInitialized\";\nimport _inherits from \"@babel/runtime/helpers/inherits\";\nimport _defineProperty from \"@babel/runtime/helpers/defineProperty\";\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n/**\n * (HOC)注入文本相关属性配置\n * 包含 'fontSize', 'fontWeight', 'color'\n * @param {*} WrappedComponent\n */\n\nconst HOCTextProps = function (WrappedComponent) {\n  let _class; let _temp;\n\n  const PROPS = {\n    fontSize: 'fontSize',\n    fontWeight: 'fontWeight',\n    color: 'color',\n  };\n  return _temp = _class =\n  /* #__PURE__ */\n  function (_Component) {\n    _inherits(_class, _Component);\n\n    function _class() {\n      let _this;\n\n      _classCallCheck(this, _class);\n\n      for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {\n        _args[_key] = arguments[_key];\n      }\n\n      _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));\n\n      _defineProperty(_assertThisInitialized(_this), \"parseStyle\", function (args) {\n        const style = {};\n        Object.keys(PROPS).forEach(function (item) {\n          // if props isn't false\n          if (!args[item]) return;\n          style[PROPS[item]] = args[item];\n        });\n        return style;\n      });\n\n      return _this;\n    }\n\n    _createClass(_class, [{\n      key: \"render\",\n      value: function render() {\n        const _this$props = this.props;\n            const fontSize = _this$props.fontSize;\n            const fontWeight = _this$props.fontWeight;\n            const color = _this$props.color;\n            const otherProps = _objectWithoutProperties(_this$props, [\"fontSize\", \"fontWeight\", \"color\"]);\n\n        return React.createElement(WrappedComponent, _extends({}, otherProps, {\n          styleText: this.parseStyle(this.props),\n        }));\n      },\n    }]);\n\n    return _class;\n  }(Component), _defineProperty(_class, \"propTypes\", {\n    fontSize: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    color: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n  }), _defineProperty(_class, \"defaultProps\", {\n    fontSize: false,\n    fontWeight: false,\n    color: false,\n  }), _temp;\n};\n\nexport default HOCTextProps;"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/es/index.js",
    "content": "import AIMakeBlank from './basic/AIMakeBlank';\nimport AIMakeIcon from './basic/AIMakeIcon';\nimport AIMakeImage from './basic/AIMakeImage';\nimport AIMakeLink from './basic/AIMakeLink';\nimport AIMakePlaceholder from './basic/AIMakePlaceholder';\nimport AIMakeText from './basic/AIMakeText';\nimport Root from './basic/Root';\n\nexport { AIMakeBlank, AIMakeIcon, AIMakeImage, AIMakeLink, AIMakePlaceholder, AIMakeText, Root };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/package.json",
    "content": "{\n  \"name\": \"multiple-exported-component\",\n  \"description\": \"提供最基础、通用的物料组件\",\n  \"version\": \"1.0.0\",\n  \"main\": \"es/index.js\",\n  \"module\": \"es/index.js\",\n  \"dependencies\": {\n    \"classnames\": \"^2.2.6\",\n    \"prop-types\": \"^15.7.2\",\n    \"react\": \"^16.8.5\",\n    \"react-dom\": \"^16.8.5\"\n  },\n  \"devDependencies\": {\n    \"cross-spawn\": \"^6.0.5\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.6\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npm.alibaba-inc.com\"\n  }\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = () => Promise.resolve(component);\n\nexport default { getComponent, manifest: amManifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\n\nfunction _update(Nygma, node) {\n  const attributes = node.get();\n  const {\n    display,\n    flexDirection,\n    alignItems,\n    justifyContent,\n    flexWrap,\n  } = attributes;\n  const isFlex = display === 'flex';\n  node.set({\n    display,\n    flexDirection: isFlex ? flexDirection : undefined,\n    alignItems: isFlex ? alignItems : undefined,\n    justifyContent: isFlex ? justifyContent : undefined,\n    flexWrap: isFlex ? flexWrap : undefined,\n  });\n}\n\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeBlank',\n  // The description of current component.\n  description: '空白卡片',\n  // The coverimage's url of current component.\n  coverImage:\n    'https://img.alicdn.com/tfs/TB1un9tqntYBeNjy1XdXXXXyVXa-366-124.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '布局', // card.blank\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [\n    {\n      alias: '空白卡片',\n      thumbnail:\n        'https://img.alicdn.com/tfs/TB1ucPNVsbpK1RjSZFyXXX_qFXa-198-120.png',\n      colSpan: 12,\n      customProps: {\n        id: '',\n        textAlign: 'left',\n        padding: '12px',\n        width: '100%',\n        backgroundColor: '#FFF',\n      },\n    },\n  ],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'container',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'tbrlv',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    lifeCycle: {\n      didMount: (props) => {\n        const { Nygma, dragInstance } = props;\n        const Drager = dragInstance.NygmaNode;\n        _update(Nygma, Drager);\n      },\n      didUpdate: (Nygma, node, args) => {\n        const newvalue = args[1];\n        const oldvalue = args[2];\n        if (JSON.stringify(newvalue) !== JSON.stringify(oldvalue)) {\n          _update(Nygma, node);\n        }\n      },\n    },\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [\n      {\n        name: 'id',\n        label: 'id',\n        defaultValue: '',\n        renderer: 'Input',\n      },\n      {\n        name: 'textAlign',\n        label: '水平对齐',\n        defaultValue: 'left',\n        renderer: 'TextAlign',\n      },\n      {\n        name: 'margin',\n        label: '外边距',\n        renderer: 'Quadrant',\n      },\n      {\n        name: 'padding',\n        label: '内边距',\n        renderer: 'Quadrant',\n        defaultValue: '12px',\n      },\n      {\n        name: 'width',\n        label: '宽度',\n        defaultValue: '100%',\n        renderer: 'Width',\n      },\n      {\n        name: 'height',\n        label: '高度',\n        renderer: 'Height',\n        defaultValue: undefined,\n      },\n      {\n        name: 'backgroundColor',\n        label: '背景颜色',\n        renderer: 'Color',\n        defaultValue: '#FFF',\n      },\n      {\n        name: 'border',\n        label: '边框',\n        renderer: 'BarBorder',\n      },\n      {\n        name: 'display',\n        label: '布局设置',\n        renderer: 'FlexLayout',\n      },\n    ],\n  },\n};\n\nexport default manifest;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/container.js",
    "content": "\nimport AIMakeBlank from '../../../es/basic/AIMakeBlank/index.js';\nimport manifest from './manifest.js';\n\nexport default { origin: AIMakeBlank, manifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\nimport HOCBackgroundProps from '../utils/HOCBackgroundProps';\nimport HOCFlexLayoutProps from '../utils/HOCFlexLayoutProps';\n\nclass AIMakeBlank extends Component {\n  static propTypes = {\n    children: PropTypes.oneOfType([\n      PropTypes.arrayOf(PropTypes.node),\n      PropTypes.node,\n    ]),\n    styleBoxModel: PropTypes.object.isRequired,\n    styleLayout: PropTypes.object.isRequired,\n    styleBackground: PropTypes.object.isRequired,\n    styleFlexLayout: PropTypes.object.isRequired,\n    style: PropTypes.object,\n    id: PropTypes.string,\n  };\n\n  static defaultProps = {\n    children: [],\n    style: {},\n    id: '',\n  };\n\n  render() {\n    const merged = {};\n    const {\n      children,\n      styleBoxModel,\n      styleLayout,\n      styleBackground,\n      styleFlexLayout,\n      style,\n      id,\n    } = this.props;\n\n    const styles = {\n      ...styleBoxModel,\n      ...styleLayout,\n      ...styleBackground,\n      ...styleFlexLayout,\n      ...style,\n    };\n    if (id) {\n      merged.id = id;\n    }\n    return (\n      <div style={styles} {...merged}>\n        {children}\n      </div>\n    );\n  }\n}\n\nexport default HOCBoxModelProps(\n  HOCLayoutProps(HOCBackgroundProps(HOCFlexLayoutProps(AIMakeBlank))),\n);\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.js",
    "content": "{\"componentName\":\"AIMakeBlank\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"AIMakeBlank\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleFlexLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"},{\"name\":\"id\",\"propType\":\"string\",\"description\":\"\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/IconFont.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\n// 缓存已加载的字体文件\nconst customCache = new Set();\n\n// 动态加载字体文件\nexport default function createFromIconfont(options) {\n  const { scriptUrl } = options;\n  if (\n    typeof document !== 'undefined'\n    && typeof window !== 'undefined'\n    && typeof document.createElement === 'function'\n    && typeof scriptUrl === 'string'\n    && scriptUrl.length\n    && !customCache.has(scriptUrl)\n  ) {\n    const script = document.createElement('script');\n    script.setAttribute('src', scriptUrl);\n    script.setAttribute('data-namespace', scriptUrl);\n    customCache.add(scriptUrl);\n    document.body.appendChild(script);\n  }\n\n  class IconFont extends Component {\n    render() {\n      const { type, ...restProps } = this.props;\n      const innerSvgProps = {\n        width: '1em',\n        height: '1em',\n        fill: 'currentColor',\n        'aria-hidden': 'true',\n        focusable: 'false',\n      };\n      // 引用指定svg\n      const content = <use xlinkHref={`#${type}`} />;\n\n      return (\n        <i {...restProps} className={`iconfont ${type}`}>\n          <svg {...innerSvgProps}>{content}</svg>\n        </i>\n      );\n    }\n  }\n\n  IconFont.propTypes = {\n    type: PropTypes.string.isRequired, // icon\n  };\n\n  return IconFont;\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\nimport createFromIconfont from './IconFont';\n\nconst getComponent = () => Promise.resolve(component);\n\nexport default { getComponent, manifest: amManifest, createFromIconfont };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeIcon',\n  // The description of current component.\n  description: '图标',\n  // The coverimage's url of current component.\n  coverImage: '',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: 'AIMakeIcon',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'rl',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [\n      {\n        name: 'margin',\n        label: '外边距',\n        renderer: 'Quadrant',\n      },\n      {\n        name: 'color',\n        label: '图标颜色',\n        renderer: 'Color',\n        defaultValue: '#333',\n      },\n      {\n        name: 'fontSize',\n        label: '图标大小',\n        renderer: 'FontSize',\n        defaultValue: '16px',\n      },\n      {\n        name: 'display',\n        label: '显示',\n        defaultValue: 'inline-block',\n      },\n      {\n        name: 'className',\n        label: '图标类型',\n        defaultValue: 'iconfont',\n        renderer: false,\n        params: {\n          placeholder: '请输入Iconfont名',\n        },\n      },\n    ],\n  },\n};\n\nexport default manifest;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/container.js",
    "content": "\nimport AIMakeIcon from '../../../es/basic/AIMakeIcon/index.js';\nimport manifest from './manifest.js';\n\nexport default { origin: AIMakeIcon, manifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\n\nimport createFromIconfont from './IconFont';\n\nclass AIMakeIcon extends Component {\n  static propTypes = {\n    className: PropTypes.string,\n    iconClassName: PropTypes.string,\n    children: PropTypes.oneOfType([\n      PropTypes.arrayOf(PropTypes.node),\n      PropTypes.node,\n    ]),\n    styleBoxModel: PropTypes.object.isRequired,\n    styleText: PropTypes.object.isRequired,\n    styleBackground: PropTypes.object.isRequired,\n    style: PropTypes.object,\n  };\n\n  static defaultProps = {\n    className: '',\n    iconClassName: 'iconfont',\n    children: '',\n    style: {},\n  };\n\n  render() {\n    const {\n      className,\n      iconClassName,\n      children,\n      styleBoxModel,\n      styleText,\n      styleBackground,\n      style,\n      ...otherProps\n    } = this.props;\n    const styles = {\n      ...styleBoxModel,\n      ...styleText,\n      ...styleBackground,\n      ...style,\n    };\n    return (\n      <i\n        {...otherProps}\n        className={classNames(className, iconClassName)}\n        style={styles}\n      >\n        {children}\n      </i>\n    );\n  }\n}\n\nAIMakeIcon.createFromIconfont = createFromIconfont;\n\nexport default AIMakeIcon;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.js",
    "content": "{\"componentName\":\"AIMakeIcon\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"AIMakeIcon\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"className\",\"propType\":\"string\",\"description\":\"\"},{\"name\":\"iconClassName\",\"propType\":\"string\",\"description\":\"\"},{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleText\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = () => Promise.resolve(component);\n\nexport default { getComponent, manifest: amManifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeImage',\n  // The description of current component.\n  description: '图片',\n  // The coverimage's url of current component.\n  coverImage:\n    'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '线条图像',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [\n    {\n      alias: '图片',\n      thumbnail:\n        'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',\n      colSpan: 12,\n      customProps: {\n        width: '224px',\n        height: '126px',\n        src:\n          'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',\n      },\n    },\n  ],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'rl',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [\n      {\n        name: 'margin',\n        label: '外边距',\n        renderer: 'Quadrant',\n      },\n      {\n        name: 'width',\n        label: '宽度',\n        defaultValue: '224px',\n        renderer: 'Width',\n      },\n      {\n        name: 'height',\n        label: '高度',\n        defaultValue: '126px',\n        renderer: 'Height',\n      },\n      {\n        name: 'src',\n        label: '图片URL',\n        renderer: 'Uploader',\n        placeholder:\n          'eg: https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',\n        hint: '请填入图片的URL',\n        defaultValue:\n          'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',\n      },\n    ],\n  },\n};\n\nexport default manifest;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/container.js",
    "content": "\nimport AIMakeImage from '../../../es/basic/AIMakeImage/index.js';\nimport manifest from './manifest.js';\n\nexport default { origin: AIMakeImage, manifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\n\nclass AIMakeImage extends Component {\n  static propTypes = {\n    styleBoxModel: PropTypes.object.isRequired,\n    style: PropTypes.object,\n  };\n\n  static defaultProps = {\n    style: {},\n  };\n\n  render() {\n    const { styleBoxModel, style, ...otherProps } = this.props;\n    const styles = {\n      ...styleBoxModel,\n      ...style,\n    };\n    return <img {...otherProps} style={styles} alt=\"AIMakeImage\" />;\n  }\n}\n\nexport default HOCBoxModelProps(AIMakeImage);\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.js",
    "content": "{\"componentName\":\"AIMakeImage\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"AIMakeImage\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = () => Promise.resolve(component);\n\nexport default { getComponent, manifest: amManifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeLink',\n  // The description of current component.\n  description: '链接',\n  // The coverimage's url of current component.\n  coverImage:\n    'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '文本',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [\n    {\n      alias: '链接',\n      thumbnail:\n        'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',\n      colSpan: 12,\n      customProps: {\n        color: '#3788FF',\n        fontSize: '12px',\n        fontWeight: 'normal',\n        href: '#',\n        children: '链接',\n      },\n    },\n  ],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'lrv',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [\n      {\n        name: 'margin',\n        label: '外边距',\n        renderer: 'Quadrant',\n      },\n      {\n        name: 'color',\n        label: '文字颜色',\n        renderer: 'Color',\n        defaultValue: '#3788FF',\n      },\n      {\n        name: 'fontSize',\n        label: '字号',\n        renderer: 'FontSize',\n        defaultValue: '12px',\n      },\n      {\n        name: 'fontWeight',\n        label: '字重',\n        renderer: 'FontWeight',\n        defaultValue: 'normal',\n      },\n      {\n        name: 'lineHeight',\n        label: '行高',\n        defaultValue: undefined,\n        renderer: 'LineHeight',\n      },\n      {\n        name: 'href',\n        label: '链接URL',\n        renderer: 'Input',\n        placeholder: '请输入链接URL',\n        defaultValue: '#',\n      },\n      {\n        name: 'children',\n        label: '内容',\n        defaultValue: '链接',\n        renderer: 'TextArea',\n      },\n    ],\n  },\n};\n\nexport default manifest;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/container.js",
    "content": "\nimport AIMakeLink from '../../../es/basic/AIMakeLink/index.js';\nimport manifest from './manifest.js';\n\nexport default { origin: AIMakeLink, manifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCTextProps from '../utils/HOCTextProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\nimport HOCBackgroundProps from '../utils/HOCBackgroundProps';\n\nclass AIMakeLink extends Component {\n  static propTypes = {\n    children: PropTypes.oneOfType([\n      PropTypes.arrayOf(PropTypes.node),\n      PropTypes.node,\n    ]),\n    styleBoxModel: PropTypes.object.isRequired,\n    styleText: PropTypes.object.isRequired,\n    styleLayout: PropTypes.object.isRequired,\n    styleBackground: PropTypes.object.isRequired,\n    style: PropTypes.object,\n  };\n\n  static defaultProps = {\n    children: '',\n    style: {},\n  };\n\n  render() {\n    const {\n      children,\n      styleBoxModel,\n      styleText,\n      styleLayout,\n      styleBackground,\n      style,\n      ...otherProps\n    } = this.props;\n    const styles = {\n      ...styleBoxModel,\n      ...styleText,\n      ...styleLayout,\n      ...styleBackground,\n      ...style,\n    };\n    if (typeof children !== 'string') {\n      styles.display = 'inline-block';\n    }\n    return (\n      <a {...otherProps} style={styles}>\n        {[children]}\n      </a>\n    );\n  }\n}\n\nexport default HOCBoxModelProps(\n  HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeLink))),\n);\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.js",
    "content": "{\"componentName\":\"AIMakeLink\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"AIMakeLink\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleText\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = () => Promise.resolve(component);\n\nexport default { getComponent, manifest: amManifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakePlaceholder',\n  // The description of current component.\n  description: '占位图',\n  // The coverimage's url of current component.\n  coverImage:\n    'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '占位图',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [\n    {\n      alias: '占位图',\n      thumbnail:\n        'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',\n      colSpan: 24,\n      customProps: {\n        width: '224px',\n        height: '126px',\n        backgroundColor: '#FFF6E0',\n        textAlign: 'center',\n        border: '1px dashed rgb(170, 170, 170)',\n        children: '暂不支持此组件',\n      },\n    },\n  ],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'lr',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [\n      {\n        name: 'margin',\n        label: '外边距',\n        renderer: 'Quadrant',\n      },\n      {\n        name: 'width',\n        label: '宽度',\n        defaultValue: '224px',\n        renderer: 'Width',\n      },\n      {\n        name: 'height',\n        label: '高度',\n        defaultValue: '126px',\n        renderer: 'Height',\n      },\n      {\n        name: 'backgroundColor',\n        label: '背景色',\n        defaultValue: '#FFF6E0',\n        renderer: false,\n      },\n      {\n        name: 'textAlign',\n        label: '对齐',\n        defaultValue: 'center',\n        renderer: false,\n      },\n      {\n        name: 'border',\n        label: '边框',\n        defaultValue: '1px dashed rgb(170, 170, 170)',\n        renderer: false,\n      },\n      {\n        name: 'children',\n        label: '内容',\n        defaultValue: '暂不支持此组件',\n        renderer: false,\n      },\n    ],\n  },\n};\n\nexport default manifest;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/container.js",
    "content": "\nimport AIMakePlaceholder from '../../../es/basic/AIMakePlaceholder/index.js';\nimport manifest from './manifest.js';\n\nexport default { origin: AIMakePlaceholder, manifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\n\nclass AIMakePlaceholder extends Component {\n  static propTypes = {\n    children: PropTypes.oneOfType([\n      PropTypes.arrayOf(PropTypes.node),\n      PropTypes.node,\n    ]),\n    styleBoxModel: PropTypes.object.isRequired,\n    styleLayout: PropTypes.object.isRequired,\n    style: PropTypes.object,\n  };\n\n  static defaultProps = {\n    children: '',\n    style: {},\n  };\n\n  render() {\n    const {\n      children, styleBoxModel, styleLayout, style,\n    } = this.props;\n    const styles = {\n      ...styleBoxModel,\n      ...styleLayout,\n      ...style,\n    };\n    const placeholderStyle = {\n      display: 'inline-block',\n      border: '1px dashed #aaa',\n      lineHeight: styles.height,\n      backgroundColor: '#F5E075',\n      overflow: 'hidden',\n      textAlign: 'center',\n      ...styles,\n    };\n    return <div style={placeholderStyle}>{children}</div>;\n  }\n}\n\nexport default HOCBoxModelProps(HOCLayoutProps(AIMakePlaceholder));\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.js",
    "content": "{\"componentName\":\"AIMakePlaceholder\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"AIMakePlaceholder\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = () => Promise.resolve(component);\n\nexport default { getComponent, manifest: amManifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amManifest.js",
    "content": "/**\n * The template of manifest for AiMake studio.\n */\nconst manifest = {\n  // The name of current component.\n  name: 'AIMakeText',\n  // The description of current component.\n  description: '富文本',\n  // The coverimage's url of current component.\n  coverImage:\n    'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',\n  // The category of current component in AiMake studio.\n  // can be:\n  // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`\n  // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`\n  // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`\n  // or `树控件` or `折叠面板` or `占位图`\n  category: '文本',\n  // The preview list of current component in AiMake studio.\n  // Each preset contains following keys:\n  // - `alias`: string. required. The previewing component's name to display\n  // - `thumbnail`: string. not required. The previewing component's thumbnail\n  // - `customProps`: object. not required.\n  // The previewing component's customize props, e.g. { [propName]: [propValue] }\n  // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display\n  presets: [\n    {\n      alias: '富文本',\n      thumbnail:\n        'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',\n      colSpan: 12,\n      customProps: {\n        type: 'label',\n        fontSize: '12px',\n        fontWeight: 'normal',\n        children: '文本内容',\n      },\n    },\n  ],\n  // Other settings of current component for AiMake studio.\n  settings: {\n    // The render type of current component in AiMake studio.\n    // can be:\n    // `element_inline` or `element_block` or `container`\n    type: 'element_inline',\n    // The insert mode of current component in AiMake studio.\n    // can be:\n    // one or combine of `t` and `b` and `r` and `l`\n    insertionModes: 'tbrl',\n    // The handle list of current component in AiMake studio.\n    // can be:\n    // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']\n    handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],\n    // Whether the component can be actived.\n    shouldActive: true,\n    // Whether the component can be dragged.\n    shouldDrag: true,\n    // The props of current component in AiMake studio.\n    // Each property contains following keys:\n    // - `name`: string. required. The property's name\n    // - `label`: string. required. The property's name to display\n    // - `renderer`: string. required. The property's editor. can be: (@冰骊)\n    // - `defaultValue`: any. not required. The property's default value\n    // - `params`: any. not required. The parameters for property's editor\n    // - `placeholder`: string. not required. The placeholder for property's editor\n    // - `hint`: string. not required. The hint for property's editor\n    props: [\n      {\n        name: 'type',\n        label: '类型',\n        renderer: 'Select',\n        defaultValue: 'label',\n        params: [\n          { label: '一级标题', value: 'h1' },\n          { label: '二级标题', value: 'h2' },\n          { label: '三级标题', value: 'h3' },\n          { label: '段落', value: 'p' },\n          { label: '标签', value: 'label' },\n        ],\n      },\n      {\n        name: 'margin',\n        label: '外边距',\n        renderer: 'Quadrant',\n      },\n      {\n        name: 'color',\n        label: '文字颜色',\n        renderer: 'Color',\n      },\n      {\n        name: 'fontSize',\n        label: '字号',\n        renderer: 'FontSize',\n        defaultValue: '12px',\n      },\n      {\n        name: 'fontWeight',\n        label: '字重',\n        renderer: 'FontWeight',\n        defaultValue: 'normal',\n      },\n      {\n        name: 'lineHeight',\n        label: '行高',\n        defaultValue: undefined,\n        renderer: 'LineHeight',\n      },\n      {\n        name: 'children',\n        label: '内容',\n        defaultValue: '文本内容',\n        renderer: 'TextArea',\n      },\n    ],\n  },\n};\n\nexport default manifest;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/container.js",
    "content": "\nimport AIMakeText from '../../../es/basic/AIMakeText/index.js';\nimport manifest from './manifest.js';\n\nexport default { origin: AIMakeText, manifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nimport HOCBoxModelProps from '../utils/HOCBoxModelProps';\nimport HOCTextProps from '../utils/HOCTextProps';\nimport HOCLayoutProps from '../utils/HOCLayoutProps';\nimport HOCBackgroundProps from '../utils/HOCBackgroundProps';\n\nclass AIMakeText extends Component {\n  static propTypes = {\n    children: PropTypes.oneOfType([\n      PropTypes.arrayOf(PropTypes.node),\n      PropTypes.node,\n      PropTypes.string,\n    ]),\n    type: PropTypes.string,\n    styleBoxModel: PropTypes.object.isRequired,\n    styleText: PropTypes.object.isRequired,\n    styleLayout: PropTypes.object.isRequired,\n    styleBackground: PropTypes.object.isRequired,\n    style: PropTypes.object,\n  };\n\n  static defaultProps = {\n    children: '',\n    type: '', // paragraph || label\n    style: {},\n  };\n\n  generateComponentType = (componentType) => {\n    const componentNameMap = {\n      h1: 'h1',\n      h2: 'h2',\n      h3: 'h3',\n      h4: 'h4',\n      h5: 'h5',\n      paragraph: 'p',\n      label: 'label',\n    };\n    return componentNameMap[componentType] || 'div';\n  };\n\n  render() {\n    const {\n      children,\n      type,\n      styleBoxModel,\n      styleText,\n      styleLayout,\n      styleBackground,\n      style,\n    } = this.props;\n    const styles = {\n      ...styleBoxModel,\n      ...styleText,\n      ...styleLayout,\n      ...styleBackground,\n      ...style,\n    };\n    const Comp = this.generateComponentType(type);\n    const labelStyle = Comp === 'label' ? { display: 'inline-block' } : {};\n    return (\n      <Comp className=\"AIMakeText\" style={Object.assign(labelStyle, styles)}>\n        {[children]}\n      </Comp>\n    );\n  }\n}\n\nexport default HOCBoxModelProps(\n  HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeText))),\n);\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.js",
    "content": "{\"componentName\":\"AIMakeText\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"AIMakeText\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"type\",\"propType\":\"string\",\"description\":\"\"},{\"name\":\"styleBoxModel\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleText\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleLayout\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"styleBackground\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{}\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amContainer.js",
    "content": "import component from './index.js';\nimport amManifest from './amManifest.js';\n\nconst getComponent = () => Promise.resolve(component);\n\nexport default { getComponent, manifest: amManifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amManifest.js",
    "content": "const manifest = {\n  name: 'Root',\n  description: '底板',\n  coverImage: '',\n  category: '',\n  presets: [],\n  settings: {\n    type: 'container',\n    insertionModes: 'v',\n    handles: ['paste'],\n    shouldActive: true,\n    shouldDrag: false,\n    props: [\n      {\n        name: 'padding',\n        label: '内边距',\n        renderer: 'Quadrant',\n      },\n      {\n        name: 'backgroundColor',\n        label: '背景颜色',\n        defaultValue: '#F5F6FA',\n        renderer: 'Color',\n      },\n    ],\n  },\n};\n\nexport default manifest;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/container.js",
    "content": "\nimport Root from '../../../es/basic/Root/index.js';\nimport manifest from './manifest.js';\n\nexport default { origin: Root, manifest };\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/index.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nclass Root extends React.Component {\n  static propTypes = {\n    style: PropTypes.object,\n    children: PropTypes.oneOfType([\n      PropTypes.element,\n      PropTypes.arrayOf(PropTypes.element),\n    ]),\n  };\n\n  static defaultProps = {\n    style: {\n      padding: 0,\n      backgroundColor: '#f0f2f5',\n      minHeight: '100%',\n    },\n    children: null,\n  };\n\n  render() {\n    const { style, children } = this.props;\n    const newStyle = Object.assign({}, Root.defaultProps.style, style);\n    return <div style={newStyle}>{children}</div>;\n  }\n}\n\nexport default Root;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.js",
    "content": "{\"componentName\":\"Root\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"Root\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"style\",\"propType\":\"object\",\"description\":\"\",\"defaultValue\":\"{\\n  padding: 0,\\n  backgroundColor: '#f0f2f5',\\n  minHeight: '100%'\\n}\"},{\"name\":\"children\",\"propType\":\"oneOfType\",\"description\":\"\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.json",
    "content": "{\"title\":\"multiple-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"multiple-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.js",
    "content": "import './index.less';\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.less",
    "content": "// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n.text-nowrap         { white-space: nowrap; }\n\n// BoxModel"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBackgroundProps.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\n/**\n * (HOC)注入背景相关属性配置\n * 包含 'backgroundColor'\n * @param {*} WrappedComponent\n */\nconst HOCBackgroundProps = (WrappedComponent) => {\n  const PROPS = {\n    backgroundColor: 'backgroundColor',\n  };\n  return class extends Component {\n    static propTypes = {\n      backgroundColor: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    };\n\n    static defaultProps = {\n      backgroundColor: false,\n    };\n\n    parseStyle = (args) => {\n      const style = {};\n      Object.keys(PROPS).forEach((item) => {\n        // if props isn't false\n        if (!args[item]) return;\n        style[PROPS[item]] = args[item];\n      });\n      return style;\n    };\n\n    render() {\n      const { backgroundColor, ...otherProps } = this.props;\n      return (\n        <WrappedComponent\n          {...otherProps}\n          styleBackground={this.parseStyle(this.props)}\n        />\n      );\n    }\n  };\n};\n\nexport default HOCBackgroundProps;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBoxModelProps.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nconst parseJoin = value => value.join(' ');\n\n/**\n * (HOC)注入盒子模型相关属性配置\n * 包含 'display', 'margin', 'border', 'padding', 'width', 'height', 'borderRadius'\n * @param {*} WrappedComponent\n */\nconst HOCBoxModelProps = (WrappedComponent) => {\n  const PROPS = {\n    display: 'display',\n    margin: 'margin',\n    border: 'border',\n    padding: 'padding',\n    width: 'width',\n    height: 'height',\n    borderRadius: 'borderRadius',\n  };\n  return class extends Component {\n    static propTypes = {\n      display: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      margin: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),\n      border: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),\n      padding: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),\n      width: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      height: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      borderRadius: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    };\n\n    static defaultProps = {\n      display: false,\n      margin: false,\n      border: false,\n      padding: false,\n      width: false,\n      height: false,\n      borderRadius: false,\n    };\n\n    parseStyle = (args) => {\n      const style = {};\n      Object.keys(PROPS).forEach((item) => {\n        // if props isn't false\n        if (!args[item]) return;\n        style[PROPS[item]] = Array.isArray(args[item])\n          ? parseJoin(args[item])\n          : args[item];\n      });\n      return style;\n    };\n\n    render() {\n      const {\n        display,\n        margin,\n        border,\n        padding,\n        width,\n        height,\n        borderRadius,\n        ...otherProps\n      } = this.props;\n      return (\n        <WrappedComponent\n          {...otherProps}\n          styleBoxModel={this.parseStyle(this.props)}\n        />\n      );\n    }\n  };\n};\n\nexport default HOCBoxModelProps;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCFlexLayoutProps.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\n/**\n * (HOC)注入flex布局相关属性配置\n * 包含 'alignItems', 'justifyContent', 'flexDirection'\n * @param {*} WrappedComponent\n */\nconst HOCFlexLayoutProps = (WrappedComponent) => {\n  const PROPS = {\n    alignItems: 'alignItems',\n    justifyContent: 'justifyContent',\n    flexDirection: 'flexDirection',\n    flexWrap: 'flexWrap',\n  };\n  return class extends Component {\n    static propTypes = {\n      alignItems: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      justifyContent: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      flexDirection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      flexWrap: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    };\n\n    static defaultProps = {\n      alignItems: false,\n      justifyContent: false,\n      flexDirection: false,\n      flexWrap: false,\n    };\n\n    parseStyle = (args) => {\n      const style = {};\n      if (args.style && args.style.display === 'flex') {\n        Object.keys(PROPS).forEach((item) => {\n          // if props isn't false\n          if (!args[item]) return;\n          style[PROPS[item]] = args[item];\n        });\n      }\n      return style;\n    };\n\n    render() {\n      const {\n        alignItems,\n        justifyContent,\n        flexDirection,\n        flexWrap,\n        ...otherProps\n      } = this.props;\n      return (\n        <WrappedComponent\n          {...otherProps}\n          styleFlexLayout={this.parseStyle(this.props)}\n        />\n      );\n    }\n  };\n};\n\nexport default HOCFlexLayoutProps;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCLayoutProps.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\n/**\n * (HOC)注入布局相关属性配置\n * 包含 'align', 'lineHeight', 'verticalAlign'\n * @param {*} WrappedComponent\n */\nconst HOCLayoutProps = (WrappedComponent) => {\n  const PROPS = {\n    align: 'textAlign',\n    lineHeight: 'lineHeight',\n    verticalAlign: 'verticalAlign',\n  };\n  return class extends Component {\n    static propTypes = {\n      align: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      lineHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      verticalAlign: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    };\n\n    static defaultProps = {\n      align: false,\n      lineHeight: false,\n      verticalAlign: false,\n    };\n\n    parseStyle = (args) => {\n      const style = {};\n      Object.keys(PROPS).forEach((item) => {\n        // if props isn't false\n        if (!args[item]) return;\n        style[PROPS[item]] = args[item];\n      });\n      return style;\n    };\n\n    render() {\n      const {\n        align, lineHeight, verticalAlign, ...otherProps\n      } = this.props;\n      return (\n        <WrappedComponent\n          {...otherProps}\n          styleLayout={this.parseStyle(this.props)}\n        />\n      );\n    }\n  };\n};\n\nexport default HOCLayoutProps;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCTextProps.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\n/**\n * (HOC)注入文本相关属性配置\n * 包含 'fontSize', 'fontWeight', 'color'\n * @param {*} WrappedComponent\n */\nconst HOCTextProps = (WrappedComponent) => {\n  const PROPS = {\n    fontSize: 'fontSize',\n    fontWeight: 'fontWeight',\n    color: 'color',\n  };\n  return class extends Component {\n    static propTypes = {\n      fontSize: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n      color: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),\n    };\n\n    static defaultProps = {\n      fontSize: false,\n      fontWeight: false,\n      color: false,\n    };\n\n    parseStyle = (args) => {\n      const style = {};\n      Object.keys(PROPS).forEach((item) => {\n        // if props isn't false\n        if (!args[item]) return;\n        style[PROPS[item]] = args[item];\n      });\n      return style;\n    };\n\n    render() {\n      const {\n        fontSize, fontWeight, color, ...otherProps\n      } = this.props;\n      return (\n        <WrappedComponent\n          {...otherProps}\n          styleText={this.parseStyle(this.props)}\n        />\n      );\n    }\n  };\n};\n\nexport default HOCTextProps;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/multiple-exported-component/src/index.js",
    "content": "import AIMakeBlank from './basic/AIMakeBlank';\nimport AIMakeIcon from './basic/AIMakeIcon';\nimport AIMakeImage from './basic/AIMakeImage';\nimport AIMakeLink from './basic/AIMakeLink';\nimport AIMakePlaceholder from './basic/AIMakePlaceholder';\nimport AIMakeText from './basic/AIMakeText';\nimport Root from './basic/Root';\n\nexport {\n  AIMakeBlank,\n  AIMakeIcon,\n  AIMakeImage,\n  AIMakeLink,\n  AIMakePlaceholder,\n  AIMakeText,\n  Root,\n};\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/rax-component/package.json",
    "content": "{\n  \"name\": \"@ali/chaoshi-meta-example\",\n  \"version\": \"1.0.0\",\n  \"description\": \"intro component\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"miniappConfig\": {\n    \"main\": \"lib/miniapp/index\",\n    \"main:wechat\": \"lib/wechat-miniprogram/index\"\n  },\n  \"files\": [\n    \"build\",\n    \"dist\",\n    \"es\",\n    \"lib\",\n    \"material-meta.json\"\n  ],\n  \"keywords\": [\n    \"Rax\",\n    \"rax-component\"\n  ],\n  \"engines\": {\n    \"npm\": \">=3.0.0\"\n  },\n  \"scripts\": {\n    \"start\": \"build-scripts start\",\n    \"build\": \"build-scripts build\",\n    \"eslint\": \"eslint --ext .js,.jsx,.ts,.tsx ./\",\n    \"eslint:fix\": \"npm run eslint -- --fix\",\n    \"stylelint\": \"stylelint \\\"**/*.{css,scss,less}\\\"\",\n    \"lint\": \"npm run eslint && npm run stylelint\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"dependencies\": {\n    \"@ali/pcom-chaoshi-meta-design\": \"^1.1.5\",\n    \"rax-text\": \"^2.0.0\",\n    \"rax-view\": \"^2.0.0\"\n  },\n  \"peerDependencies\": {\n    \"rax\": \"^1.1.0\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.0\",\n    \"@alife/build-plugin-lowcode\": \"^1.0.17\",\n    \"@iceworks/spec\": \"^1.0.0\",\n    \"@types/rax\": \"^1.0.0\",\n    \"driver-universal\": \"^3.1.0\",\n    \"eslint\": \"^6.8.0\",\n    \"rax\": \"^1.1.0\",\n    \"rax-test-renderer\": \"^1.0.0\",\n    \"stylelint\": \"^13.7.2\",\n    \"typescript\": \"^3.7.3\"\n  },\n  \"componentConfig\": {\n    \"name\": \"ChaoshiMetaExample\",\n    \"title\": \"ChaoshiMetaExample\",\n    \"category\": \"Information\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npm.alibaba-inc.com\"\n  },\n  \"license\": \"MIT\",\n  \"homepage\": \"https://unpkg.alibaba-inc.com/@ali/chaoshi-meta-example@1.0.0/build/index.html\"\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/rax-component/src/index.css",
    "content": ".rax-demo-title {\n  font-size: 45rpx;\n  font-weight: bold;\n  margin: 20rpx 0;\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/rax-component/src/index.tsx",
    "content": "import { createElement, forwardRef } from 'rax';\nimport { Price as _Price, Title as _Title } from '@ali/pcom-chaoshi-meta-design';\nimport View from 'rax-view';\nimport Text from 'rax-text';\nimport './index.css';\n\ninterface Props {\n  a: string;\n}\n\nconst MyComponent = forwardRef((props: Props, ref: any) => {\n  return (\n    <View>\n      <Text className=\"rax-demo-title\">Hello World!</Text>\n    </View>\n  );\n});\n\nexport default MyComponent;\n\nexport const Price = _Price;\nexport const Title = _Title;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/es/container.js",
    "content": "\n      import Demo from './index.js';\n      import manifest from './manifest.js';\n\n      export default { origin: Demo, manifest };\n    "
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/es/index.js",
    "content": "import _classCallCheck from '@babel/runtime/helpers/classCallCheck';\nimport _createClass from '@babel/runtime/helpers/createClass';\nimport _possibleConstructorReturn from '@babel/runtime/helpers/possibleConstructorReturn';\nimport _getPrototypeOf from '@babel/runtime/helpers/getPrototypeOf';\nimport _inherits from '@babel/runtime/helpers/inherits';\n\n/* eslint-disable react/no-unused-prop-types */\n\n/* eslint-disable react/require-default-props */\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport './main.css';\n\nconst Demo =\n  /* #__PURE__ */\n  (function(_React$Component) {\n    _inherits(Demo, _React$Component);\n\n    function Demo() {\n      _classCallCheck(this, Demo);\n\n      return _possibleConstructorReturn(this, _getPrototypeOf(Demo).apply(this, arguments));\n    }\n\n    _createClass(Demo, [\n      {\n        key: 'render',\n        value: function render() {\n          return React.createElement('div', null, ' Test ');\n        },\n      },\n    ]);\n\n    return Demo;\n  })(React.Component);\n\nDemo.propTypes = {\n  optionalArray: PropTypes.array,\n  optionalBool: PropTypes.bool,\n  /**\n   * desc\n   * @param {string} title - The title of the book.\n   * @param {string} author - The author of the book.\n   * @returns {any}\n   */\n  optionalFunc: PropTypes.func,\n  optionalNumber: PropTypes.number,\n  optionalObject: PropTypes.object,\n  optionalString: PropTypes.string,\n  optionalSymbol: PropTypes.symbol,\n  // Anything that can be rendered: numbers, strings, elements or an array\n  // (or fragment) containing these types.\n  optionalNode: PropTypes.node,\n  // A React element (ie. <MyComponent />).\n  optionalElement: PropTypes.element,\n  // A React element type (ie. MyComponent).\n  optionalElementType: PropTypes.elementType,\n  // You can also declare that a prop is an instance of a class. This uses\n  // JS's instanceof operator.\n  optionalMessage: PropTypes.instanceOf(Demo),\n  // You can ensure that your prop is limited to specific values by treating\n  // it as an enum.\n  optionalEnum: PropTypes.oneOf(['News', 'Photos']),\n  // An object that could be one of many types\n  optionalUnion: PropTypes.oneOfType([\n    PropTypes.string,\n    PropTypes.number,\n    PropTypes.instanceOf(Demo),\n  ]),\n  // An array of a certain type\n  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),\n  // An object with property values of a certain type\n  optionalObjectOf: PropTypes.objectOf(PropTypes.number),\n  // You can chain any of the above with `isRequired` to make sure a warning\n  // is shown if the prop isn't provided.\n  // An object taking on a particular shape\n  optionalObjectWithShape: PropTypes.shape({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }),\n  optionalObjectWithShape2: PropTypes.shape({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }).isRequired,\n  // An object with warnings on extra properties\n  optionalObjectWithStrictShape: PropTypes.exact({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }),\n  requiredFunc: PropTypes.func.isRequired,\n  // A value of any data type\n  requiredAny: PropTypes.any.isRequired,\n};\nDemo.defaultProps = {\n  optionalNumber: 123,\n};\nexport default Demo;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/es/main.css",
    "content": "@charset \"UTF-8\";\n/* 不引入依赖组件的样式，比如组件 import { Button } from '@alife/next'; */\n/* 不需要在main.scss中引入 @import '~@alife/next/lib/button/index.scss'; */\n/* 但是在lib/index.scss中需要引入 @import '~@alife/next/lib/button/index.scss'; */\n/* 如果需要引入主题变量引入此段 */\n/* 组件自身样式 */\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/es/main.scss",
    "content": "/* 不引入依赖组件的样式，比如组件 import { Button } from '@alife/next'; */\n/* 不需要在main.scss中引入 @import '~@alife/next/lib/button/index.scss'; */\n/* 但是在lib/index.scss中需要引入 @import '~@alife/next/lib/button/index.scss'; */\n\n/* 如果需要引入主题变量引入此段 */\n// @import '~@alife/next/variables.scss';\n\n/* 组件自身样式 */\n// .custom-component {\n//    color: $color-brand1-1;\n// }\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/es/manifest.js",
    "content": "{\"componentName\":\"Demo\",\"title\":\"\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"single-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"Demo\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[{\"name\":\"optionalArray\",\"propType\":\"array\",\"description\":\"\"},{\"name\":\"optionalBool\",\"propType\":\"bool\",\"description\":\"\"},{\"name\":\"optionalFunc\",\"propType\":\"func\",\"description\":\"\"},{\"name\":\"optionalNumber\",\"propType\":\"number\",\"description\":\"\"},{\"name\":\"optionalObject\",\"propType\":\"object\",\"description\":\"\"},{\"name\":\"optionalString\",\"propType\":\"string\",\"description\":\"\"},{\"name\":\"optionalSymbol\",\"propType\":\"symbol\",\"description\":\"\"},{\"name\":\"optionalNode\",\"propType\":\"node\",\"description\":\"\"},{\"name\":\"optionalElement\",\"propType\":\"element\",\"description\":\"\"},{\"name\":\"optionalElementType\",\"propType\":\"elementType\",\"description\":\"\"},{\"name\":\"optionalMessage\",\"propType\":\"instanceOf\",\"description\":\"\"},{\"name\":\"optionalEnum\",\"propType\":\"oneOf\",\"description\":\"\"},{\"name\":\"optionalUnion\",\"propType\":\"oneOfType\",\"description\":\"\"},{\"name\":\"optionalArrayOf\",\"propType\":\"arrayOf\",\"description\":\"\"},{\"name\":\"optionalObjectOf\",\"propType\":\"objectOf\",\"description\":\"\"},{\"name\":\"optionalObjectWithShape\",\"propType\":\"shape\",\"description\":\"\"},{\"name\":\"optionalObjectWithShape2\",\"propType\":\"shape\",\"description\":\"\"},{\"name\":\"optionalObjectWithStrictShape\",\"propType\":\"exact\",\"description\":\"\"},{\"name\":\"requiredFunc\",\"propType\":\"func\",\"description\":\"\"},{\"name\":\"requiredAny\",\"propType\":\"any\",\"description\":\"\"}]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/es/manifest.json",
    "content": "{\"title\":\"single-exported-component\",\"docUrl\":\"\",\"screenshot\":\"\",\"npm\":{\"package\":\"single-exported-component\",\"version\":\"1.0.0\",\"exportName\":\"\",\"main\":\"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js\",\"destructuring\":false,\"subName\":\"\"},\"props\":[]}"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/package.json",
    "content": "{\n  \"name\": \"single-exported-component\",\n  \"description\": \"\",\n  \"version\": \"1.0.0\",\n  \"main\": \"src/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"demo/\",\n    \"lib/\",\n    \"es/\",\n    \"build/\"\n  ],\n  \"scripts\": {\n    \"postversion\": \"node ./scripts/postversion.js\"\n  },\n  \"dependencies\": {\n    \"prop-types\": \"^15.7.2\",\n    \"react\": \"^16.8.5\",\n    \"react-dom\": \"^16.8.5\"\n  },\n  \"devDependencies\": {\n    \"cross-spawn\": \"^6.0.5\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.6\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npm.alibaba-inc.com\"\n  }\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/src/index.js",
    "content": "/* eslint-disable react/no-unused-prop-types */\n/* eslint-disable react/require-default-props */\nimport React from 'react';\nimport PropTypes from 'prop-types';\n\nimport './main.scss';\n\nconst a = 1, Demo = (props) => {\n  return <div> Test </div>;\n}\n\nDemo.staticMethod = () => {\n  console.log('static method');\n}\n\nDemo.propTypes = {\n  optionalArray: PropTypes.array,\n  optionalBool: PropTypes.bool,\n  /**\n   * desc\n   * @param {string} title - The title of the book.\n   * @param {string} author - The author of the book.\n   * @returns {any}\n   */\n  optionalFunc: PropTypes.func,\n  optionalNumber: PropTypes.number,\n  optionalObject: PropTypes.object,\n  optionalString: PropTypes.string,\n  optionalSymbol: PropTypes.symbol,\n\n  // Anything that can be rendered: numbers, strings, elements or an array\n  // (or fragment) containing these types.\n  optionalNode: PropTypes.node,\n\n  // A React element (ie. <MyComponent />).\n  optionalElement: PropTypes.element,\n\n  // A React element type (ie. MyComponent).\n  optionalElementType: PropTypes.elementType,\n\n  // You can also declare that a prop is an instance of a class. This uses\n  // JS's instanceof operator.\n  optionalMessage: PropTypes.instanceOf(Demo),\n\n  // You can ensure that your prop is limited to specific values by treating\n  // it as an enum.\n  optionalEnum: PropTypes.oneOf(['News', 'Photos']),\n\n  // An object that could be one of many types\n  optionalUnion: PropTypes.oneOfType([\n    PropTypes.string,\n    PropTypes.number,\n    PropTypes.instanceOf(Demo),\n  ]),\n\n  // An array of a certain type\n  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),\n\n  // An object with property values of a certain type\n  optionalObjectOf: PropTypes.objectOf(PropTypes.number),\n\n  // You can chain any of the above with `isRequired` to make sure a warning\n  // is shown if the prop isn't provided.\n\n  // An object taking on a particular shape\n  optionalObjectWithShape: PropTypes.shape({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }),\n\n  optionalObjectWithShape2: PropTypes.shape({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }).isRequired,\n\n  // An object with warnings on extra properties\n  optionalObjectWithStrictShape: PropTypes.exact({\n    optionalProperty: PropTypes.string,\n    requiredProperty: PropTypes.number.isRequired,\n  }),\n\n  requiredFunc: PropTypes.func.isRequired,\n\n  // A value of any data type\n  requiredAny: PropTypes.any.isRequired,\n};\n\nDemo.defaultProps = {};\n\nexport default Demo;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/single-exported-component/src/main.scss",
    "content": "/* 不引入依赖组件的样式，比如组件 import { Button } from '@alife/next'; */\n/* 不需要在main.scss中引入 @import '~@alife/next/lib/button/index.scss'; */\n/* 但是在lib/index.scss中需要引入 @import '~@alife/next/lib/button/index.scss'; */\n\n/* 如果需要引入主题变量引入此段 */\n// @import '~@alife/next/variables.scss';\n\n/* 组件自身样式 */\n// .custom-component {\n//    color: $color-brand1-1;\n// }\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/transpiled-component/package.json",
    "content": "{\n    \"name\": \"transpiled-component\",\n    \"version\": \"1.0.0\",\n    \"main\": \"lib/index.js\",\n    \"dependencies\": {\n        \"react\": \"^16.0.0\"\n    }\n}"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component/package.json",
    "content": "{\n  \"name\": \"ts-component\",\n  \"description\": \"\",\n  \"version\": \"1.0.0\",\n  \"module\": \"src/index.tsx\",\n  \"main\": \"src/index.tsx\",\n  \"files\": [\n    \"demo/\",\n    \"lib/\",\n    \"es/\",\n    \"build/\"\n  ],\n  \"scripts\": {\n    \"postversion\": \"node ./scripts/postversion.js\"\n  },\n  \"dependencies\": {\n    \"prop-types\": \"^15.7.2\",\n    \"react\": \"^16.8.5\",\n    \"react-dom\": \"^16.8.5\"\n  },\n  \"devDependencies\": {\n    \"@types/cross-spawn\": \"^6.0.2\",\n    \"@types/prop-types\": \"^15.7.3\",\n    \"@types/react\": \"^16.9.46\",\n    \"@types/react-dom\": \"^16.9.8\",\n    \"cross-spawn\": \"^6.0.5\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.6\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npm.alibaba-inc.com\"\n  }\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component/src/index.tsx",
    "content": "import App from './main-module';\nimport SubModule from './sub-module';\n\nApp.SubModule = SubModule;\nApp.defaultProps = {\n  str: 'str2',\n};\n\nexport default App;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component/src/main-module.tsx",
    "content": "/* eslint-disable @typescript-eslint/ban-types */\n/* eslint-disable @typescript-eslint/indent */\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/member-ordering */\nimport * as React from 'react';\nimport SubModule from './sub-module';\n\nenum Gender {\n  MALE,\n  FEMALE,\n}\n\ninterface Obj {\n  s: string;\n  n: number;\n}\n\ntype Func = (a: string) => JSX.Element;\ntype Union =\n  | string\n  | number\n  | {\n      a: string;\n    };\n\ninterface Props {\n  error(a: string): number;\n  void: void;\n  object: Object;\n  trigger?: Array<'click' | 'hover' | 'contextMenu'>;\n  str?: string;\n  num: number;\n  gender: Gender;\n  any: any;\n  bool: boolean;\n  tuple: [number, string, true];\n  enum: 'red' | 'yellow' | 'green';\n  arr: number[];\n  halfEmptyObj: {\n    [k: string]: any;\n    fun(a: string[]): void;\n  };\n  // eslint-disable-next-line @typescript-eslint/ban-types\n  emptyObj: {};\n  func(arg: string): number;\n  funcs: {\n    n(): number;\n    a(arg: string, num: number): void;\n  };\n  fuzzy:\n    | boolean\n    | 'object'\n    | number\n    | 'number'\n    | 'test'\n    | {\n        a: any;\n        sa: string[];\n      };\n  oneOf: boolean | 'test' | Obj;\n  refFunc(p: Props): void;\n  elementOrOther: JSX.Element | Func;\n  obj: {\n    a: number;\n    arrOfStr: string[];\n    arrOfObj: Obj[];\n    func: () => void;\n  };\n  objOf: {\n    [k: string]: number;\n  };\n  exact: {\n    a: number;\n  };\n  node?: React.ReactNode;\n  element?: JSX.Element;\n  elementType?: React.ElementType;\n  union: Union;\n  // eslint-disable-next-line @typescript-eslint/adjacent-overload-signatures\n  func2: Func;\n  html: HTMLBaseElement;\n  loading?: boolean | { delay?: number };\n}\n\ninterface AppProps extends React.FC<Props> {\n  SubModule?: typeof SubModule;\n}\n\nconst App: AppProps = React.forwardRef((props, ref: React.Ref<HTMLDivElement>) => {\n  return <div ref={ref}>{props.str}</div>;\n});\n\nApp.defaultProps = {\n  object: {\n    a: '1',\n    b: '2',\n  },\n  func(a: string) {\n    return 123;\n  },\n  str: 'str',\n};\n\nexport default App;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component/src/sub-module.tsx",
    "content": "import * as React from 'react';\n\ninterface Props {\n  name: string;\n}\n\nclass SubModule extends React.Component<Props> {\n  static defaultProps = {\n    name: 'abc',\n  };\n\n  render() {\n    const { name } = this.props;\n    return <div>hello, {name}</div>;\n  }\n}\n\nSubModule.defaultProps = {\n  name: 'abc',\n};\n\nexport default SubModule;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component2/package.json",
    "content": "{\n  \"name\": \"@alife/empty\",\n  \"version\": \"1.0.1\",\n  \"description\": \"空组件\",\n  \"files\": [\n    \"demo/\",\n    \"es/\",\n    \"lib/\",\n    \"build/\",\n    \"dist\",\n    \"material-meta.json\"\n  ],\n  \"main\": \"src/index.tsx\",\n  \"module\": \"src/index.tsx\",\n  \"stylePath\": \"style.js\",\n  \"scripts\": {\n    \"start\": \"build-scripts start\",\n    \"build\": \"build-scripts build\",\n    \"test\": \"build-scripts test\",\n    \"prepublishOnly\": \"npm run build\",\n    \"doc\": \"react-doc-gen\",\n    \"lint\": \"eslint --cache --ext .js,.jsx ./\"\n  },\n  \"keywords\": [\n    \"ice\",\n    \"react\",\n    \"component\"\n  ],\n  \"dependencies\": {\n    \"classnames\": \"^2.2.6\",\n    \"prop-types\": \"^15.5.8\"\n  },\n  \"devDependencies\": {\n    \"@alife/build-plugin-lowcode\": \"^1.0.7\",\n    \"@alib/build-scripts\": \"^0.1.3\",\n    \"@alifd/adaptor-generate\": \"^0.1.3\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-fusion-cool\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"react\": \"^16.3.0\",\n    \"react-dom\": \"^16.3.0\",\n    \"@ice/spec\": \"^1.0.0\",\n    \"eslint\": \"^6.0.1\",\n    \"@alifd/next\": \"1.x\",\n    \"@types/react\": \"^16.9.13\",\n    \"@types/react-dom\": \"^16.9.4\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.3.0\",\n    \"@alifd/next\": \"1.x\"\n  },\n  \"componentConfig\": {\n    \"name\": \"Empty\",\n    \"title\": \"empty\",\n    \"category\": \"DataDisplay\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npm.alibaba-inc.com\"\n  },\n  \"license\": \"MIT\",\n  \"homepage\": \"https://unpkg.alibaba-inc.com/@alife/empty@1.0.1/build/index.html\"\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component2/src/empty.tsx",
    "content": "import * as React from 'react';\nimport classNames from 'classnames';\nimport './index';\ninterface DefaultEmptyImg {\n  className?: string;\n  imageStyle?: React.CSSProperties;\n}\n\nexport const DefaultEmptyImg = (props: DefaultEmptyImg) => {\n  const { className, imageStyle, ...restProps } = props;\n  const prefixCls = 'design-empty-default';\n  const alt = 'empty';\n\n  return (\n    <div className={classNames(prefixCls, className)} {...restProps}>\n      <div className={`${prefixCls}-image`} style={imageStyle}>\n        <img alt={alt} src=\"https://img.alicdn.com/tfs/TB13G0LTNv1gK0jSZFFXXb0sXXa-54-54.svg\" />\n      </div>\n      <p className={`${prefixCls}-description`}>暂时没有数据</p>\n    </div>\n  );\n};\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component2/src/index.scss",
    "content": ".design-empty {\n  margin: 0 8px;\n  font-size: 14px;\n  line-height: 1.5715;\n  text-align: center;\n\n  &-image {\n    height: 200px;\n    margin-bottom: 4px;\n\n    img {\n      height: 100%;\n    }\n\n    svg {\n      height: 100%;\n      margin: auto;\n    }\n  }\n\n  &-description {\n    margin: 0;\n  }\n\n  &-footer {\n    margin-top: 16px;\n  }\n}\n\n.design-empty-default {\n  margin: 0 8px;\n  font-size: 14px;\n  line-height: 1.5715;\n  text-align: center;\n\n  &-image {\n    height: 54px;\n    margin-bottom: 8px;\n\n    img {\n      height: 100%;\n    }\n  }\n\n  &-description {\n    font-size: 14px;\n    color: #c2c2c2;\n  }\n}\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/ts-component2/src/index.tsx",
    "content": "import * as React from 'react';\nimport classNames from 'classnames';\nimport { DefaultEmptyImg } from './empty';\n\nexport interface EmptyProps extends React.HTMLAttributes<HTMLDivElement> {\n  className?: string;\n  style?: React.CSSProperties;\n  imageStyle?: React.CSSProperties;\n  image?: React.ReactNode | string;\n  description?: React.ReactNode;\n  children?: React.ReactNode;\n  type?: 'default' | 'custom'; // default 默认， custom 表示自定义\n}\n\nconst prefixCls = 'design-empty';\ninterface EmptyType extends React.FC<EmptyProps> {\n  IMAGE_TYPE_SERVERBUSY: string; //服务器繁忙\n  IMAGE_TYPE_SERVERNOFOUND: string; // 404\n  IMAGE_TYPE_FILENOFOUND: string; //文件不存在\n  IMAGE_TYPE_PROJECTNOFOUND: string; // 项目不存在\n  IMAGE_TYPE_EMPTY: string; //空\n}\n\nconst Empty: EmptyType = (props: EmptyProps) => {\n  const {\n    className,\n    image = 'Empty.IMAGE_TYPE_EMPTY',\n    description,\n    children,\n    imageStyle,\n    type = 'custom',\n    ...restProps\n  } = props;\n\n  if (type === 'default') {\n    return <DefaultEmptyImg />;\n  }\n\n  let imageNode: React.ReactNode = null;\n  const alt = typeof description === 'string' ? description : 'empty';\n\n  if (typeof image === 'string') {\n    imageNode = <img alt={alt} src={image} />;\n  } else {\n    imageNode = image;\n  }\n\n  return (\n    <div className={classNames(prefixCls, className)} {...restProps}>\n      <div className={`${prefixCls}-image`} style={imageStyle}>\n        {imageNode}\n      </div>\n      {description && <p className={`${prefixCls}-description`}>{description}</p>}\n      {children && <div className={`${prefixCls}-footer`}>{children}</div>}\n    </div>\n  );\n};\n\n//服务器繁忙\nEmpty.IMAGE_TYPE_SERVERBUSY = 'https://img.alicdn.com/tfs/TB1qPJvTFY7gK0jSZKzXXaikpXa-400-400.png';\n//404\nEmpty.IMAGE_TYPE_SERVERNOFOUND =\n  'https://img.alicdn.com/tfs/TB18gVGTUH1gK0jSZSyXXXtlpXa-400-400.png';\n//文件不存在\nEmpty.IMAGE_TYPE_FILENOFOUND = 'https://img.alicdn.com/tfs/TB1.ClQTUT1gK0jSZFrXXcNCXXa-400-400.png';\n//项目不存在\nEmpty.IMAGE_TYPE_PROJECTNOFOUND =\n  'https://img.alicdn.com/tfs/TB1ZWumfcieb18jSZFvXXaI3FXa-400-400.png';\n//空\nEmpty.IMAGE_TYPE_EMPTY = 'https://img.alicdn.com/tfs/TB13G0LTNv1gK0jSZFFXXb0sXXa-54-54.svg';\nexport default Empty;\n"
  },
  {
    "path": "modules/material-parser/test/fixtures/without-display-name/index.js",
    "content": "var React = require('react');\nvar PropTypes = require('prop-types');\n\nmodule.exports = class extends React.Component {\n    static propTypes = {\n        name: PropTypes.string\n    }\n\n    render() {\n        return <div>{this.props.name}</div>\n    }\n}"
  },
  {
    "path": "modules/material-parser/test/fixtures/without-display-name/package.json",
    "content": "{\n    \"name\": \"without-display-name\",\n    \"version\": \"1.0.0\",\n    \"main\": \"index.js\",\n    \"dependencies\": {\n        \"react\": \"^16.0.0\",\n        \"prop-types\": \"latest\"\n    }\n}"
  },
  {
    "path": "modules/material-parser/test/helpers/index.ts",
    "content": "import { join } from 'path';\n\nconst baseDir = join(__dirname, '../fixtures');\n\n/**\n * 从 fixtures 下获取文件完整路径\n */\nexport const getFromFixtures = (...args: string[]) => {\n  return join(baseDir, ...args);\n};\n"
  },
  {
    "path": "modules/material-parser/test/index.test.ts",
    "content": "import { join } from 'path';\nimport parse from '../src';\nimport { IMaterializeOptions } from '../src/types';\nimport { getFromFixtures } from './helpers';\n\nconst multiExportedComptPath = getFromFixtures('multiple-exported-component');\nconst singleExportedComptPath = getFromFixtures('single-exported-component');\nconst tsComponent = getFromFixtures('ts-component');\nconst tsComponent2 = getFromFixtures('ts-component2');\nconst dtsComponent = getFromFixtures('dts-component');\nconst transpiledComponent = getFromFixtures('transpiled-component');\nconst withoutDisplayName = getFromFixtures('without-display-name');\n\ntest('materialize single exported component by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: singleExportedComptPath,\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('materialize multiple exported component by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: multiExportedComptPath,\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('ts component by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: tsComponent,\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('ts component 2 by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: tsComponent2,\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('rax component by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: 'src/index.tsx',\n    root: getFromFixtures('rax-component'),\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('d.ts component by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: join(dtsComponent, 'src/index.jsx'),\n    root: dtsComponent,\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('transpiled component by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: transpiledComponent,\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('without display name by local', async done => {\n  const options: IMaterializeOptions = {\n    entry: withoutDisplayName,\n    accesser: 'local',\n  };\n\n  const actual = await parse(options);\n\n  expect(actual).toMatchSnapshot();\n  done();\n});\n"
  },
  {
    "path": "modules/material-parser/test/localize.test.ts",
    "content": "import {getPkgNameAndVersion} from '../src/localize';\n\ntest('getPkgNameAndVersion from string', () => {\n    const result = getPkgNameAndVersion('react');\n    expect(result).toEqual({\"name\": \"react\"});\n});"
  },
  {
    "path": "modules/material-parser/test/online.test.ts",
    "content": "import { remove } from 'fs-extra';\nimport parse from '../src';\nimport { IMaterializeOptions } from '../src/types';\n\ntest('materialize react-color by online', async (done) => {\n  const options: IMaterializeOptions = {\n    entry: 'react-color@2.19.3',\n    accesser: 'online',\n  };\n\n  const actual = await parse(options);\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('materialize mc-hello by online', async (done) => {\n  const options: IMaterializeOptions = {\n    entry: 'mc-hello@1.0.1',\n    accesser: 'online',\n  };\n\n  const actual = await parse(options);\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('materialize rc-picker by online', async (done) => {\n  const options: IMaterializeOptions = {\n    entry: 'rc-picker@2.4.3',\n    accesser: 'online',\n  };\n\n  const actual = await parse(options);\n  expect(actual).toMatchSnapshot();\n  done();\n});\n\ntest('materialize online rax module by path & specify workDir', async (done) => {\n  const tempDir = './test/temp';\n  const options: IMaterializeOptions = {\n    name: 'rax-view',\n    version: '2.2.1',\n    entry: './es/common/index.d.ts',\n    accesser: 'online',\n    dslType: 'rax',\n    tempDir,\n  };\n\n  const actual = await parse(options);\n  await remove(tempDir);\n  expect(actual).toMatchSnapshot();\n  done();\n});\n"
  },
  {
    "path": "modules/material-parser/test/validate/__snapshots__/index.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`should be right in dir basic-error 1`] = `\n\"[\n  {\n    \\\\\"keyword\\\\\": \\\\\"required\\\\\",\n    \\\\\"dataPath\\\\\": \\\\\"\\\\\",\n    \\\\\"schemaPath\\\\\": \\\\\"#/required\\\\\",\n    \\\\\"params\\\\\": {\n      \\\\\"missingProperty\\\\\": \\\\\"props\\\\\"\n    },\n    \\\\\"message\\\\\": \\\\\"should have required property 'props'\\\\\"\n  }\n]\"\n`;\n\nexports[`should be right in dir basic-success 1`] = `true`;\n\nexports[`should be right in dir configure 1`] = `true`;\n\nexports[`should be right in dir props-basic-type 1`] = `true`;\n\nexports[`should be right in dir props-complex-type 1`] = `true`;\n"
  },
  {
    "path": "modules/material-parser/test/validate/fixtures/basic-error/schema.json",
    "content": "{\n  \"componentName\": \"Select\",\n  \"title\": \"下拉选择器\",\n  \"description\": \"适用于下拉选择，下拉多选等场景\",\n  \"tags\": [\"xx\", \"yy\"],\n  \"docUrl\": \"https://fusion-demo.alibaba-inc.com/demos/next/select\",\n  \"screenshot\": \"https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png\",\n  \"icon\": \"url/fsdfasdfa.svg\",\n  \"devMode\": \"proCode\",\n  \"npm\": {\n    \"package\": \"@ali/deep\",\n    \"exportName\": \"Button\",\n    \"subName\": \"Icon.Option\",\n    \"main\": \"\",\n    \"destructuring\": true,\n    \"version\": \"0.1.13\"\n  }\n}"
  },
  {
    "path": "modules/material-parser/test/validate/fixtures/basic-success/schema.json",
    "content": "{\n  \"componentName\": \"Select\",\n  \"title\": \"下拉选择器\",\n  \"description\": \"适用于下拉选择，下拉多选等场景\",\n  \"tags\": [\"xx\", \"yy\"],\n  \"docUrl\": \"https://fusion-demo.alibaba-inc.com/demos/next/select\",\n  \"screenshot\": \"https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png\",\n  \"icon\": \"url/fsdfasdfa.svg\",\n  \"devMode\": \"proCode\",\n  \"npm\": {\n    \"package\": \"@ali/deep\",\n    \"exportName\": \"Button\",\n    \"subName\": \"Icon.Option\",\n    \"main\": \"\",\n    \"destructuring\": true,\n    \"version\": \"0.1.13\"\n  },\n  \"props\": []\n}\n"
  },
  {
    "path": "modules/material-parser/test/validate/fixtures/configure/schema.json",
    "content": "{\n    \"componentName\": \"Select\",\n    \"title\": \"下拉选择器\",\n    \"description\": \"适用于下拉选择，下拉多选等场景\",\n    \"tags\": [\"xx\", \"yy\"],\n    \"docUrl\": \"https://fusion-demo.alibaba-inc.com/demos/next/select\",\n    \"screenshot\": \"https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png\",\n    \"icon\": \"url/fsdfasdfa.svg\",\n    \"devMode\": \"proCode\",\n    \"npm\": {\n        \"package\": \"@ali/deep\",\n        \"exportName\": \"Button\",\n        \"subName\": \"Icon.Option\",\n        \"main\": \"\",\n        \"destructuring\": true,\n        \"version\": \"0.1.13\"\n    },\n    \"props\": [],\n    \"configure\": {\n        \"props\": [\n            {\n                \"type\": \"field\",\n                \"title\": \"field\",\n                \"name\": \"field\",\n                \"setter\": {\n                    \"componentName\": \"Mixin\",\n                    \"props\": {\n                        \"onlyChangeType\": false,\n                        \"defaultType\": \"Input\",\n                        \"typeMap\": {\n                            \"Input\": {},\n                            \"Select\": {}\n                        }\n                    }\n                }\n            },\n            {\n                \"type\": \"group\",\n                \"title\": \"group\",\n                \"items\": [\n                    {\n                        \"type\": \"field\",\n                        \"componentName\": \"Function\",\n                        \"props\": {\n                            \"defaultValue\":  \"function(){ console.log('aloha') }\"\n                        }\n                    },\n                    {\n                        \"type\": \"field\",\n                        \"componentName\": \"Number\",\n                        \"props\": {\n                            \"value\":  123\n                        }\n                    }\n                ]\n            }\n        ],\n        \"component\": { \n            \"isContainer\": true,\n            \"isModal\": false,\n            \"descriptor\": \"title\",\n            \"nestingRule\": {\n                \"childWhitelist\": [\"SelectOption\"],\n                \"parentWhitelist\": [\"Select\", \"Table\"]\n            }\n        }\n    }\n}"
  },
  {
    "path": "modules/material-parser/test/validate/fixtures/props-basic-type/schema.json",
    "content": "{\n    \"componentName\": \"Select\",\n    \"title\": \"下拉选择器\",\n    \"description\": \"适用于下拉选择，下拉多选等场景\",\n    \"tags\": [\"xx\", \"yy\"],\n    \"docUrl\": \"https://fusion-demo.alibaba-inc.com/demos/next/select\",\n    \"screenshot\": \"https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png\",\n    \"icon\": \"url/fsdfasdfa.svg\",\n    \"devMode\": \"proCode\",\n    \"npm\": {\n        \"package\": \"@ali/deep\",\n        \"exportName\": \"Button\",\n        \"subName\": \"Icon.Option\",\n        \"main\": \"\",\n        \"destructuring\": true,\n        \"version\": \"0.1.13\"\n    },\n    \"props\": [\n        {\n            \"name\": \"placeholder\",\n            \"propType\": \"string\",\n            \"description\": \"占位提示\",\n            \"defaultValue\": \"请输入...\"\n        },\n        {\n            \"name\": \"disabled\",\n            \"propType\": \"bool\",\n            \"description\": \"disabled\",\n            \"defaultValue\": false\n        },\n        {\n            \"name\": \"size\",\n            \"propType\": \"number\",\n            \"description\": \"尺寸\",\n            \"defaultValue\": 10\n        },\n        {\n            \"name\": \"dataSource\",\n            \"propType\": \"array\",\n            \"description\": \"下拉选项配置\",\n            \"defaultValue\": []\n        },\n        {\n            \"name\": \"object\",\n            \"propType\": \"object\",\n            \"description\": \"object\",\n            \"defaultValue\": {\n                \"a\": 123,\n                \"b\": 234\n            }\n        },\n        {\n            \"name\": \"node\",\n            \"propType\": \"node\",\n            \"description\": \"node\"\n        },\n        {\n            \"name\": \"element\",\n            \"propType\": \"element\",\n            \"description\": \"element\"\n        },\n        {\n            \"name\": \"onClick\",\n            \"propType\": {\n                \"type\": \"func\",\n                \"isRequired\": true\n            },\n            \"description\": \"下拉选项配置\"\n        }\n    ]\n}"
  },
  {
    "path": "modules/material-parser/test/validate/fixtures/props-complex-type/schema.json",
    "content": "{\n    \"componentName\": \"Select\",\n    \"title\": \"下拉选择器\",\n    \"description\": \"适用于下拉选择，下拉多选等场景\",\n    \"tags\": [\"xx\", \"yy\"],\n    \"docUrl\": \"https://fusion-demo.alibaba-inc.com/demos/next/select\",\n    \"screenshot\": \"https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png\",\n    \"icon\": \"url/fsdfasdfa.svg\",\n    \"devMode\": \"proCode\",\n    \"npm\": {\n        \"package\": \"@ali/deep\",\n        \"exportName\": \"Button\",\n        \"subName\": \"Icon.Option\",\n        \"main\": \"\",\n        \"destructuring\": true,\n        \"version\": \"0.1.13\"\n    },\n    \"props\": [\n        {\n            \"name\": \"oneOf\",\n            \"propType\": {\n                \"type\": \"oneOf\",\n                \"value\": [\"a\", \"b\", \"c\"]\n            }\n        },\n        {\n            \"name\": \"oneOfType\",\n            \"propType\": {\n                \"type\": \"oneOfType\",\n                \"value\": [\"string\", \"number\",  {\n                    \"type\": \"array\",\n                    \"isRequired\": true\n                }]\n            }\n        },\n        {\n            \"name\": \"arrayOf\",\n            \"propType\": \"number\"\n        },\n        {\n            \"name\": \"objectOf\",\n            \"propType\": \"number\"\n        },\n        {\n            \"name\": \"size\",\n            \"propType\": \"number\",\n            \"description\": \"尺寸\",\n            \"defaultValue\": 10\n        },\n        {\n            \"name\": \"dataSource\",\n            \"propType\": \"array\",\n            \"description\": \"下拉选项配置\",\n            \"defaultValue\": []\n        },\n        {\n            \"name\": \"shape\",\n            \"propType\": {\n                \"type\": \"shape\",\n                \"value\": [\n                    {\n                        \"name\": \"color\",\n                        \"propType\": \"string\"\n                    }, \n                    {\n                        \"name\": \"fontSize\",\n                        \"propType\": {\n                            \"type\": \"number\",\n                            \"isRequired\": true \n                        }  \n                    }\n                ]\n            }\n        },\n        {\n            \"name\": \"exact\",\n            \"propType\": {\n                \"type\": \"exact\",\n                \"value\": [\n                    {\n                        \"name\": \"name\",\n                        \"propType\": \"string\"\n                    }, \n                    {\n                        \"name\": \"quantity\",\n                        \"propType\": {\n                            \"type\": \"number\",\n                            \"isRequired\": true \n                        }  \n                    }\n                ]\n            }\n        }\n    ]\n}"
  },
  {
    "path": "modules/material-parser/test/validate/index.test.ts",
    "content": "import * as fs from 'fs';\nimport yaml = require('js-yaml');\nimport path = require('path');\nimport {validate} from '../../src'\n\nlet fixtures = fs.readdirSync(path.join(__dirname, 'fixtures'));\nfixtures = fixtures.filter(item => !item.includes('.skip'));\nif (fixtures.find(item => item.includes('.only'))) {\n  fixtures = fixtures.filter(item => item.includes('.only'));\n}\n\nfor (const dir of fixtures) {\n  const fullPath = path.join(__dirname, 'fixtures', dir);\n  test(`should be right in dir ${dir}`, async (done) => {\n    const json: any = yaml.safeLoad(fs.readFileSync(path.resolve(fullPath, 'schema.json'), 'utf-8'));\n    let validateResult: any;\n    try {\n      validateResult = validate(json)\n    } catch (e) {\n      validateResult = e.message;\n    }\n    expect(validateResult).toMatchSnapshot();\n    done();\n  });\n}\n"
  },
  {
    "path": "modules/material-parser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    // Enable strictest settings like strictNullChecks & noImplicitAny.\n    \"strict\": false,\n    // Allow json import\n    \"resolveJsonModule\": true,\n    // skip type checking of declaration files\n    \"skipLibCheck\": true,\n    \"baseUrl\": \"./packages\",\n    \"allowJs\": true,\n    \"outDir\": \"lib\",\n    \"lib\": [\"es2018\"],\n    \"module\": \"commonjs\",\n    \"target\": \"es2018\"\n  },\n  \"exclude\": [\"**/test\", \"**/lib\", \"**/dist\", \"**/es\", \"node_modules\", \"schemas\"],\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "modules/material-parser/webpack.config.js",
    "content": "const path = require('path');\nconst nodeExternals = require('webpack-node-externals');\nconst CopyPlugin = require('copy-webpack-plugin');\n\nmodule.exports = {\n  entry: './src/index.ts',\n  target: 'node',\n  output: {\n    path: path.resolve(__dirname, 'dist'),\n    filename: 'index.js',\n    library: {\n      type: 'commonjs2',\n    },\n  },\n  mode: 'production',\n  module: {\n    rules: [\n      {\n        test: /\\.tsx?$/,\n        use: 'ts-loader',\n        exclude: /node_modules/,\n      },\n    ],\n  },\n  externalsPresets: { node: true }, // in order to ignore built-in modules like path, fs, etc.\n  externals: [nodeExternals()], // in order to ignore all modules in node_modules folder\n  resolve: {\n    extensions: ['.tsx', '.ts', '.js'],\n  },\n  plugins: [\n    new CopyPlugin({\n      patterns: [\n        {\n          from: path.resolve(__dirname, 'src/parse/ts/tsconfig.json'),\n          to: path.resolve(__dirname, 'dist/tsconfig.json'),\n        },\n      ],\n    }),\n  ],\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"workspaces\": {\n    \"packages\": [\n      \"packages/*\"\n    ],\n    \"nohoist\": [\n      \"**/css-modules-typescript-loader\",\n      \"**/@alifc/theme-lowcode-*\",\n      \"**/jest\"\n    ]\n  },\n  \"scripts\": {\n    \"build\": \"./scripts/build.sh\",\n    \"build:npm\": \"lerna run build --stream\",\n    \"build:umd\": \"lerna run build:umd --stream\",\n    \"clean\": \"rimraf ./packages/*/lib ./packages/*/es ./packages/*/dist ./packages/*/build\",\n    \"clean:lib\": \"rimraf ./node_modules\",\n    \"lint\": \"f2elint scan -q -i ./packages/*/src\",\n    \"lint:fix\": \"f2elint fix -i ./packages/*/src\",\n    \"lint:modules\": \"f2elint scan -q -i ./modules/*/src\",\n    \"lint:modules:fix\": \"f2elint fix -i ./modules/*/src\",\n    \"pub\": \"npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog\",\n    \"pub:minor\": \"npm run watchdog:build && lerna publish minor --yes --force-publish --exact --no-changelog\",\n    \"pub:major\": \"npm run watchdog:build && lerna publish major --yes --force-publish --exact --no-changelog\",\n    \"pub:premajor\": \"npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog\",\n    \"pub:preminor\": \"npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog\",\n    \"pub:prepatch\": \"npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog\",\n    \"pub:prerelease\": \"npm run watchdog:build && lerna publish prerelease --yes --force-publish --exact --dist-tag beta --preid beta --no-changelog\",\n    \"setup\": \"node ./scripts/setup.js\",\n    \"setup:test\": \"./scripts/setup-for-test.sh\",\n    \"setup:skip-build\": \"./scripts/setup-skip-build.sh\",\n    \"start\": \"node ./scripts/start.js\",\n    \"test\": \"lerna run test --stream\",\n    \"test:snapshot\": \"lerna run test:snapshot\",\n    \"watchdog:build\": \"node ./scripts/watchdog.js\",\n    \"sync\": \"./scripts/sync.sh\",\n    \"syncOss\": \"node ./scripts/sync-oss.js\"\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"f2elint commit-file-scan\",\n      \"commit-msg\": \"f2elint commit-msg-scan\"\n    }\n  },\n  \"devDependencies\": {\n    \"del\": \"^6.1.1\",\n    \"execa\": \"^5.1.1\",\n    \"f2elint\": \"^2.0.1\",\n    \"gulp\": \"^4.0.2\",\n    \"husky\": \"^7.0.4\",\n    \"lerna\": \"^4.0.0\",\n    \"typescript\": \"4.6.2\",\n    \"yarn\": \"^1.22.17\",\n    \"rimraf\": \"^3.0.2\",\n    \"@types/react-router\": \"5.1.18\",\n    \"@alilc/build-plugin-lce\": \"^0.0.5\",\n    \"babel-jest\": \"^26.5.2\",\n    \"@alilc/lowcode-test-mate\": \"^1.0.1\"\n  },\n  \"engines\": {\n    \"node\": \">=14.17.0 <18\"\n  },\n  \"tnpm\": {\n    \"mode\": \"yarn\",\n    \"lockfile\": \"enable\"\n  },\n  \"resolutions\": {\n    \"typescript\": \"4.6.2\",\n    \"react-error-overlay\": \"6.0.9\"\n  },\n  \"repository\": \"git@github.com:alibaba/lowcode-engine.git\"\n}\n"
  },
  {
    "path": "packages/designer/README.md",
    "content": ""
  },
  {
    "path": "packages/designer/babel.config.js",
    "content": "module.exports = require('../../babel.config');"
  },
  {
    "path": "packages/designer/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\"\n  ]\n}\n"
  },
  {
    "path": "packages/designer/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ],\n  \"babelPlugins\": [\n    [\"@babel/plugin-proposal-private-property-in-object\", { \"loose\": true }]\n  ]\n}\n"
  },
  {
    "path": "packages/designer/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  // transform: {\n  //   '^.+\\\\.[jt]sx?$': 'babel-jest',\n  //   // '^.+\\\\.(ts|tsx)$': 'ts-jest',\n  //   // '^.+\\\\.(js|jsx)$': 'babel-jest',\n  // },\n  // testMatch: ['**/node-children.test.ts'],\n  // testMatch: ['**/plugin-manager.test.ts'],\n  // testMatch: ['**/history/history.test.ts'],\n  // testMatch: ['**/document-model.test.ts'],\n  // testMatch: ['**/prop.test.ts'],\n  // testMatch: ['(/tests?/.*(test))\\\\.[jt]s$'],\n  // testMatch: ['**/document/node/node.add.test.ts'],\n  // testMatch: ['**/setting-field.test.ts'],\n  // testMatch: ['**/node.test.ts'],\n  // testMatch: ['**/builtin-hotkey.test.ts'],\n  // testMatch: ['**/selection.test.ts'],\n  // testMatch: ['**/plugin/sequencify.test.ts'],\n  // testMatch: ['**/builtin-simulator/utils/parse-metadata.test.ts'],\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  setupFiles: ['./tests/fixtures/unhandled-rejection.ts'],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: false,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    '!src/**/*.d.ts',\n    '!src/icons/**',\n    '!src/locale/**',\n    '!src/builtin-simulator/utils/**',\n    '!src/plugin/sequencify.ts',\n    '!src/document/node/exclusive-group.ts',\n    '!src/document/node/props/value-to-source.ts',\n    '!src/builtin-simulator/live-editing/live-editing.ts',\n    '!src/designer/offset-observer.ts',\n    '!src/designer/clipboard.ts',\n    '!src/designer/scroller.ts',\n    '!src/builtin-simulator/host.ts',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/designer/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-designer\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Designer for Ali LowCode Engine\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"scripts\": {\n    \"build\": \"build-scripts build\",\n    \"test\": \"build-scripts test --config build.test.json\",\n    \"test:cov\": \"build-scripts test --config build.test.json --jest-coverage\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@alilc/lowcode-editor-core\": \"1.3.2\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"react\": \"^16\",\n    \"react-dom\": \"^16.7.0\",\n    \"ric-shim\": \"^1.0.1\",\n    \"semver\": \"^7.3.5\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.29\",\n    \"@testing-library/react\": \"^11.2.2\",\n    \"@types/classnames\": \"^2.2.7\",\n    \"@types/enzyme\": \"^3.10.12\",\n    \"@types/enzyme-adapter-react-16\": \"^1.0.6\",\n    \"@types/jest\": \"^26.0.16\",\n    \"@types/lodash\": \"^4.14.165\",\n    \"@types/medium-editor\": \"^5.0.3\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\",\n    \"@types/react-dom\": \"^16\",\n    \"@types/semver\": \"7.3.9\",\n    \"enzyme\": \"^3.11.0\",\n    \"enzyme-adapter-react-16\": \"^1.15.5\",\n    \"jest\": \"^26.6.3\",\n    \"lodash\": \"^4.17.20\",\n    \"moment\": \"^2.29.1\",\n    \"typescript\": \"^4.0.3\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/designer\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/README.md",
    "content": "内置模拟器主进程\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/bem-tools.less",
    "content": ".lc-bem-tools {\n  pointer-events: none;\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  overflow: visible;\n  z-index: 1;\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/border-container.tsx",
    "content": "import * as React from 'react';\nimport { Component, Fragment, ReactElement, PureComponent } from 'react';\nimport classNames from 'classnames';\nimport { computed, observer, Title, globalLocale } from '@alilc/lowcode-editor-core';\nimport { IPublicTypeI18nData, IPublicTypeTitleContent } from '@alilc/lowcode-types';\nimport { isI18nData } from '@alilc/lowcode-utils';\nimport { DropLocation } from '../../designer';\nimport { BuiltinSimulatorHost } from '../../builtin-simulator/host';\nimport { INode } from '../../document/node';\n\nexport class BorderContainerInstance extends PureComponent<{\n  title: IPublicTypeTitleContent;\n  rect: DOMRect | null;\n  scale: number;\n  scrollX: number;\n  scrollY: number;\n}> {\n  render() {\n    const { title, rect, scale, scrollX, scrollY } = this.props;\n    if (!rect) {\n      return null;\n    }\n\n    const style = {\n      width: rect.width * scale,\n      height: rect.height * scale,\n      transform: `translate(${(scrollX + rect.left) * scale}px, ${(scrollY + rect.top) * scale}px)`,\n    };\n\n    const className = classNames('lc-borders lc-borders-detecting');\n\n    return (\n      <div className={className} style={style}>\n        <Title title={title} className=\"lc-borders-title\" />\n      </div>\n    );\n  }\n}\n\nfunction getTitle(title: string | IPublicTypeI18nData | ReactElement) {\n  if (typeof title === 'string') return title;\n  if (isI18nData(title)) {\n    const locale = globalLocale.getLocale() || 'zh-CN';\n    return `将放入到此${title[locale]}`;\n  }\n  return '';\n}\n\n@observer\nexport class BorderContainer extends Component<{\n  host: BuiltinSimulatorHost;\n}, {\n  target?: INode;\n}> {\n  state = {} as any;\n\n  @computed get scale() {\n    return this.props.host.viewport.scale;\n  }\n\n  @computed get scrollX() {\n    return this.props.host.viewport.scrollX;\n  }\n\n  @computed get scrollY() {\n    return this.props.host.viewport.scrollY;\n  }\n\n  componentDidMount() {\n    const { host } = this.props;\n\n    host.designer.editor.eventBus.on('designer.dropLocation.change', (loc: DropLocation) => {\n      let { target } = this.state;\n      if (target === loc?.target) return;\n      this.setState({\n        target: loc?.target,\n      });\n    });\n  }\n\n  render() {\n    const { host } = this.props;\n    const { target } = this.state;\n    if (target == undefined) {\n      return null;\n    }\n    const instances = host.getComponentInstances(target!);\n    if (!instances || instances.length < 1) {\n      return null;\n    }\n\n    if (instances.length === 1) {\n      return (\n        <BorderContainerInstance\n          key=\"line-h\"\n          title={getTitle(target.componentMeta.title)}\n          scale={this.scale}\n          scrollX={this.scrollX}\n          scrollY={this.scrollY}\n          rect={host.computeComponentInstanceRect(instances[0], target.componentMeta.rootSelector)}\n        />\n      );\n    }\n    return (\n      <Fragment>\n        {instances.map((inst, i) => (\n          <BorderContainerInstance\n            key={`line-h-${i}`}\n            title={getTitle(target.componentMeta.title)}\n            scale={this.scale}\n            scrollX={this.scrollX}\n            scrollY={this.scrollY}\n            rect={host.computeComponentInstanceRect(inst, target.componentMeta.rootSelector)}\n          />\n        ))}\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx",
    "content": "import { Component, Fragment, PureComponent } from 'react';\nimport classNames from 'classnames';\nimport { computed, observer, Title } from '@alilc/lowcode-editor-core';\nimport { IPublicTypeTitleContent } from '@alilc/lowcode-types';\nimport { getClosestNode } from '@alilc/lowcode-utils';\nimport { intl } from '../../locale';\nimport { BuiltinSimulatorHost } from '../host';\n\nexport class BorderDetectingInstance extends PureComponent<{\n  title: IPublicTypeTitleContent;\n  rect: DOMRect | null;\n  scale: number;\n  scrollX: number;\n  scrollY: number;\n  isLocked?: boolean;\n}> {\n  render() {\n    const { title, rect, scale, scrollX, scrollY, isLocked } = this.props;\n    if (!rect) {\n      return null;\n    }\n\n    const style = {\n      width: rect.width * scale,\n      height: rect.height * scale,\n      transform: `translate(${(scrollX + rect.left) * scale}px, ${(scrollY + rect.top) * scale}px)`,\n    };\n\n    const className = classNames('lc-borders lc-borders-detecting');\n\n    // TODO:\n    // 1. thinkof icon\n    // 2. thinkof top|bottom|inner space\n\n    return (\n      <div className={className} style={style}>\n        <Title title={title} className=\"lc-borders-title\" />\n        {\n          isLocked ? (<Title title={intl('locked')} className=\"lc-borders-status\" />) : null\n        }\n      </div>\n    );\n  }\n}\n\n@observer\nexport class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {\n  @computed get scale() {\n    return this.props.host.viewport.scale;\n  }\n\n  @computed get scrollX() {\n    return this.props.host.viewport.scrollX;\n  }\n\n  @computed get scrollY() {\n    return this.props.host.viewport.scrollY;\n  }\n\n  @computed get current() {\n    const { host } = this.props;\n    const doc = host.currentDocument;\n    if (!doc) {\n      return null;\n    }\n    const { selection } = doc;\n    const { current } = host.designer.detecting;\n\n    if (!current || current.document !== doc || selection.has(current.id)) {\n      return null;\n    }\n    return current;\n  }\n\n  render() {\n    const { host } = this.props;\n    const { current } = this;\n\n    const canHoverHook = current?.componentMeta.advanced.callbacks?.onHoverHook;\n    const canHover = (canHoverHook && typeof canHoverHook === 'function') ? canHoverHook(current.internalToShellNode()) : true;\n\n    if (!canHover || !current || host.viewport.scrolling || host.liveEditing.editing) {\n      return null;\n    }\n\n    // rootNode, hover whole viewport\n    const focusNode = current.document.focusNode!;\n\n    if (!focusNode.contains(current)) {\n      return null;\n    }\n\n    if (current.contains(focusNode)) {\n      const bounds = host.viewport.bounds;\n      return (\n        <BorderDetectingInstance\n          key=\"line-root\"\n          title={current.title}\n          scale={this.scale}\n          scrollX={host.viewport.scrollX}\n          scrollY={host.viewport.scrollY}\n          rect={new DOMRect(0, 0, bounds.width, bounds.height)}\n        />\n      );\n    }\n\n    const lockedNode = getClosestNode(current, (n) => {\n      // 假如当前节点就是 locked 状态，要从当前节点的父节点开始查找\n      return !!(current?.isLocked ? n.parent?.isLocked : n.isLocked);\n    });\n    if (lockedNode && lockedNode.getId() !== current.getId()) {\n      // 选中父节锁定的节点\n      return (\n        <BorderDetectingInstance\n          key=\"line-h\"\n          title={current.title}\n          scale={this.scale}\n          scrollX={this.scrollX}\n          scrollY={this.scrollY}\n          // @ts-ignore\n          rect={host.computeComponentInstanceRect(host.getComponentInstances(lockedNode)[0], lockedNode.componentMeta.rootSelector)}\n          isLocked={lockedNode?.getId() !== current.getId()}\n        />\n      );\n    }\n\n    const instances = host.getComponentInstances(current);\n    if (!instances || instances.length < 1) {\n      return null;\n    }\n\n    if (instances.length === 1) {\n      return (\n        <BorderDetectingInstance\n          key=\"line-h\"\n          title={current.title}\n          scale={this.scale}\n          scrollX={this.scrollX}\n          scrollY={this.scrollY}\n          rect={host.computeComponentInstanceRect(instances[0], current.componentMeta.rootSelector)}\n        />\n      );\n    }\n    return (\n      <Fragment>\n        {instances.map((inst, i) => (\n          <BorderDetectingInstance\n            key={`line-h-${i}`}\n            title={current.title}\n            scale={this.scale}\n            scrollX={this.scrollX}\n            scrollY={this.scrollY}\n            rect={host.computeComponentInstanceRect(inst, current.componentMeta.rootSelector)}\n          />\n        ))}\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx",
    "content": "import React, { Component, Fragment } from 'react';\nimport DragResizeEngine from './drag-resize-engine';\nimport { observer, computed } from '@alilc/lowcode-editor-core';\nimport classNames from 'classnames';\nimport { SimulatorContext } from '../context';\nimport { BuiltinSimulatorHost } from '../host';\nimport { OffsetObserver, Designer, INode } from '../../designer';\nimport { Node } from '../../document';\nimport { normalizeTriggers } from '../../utils/misc';\n\n@observer\nexport default class BoxResizing extends Component<{ host: BuiltinSimulatorHost }> {\n  static contextType = SimulatorContext;\n\n  get host(): BuiltinSimulatorHost {\n    return this.props.host;\n  }\n\n  get dragging(): boolean {\n    return this.host.designer.dragon.dragging;\n  }\n\n  @computed get selecting() {\n    const doc = this.host.currentDocument;\n    if (!doc || doc.suspensed) {\n      return null;\n    }\n    const { selection } = doc;\n    return this.dragging ? selection.getTopNodes() : selection.getNodes();\n  }\n\n  componentDidUpdate() {\n    // this.hoveringCapture.setBoundary(this.outline);\n    // this.willBind();\n  }\n\n  render() {\n    const { selecting } = this;\n    if (!selecting || selecting.length < 1) {\n      // DIRTY FIX, recore has a bug!\n      return <Fragment />;\n    }\n\n    // const componentMeta = selecting[0].componentMeta;\n    // const metadata = componentMeta.getMetadata();\n\n    return (\n      <Fragment>\n        {selecting.map((node) => (\n          <BoxResizingForNode key={node.id} node={node} host={this.props.host} />\n        ))}\n      </Fragment>\n    );\n  }\n}\n\n@observer\nexport class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {\n  static contextType = SimulatorContext;\n\n  get host(): BuiltinSimulatorHost {\n    return this.props.host;\n  }\n\n  get dragging(): boolean {\n    return this.host.designer.dragon.dragging;\n  }\n\n  @computed get instances() {\n    return this.host.getComponentInstances(this.props.node);\n  }\n\n  render() {\n    const { instances } = this;\n    const { node } = this.props;\n    const { designer } = this.host;\n\n    if (!instances || instances.length < 1 || this.dragging) {\n      return null;\n    }\n    return (\n      <Fragment key={node.id}>\n        {instances.map((instance: any) => {\n          const observed = designer.createOffsetObserver({\n            node,\n            instance,\n          });\n          if (!observed) {\n            return null;\n          }\n          return (\n            <BoxResizingInstance key={observed.id} dragging={this.dragging} designer={designer} observed={observed} />\n          );\n        })}\n      </Fragment>\n    );\n  }\n}\n\n@observer\nexport class BoxResizingInstance extends Component<{\n  observed: OffsetObserver;\n  highlight?: boolean;\n  dragging?: boolean;\n  designer?: Designer;\n}> {\n  // private outline: any;\n  private willUnbind: () => any;\n\n  // outline of eight direction\n  private outlineN: any;\n  private outlineE: any;\n  private outlineS: any;\n  private outlineW: any;\n  private outlineNE: any;\n  private outlineNW: any;\n  private outlineSE: any;\n  private outlineSW: any;\n\n  private dragEngine: DragResizeEngine;\n\n  constructor(props: any) {\n    super(props);\n    this.dragEngine = new DragResizeEngine(props.designer);\n  }\n\n  componentWillUnmount() {\n    if (this.willUnbind) {\n      this.willUnbind();\n    }\n    this.props.observed.purge();\n  }\n\n  componentDidMount() {\n    // this.hoveringCapture.setBoundary(this.outline);\n    this.willBind();\n\n    const resize = (e: MouseEvent, direction: string, node: INode, moveX: number, moveY: number) => {\n      const { advanced } = node.componentMeta;\n      if (\n        advanced.callbacks &&\n        typeof advanced.callbacks.onResize === 'function'\n      ) {\n        (e as any).trigger = direction;\n        (e as any).deltaX = moveX;\n        (e as any).deltaY = moveY;\n        const cbNode = node?.isNode ? node.internalToShellNode() : node;\n        advanced.callbacks.onResize(e, cbNode);\n      }\n    };\n\n    const resizeStart = (e: MouseEvent, direction: string, node: INode) => {\n      const { advanced } = node.componentMeta;\n      if (\n        advanced.callbacks &&\n        typeof advanced.callbacks.onResizeStart === 'function'\n      ) {\n        (e as any).trigger = direction;\n        const cbNode = node?.isNode ? node.internalToShellNode() : node;\n        advanced.callbacks.onResizeStart(e, cbNode);\n      }\n    };\n\n    const resizeEnd = (e: MouseEvent, direction: string, node: INode) => {\n      const { advanced } = node.componentMeta;\n      if (\n        advanced.callbacks &&\n        typeof advanced.callbacks.onResizeEnd === 'function'\n      ) {\n        (e as any).trigger = direction;\n        const cbNode = node?.isNode ? node.internalToShellNode() : node;\n        advanced.callbacks.onResizeEnd(e, cbNode);\n      }\n\n      const editor = node.document?.designer.editor;\n      const npm = node?.componentMeta?.npm;\n      const selected =\n        [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||\n        node?.componentMeta?.componentName ||\n        '';\n      editor?.eventBus.emit('designer.border.resize', {\n        selected,\n        layout: node?.parent?.getPropValue('layout') || '',\n      });\n    };\n\n    this.dragEngine.onResize(resize);\n    this.dragEngine.onResizeStart(resizeStart);\n    this.dragEngine.onResizeEnd(resizeEnd);\n  }\n\n  willBind() {\n    if (this.willUnbind) {\n      this.willUnbind();\n    }\n\n    if (\n      !this.outlineN &&\n      !this.outlineE &&\n      !this.outlineS &&\n      !this.outlineW &&\n      !this.outlineNE &&\n      !this.outlineNW &&\n      !this.outlineSE &&\n      !this.outlineSW\n    ) {\n      return;\n    }\n\n    const unBind: any[] = [];\n    const { node } = this.props.observed;\n\n    unBind.push(\n      ...[\n        this.dragEngine.from(this.outlineN, 'n', () => node),\n        this.dragEngine.from(this.outlineE, 'e', () => node),\n        this.dragEngine.from(this.outlineS, 's', () => node),\n        this.dragEngine.from(this.outlineW, 'w', () => node),\n        this.dragEngine.from(this.outlineNE, 'ne', () => node),\n        this.dragEngine.from(this.outlineNW, 'nw', () => node),\n        this.dragEngine.from(this.outlineSE, 'se', () => node),\n        this.dragEngine.from(this.outlineSW, 'sw', () => node),\n      ],\n    );\n\n    this.willUnbind = () => {\n      if (unBind && unBind.length > 0) {\n        unBind.forEach((item) => {\n          item();\n        });\n      }\n      this.willUnbind = () => {};\n    };\n  }\n\n  render() {\n    const { observed } = this.props;\n    let triggerVisible: any = [];\n    let offsetWidth = 0;\n    let offsetHeight = 0;\n    let offsetTop = 0;\n    let offsetLeft = 0;\n    if (observed.hasOffset) {\n      offsetWidth = observed.offsetWidth;\n      offsetHeight = observed.offsetHeight;\n      offsetTop = observed.offsetTop;\n      offsetLeft = observed.offsetLeft;\n      const { node } = observed;\n      const metadata = node.componentMeta.getMetadata();\n      if (metadata.configure?.advanced?.getResizingHandlers) {\n        triggerVisible = metadata.configure.advanced.getResizingHandlers(node.internalToShellNode());\n      }\n    }\n    triggerVisible = normalizeTriggers(triggerVisible);\n\n    const baseSideClass = 'lc-borders lc-resize-side';\n    const baseCornerClass = 'lc-borders lc-resize-corner';\n\n    return (\n      <div>\n        <div\n          ref={(ref) => {\n            this.outlineN = ref;\n          }}\n          className={classNames(baseSideClass, 'n')}\n          style={{\n            height: 20,\n            transform: `translate(${offsetLeft}px, ${offsetTop - 10}px)`,\n            width: offsetWidth,\n            display: triggerVisible.includes('N') ? 'flex' : 'none',\n          }}\n        />\n        <div\n          ref={(ref) => {\n            this.outlineNE = ref;\n          }}\n          className={classNames(baseCornerClass, 'ne')}\n          style={{\n            transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop - 3}px)`,\n            cursor: 'nesw-resize',\n            display: triggerVisible.includes('NE') ? 'flex' : 'none',\n          }}\n        />\n        <div\n          className={classNames(baseSideClass, 'e')}\n          ref={(ref) => {\n            this.outlineE = ref;\n          }}\n          style={{\n            height: offsetHeight,\n            transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`,\n            width: 20,\n            display: triggerVisible.includes('E') ? 'flex' : 'none',\n          }}\n        />\n        <div\n          ref={(ref) => {\n            this.outlineSE = ref;\n          }}\n          className={classNames(baseCornerClass, 'se')}\n          style={{\n            transform: `translate(${offsetLeft + offsetWidth - 5}px, ${\n              offsetTop + offsetHeight - 5\n            }px)`,\n            cursor: 'nwse-resize',\n            display: triggerVisible.includes('SE') ? 'flex' : 'none',\n          }}\n        />\n        <div\n          ref={(ref) => {\n            this.outlineS = ref;\n          }}\n          className={classNames(baseSideClass, 's')}\n          style={{\n            height: 20,\n            transform: `translate(${offsetLeft}px, ${offsetTop + offsetHeight - 10}px)`,\n            width: offsetWidth,\n            display: triggerVisible.includes('S') ? 'flex' : 'none',\n          }}\n        />\n        <div\n          ref={(ref) => {\n            this.outlineSW = ref;\n          }}\n          className={classNames(baseCornerClass, 'sw')}\n          style={{\n            transform: `translate(${offsetLeft - 3}px, ${offsetTop + offsetHeight - 5}px)`,\n            cursor: 'nesw-resize',\n            display: triggerVisible.includes('SW') ? 'flex' : 'none',\n          }}\n        />\n        <div\n          ref={(ref) => {\n            this.outlineW = ref;\n          }}\n          className={classNames(baseSideClass, 'w')}\n          style={{\n            height: offsetHeight,\n            transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`,\n            width: 20,\n            display: triggerVisible.includes('W') ? 'flex' : 'none',\n          }}\n        />\n        <div\n          ref={(ref) => {\n            this.outlineNW = ref;\n          }}\n          className={classNames(baseCornerClass, 'nw')}\n          style={{\n            transform: `translate(${offsetLeft - 3}px, ${offsetTop - 3}px)`,\n            cursor: 'nwse-resize',\n            display: triggerVisible.includes('NW') ? 'flex' : 'none',\n          }}\n        />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx",
    "content": "import {\n  Component,\n  Fragment,\n  ReactNodeArray,\n  isValidElement,\n  cloneElement,\n  createElement,\n  ReactNode,\n  ComponentType,\n} from 'react';\nimport classNames from 'classnames';\nimport { observer, computed, Tip, engineConfig } from '@alilc/lowcode-editor-core';\nimport { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils';\nimport { IPublicTypeActionContentObject } from '@alilc/lowcode-types';\nimport { BuiltinSimulatorHost } from '../host';\nimport { INode, OffsetObserver } from '../../designer';\nimport NodeSelector from '../node-selector';\nimport { ISimulatorHost } from '../../simulator';\n\n@observer\nexport class BorderSelectingInstance extends Component<{\n  observed: OffsetObserver;\n  highlight?: boolean;\n  dragging?: boolean;\n}> {\n  componentWillUnmount() {\n    this.props.observed.purge();\n  }\n\n  render() {\n    const { observed, highlight, dragging } = this.props;\n    if (!observed.hasOffset) {\n      return null;\n    }\n\n    const { offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed;\n\n    const style = {\n      width: offsetWidth,\n      height: offsetHeight,\n      transform: `translate3d(${offsetLeft}px, ${offsetTop}px, 0)`,\n    };\n\n    const className = classNames('lc-borders lc-borders-selecting', {\n      highlight,\n      dragging,\n    });\n\n    const { hideSelectTools } = observed.node.componentMeta.advanced;\n    const hideComponentAction = engineConfig.get('hideComponentAction');\n\n    if (hideSelectTools) {\n      return null;\n    }\n\n    return (\n      <div\n        className={className}\n        style={style}\n      >\n        {(!dragging && !hideComponentAction) ? <Toolbar observed={observed} /> : null}\n      </div>\n    );\n  }\n}\n\n@observer\nclass Toolbar extends Component<{ observed: OffsetObserver }> {\n  render() {\n    const { observed } = this.props;\n    const { height, width } = observed.viewport;\n    const BAR_HEIGHT = 20;\n    const MARGIN = 1;\n    const BORDER = 2;\n    const SPACE_HEIGHT = BAR_HEIGHT + MARGIN + BORDER;\n    const SPACE_MINIMUM_WIDTH = 160; // magic number，大致是 toolbar 的宽度\n    let style: any;\n    // 计算 toolbar 的上/下位置\n    if (observed.top > SPACE_HEIGHT) {\n      style = {\n        top: -SPACE_HEIGHT,\n        height: BAR_HEIGHT,\n      };\n    } else if (observed.bottom + SPACE_HEIGHT < height) {\n      style = {\n        bottom: -SPACE_HEIGHT,\n        height: BAR_HEIGHT,\n      };\n    } else {\n      style = {\n        height: BAR_HEIGHT,\n        top: Math.max(MARGIN, MARGIN - observed.top),\n      };\n    }\n    // 计算 toolbar 的左/右位置\n    if (SPACE_MINIMUM_WIDTH > observed.left + observed.width) {\n      style.left = Math.max(-BORDER, observed.left - width - BORDER);\n    } else {\n      style.right = Math.max(-BORDER, observed.right - width - BORDER);\n      style.justifyContent = 'flex-start';\n    }\n    const { node } = observed;\n    const actions: ReactNodeArray = [];\n    node.componentMeta.availableActions.forEach((action) => {\n      const { important = true, condition, content, name } = action;\n      if (node.isSlot() && (name === 'copy' || name === 'remove')) {\n        // FIXME: need this?\n        return;\n      }\n      if (important && (typeof condition === 'function' ? condition(node) !== false : condition !== false)) {\n        actions.push(createAction(content, name, node));\n      }\n    });\n    return (\n      <div className=\"lc-borders-actions\" style={style}>\n        {actions}\n        <NodeSelector node={node} />\n      </div>\n    );\n  }\n}\n\nfunction createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: INode) {\n  if (isValidElement<{ key: string; node: INode }>(content)) {\n    return cloneElement(content, { key, node });\n  }\n  if (isReactComponent(content)) {\n    return createElement(content, { key, node });\n  }\n  if (isActionContentObject(content)) {\n    const { action, title, icon } = content;\n    return (\n      <div\n        key={key}\n        className=\"lc-borders-action\"\n        onClick={() => {\n          action && action(node.internalToShellNode()!);\n          const editor = node.document?.designer.editor;\n          const npm = node?.componentMeta?.npm;\n          const selected =\n            [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||\n            node?.componentMeta?.componentName ||\n            '';\n          editor?.eventBus.emit('designer.border.action', {\n            name: key,\n            selected,\n          });\n        }}\n      >\n        {icon && createIcon(icon, { key, node: node.internalToShellNode() })}\n        <Tip>{title}</Tip>\n      </div>\n    );\n  }\n  return null;\n}\n\n@observer\nexport class BorderSelectingForNode extends Component<{ host: ISimulatorHost; node: INode }> {\n  get host(): ISimulatorHost {\n    return this.props.host;\n  }\n\n  get dragging(): boolean {\n    return this.host.designer.dragon.dragging;\n  }\n\n  @computed get instances() {\n    return this.host.getComponentInstances(this.props.node);\n  }\n\n  render() {\n    const { instances } = this;\n    const { node } = this.props;\n    const { designer } = this.host;\n\n    if (!instances || instances.length < 1) {\n      return null;\n    }\n    return (\n      <Fragment key={node.id}>\n        {instances.map((instance) => {\n          const observed = designer.createOffsetObserver({\n            node,\n            instance,\n          });\n          if (!observed) {\n            return null;\n          }\n          return <BorderSelectingInstance key={observed.id} dragging={this.dragging} observed={observed} />;\n        })}\n      </Fragment>\n    );\n  }\n}\n\n@observer\nexport class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> {\n  get host(): BuiltinSimulatorHost {\n    return this.props.host;\n  }\n\n  get dragging(): boolean {\n    return this.host.designer.dragon.dragging;\n  }\n\n  @computed get selecting() {\n    const doc = this.host.currentDocument;\n    if (!doc || doc.suspensed || this.host.liveEditing.editing) {\n      return null;\n    }\n    const { selection } = doc;\n    return this.dragging ? selection.getTopNodes() : selection.getNodes();\n  }\n\n  render() {\n    const { selecting } = this;\n    if (!selecting || selecting.length < 1) {\n      return null;\n    }\n\n    return (\n      <Fragment>\n        {selecting.map((node) => (\n          <BorderSelectingForNode key={node.id} host={this.props.host} node={node} />\n        ))}\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/borders.less",
    "content": "@scope: lc-borders;\n\n.@{scope} {\n  box-sizing: border-box;\n  pointer-events: none;\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1;\n  border: 1px solid var(--color-brand-light);\n  will-change: transform, width, height;\n  overflow: visible;\n  & > &-title {\n    color: var(--color-brand-light);\n    transform: translateY(-100%);\n    font-weight: lighter;\n  }\n  & > &-status {\n    margin-left: 5px;\n    color: var(--color-text, #3c3c3c);\n    transform: translateY(-100%);\n    font-weight: lighter;\n  }\n  & > &-actions {\n    position: absolute;\n    display: flex;\n    flex-direction: row-reverse;\n    align-items: stretch;\n    justify-content: flex-end;\n    pointer-events: all;\n    > * {\n      flex-shrink: 0;\n    }\n  }\n\n  &-action,\n  .ve-icon-button.ve-action-save {\n    box-sizing: border-box;\n    cursor: pointer;\n    height: 20px;\n    width: 20px;\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    background: var(--color-brand, #006cff);\n    opacity: 1;\n    max-height: 100%;\n    overflow: hidden;\n    color: var(--color-icon-reverse, white);\n    &:hover {\n      background: var(--color-brand-light, #006cff);\n    }\n  }\n\n  &.lc-resize-corner {\n    display: inline-block;\n    width: 8px;\n    height: 8px;\n    border: 1px solid var(--color-brand, #197aff);\n    background: var(--color-block-background-normal, #fff);\n    pointer-events: auto;\n    z-index: 2;\n  }\n\n  &.lc-resize-side {\n    border-width: 0;\n    z-index: 1;\n    pointer-events: auto;\n    align-items: center;\n    justify-content: center;\n    display: flex;\n\n    &:after {\n      content: \"\";\n      display: block;\n      border: 1px solid var(--color-brand, #197aff);\n      background: var(--color-block-background-normal, #fff);\n      border-radius: 2px;\n    }\n\n    &.e,\n    &.w {\n      cursor: ew-resize;\n      &:after {\n        width: 4px;\n        min-height: 50%;\n      }\n    }\n\n    &.n,\n    &.s {\n      cursor: ns-resize;\n      &:after {\n        min-width: 50%;\n        height: 4px;\n      }\n    }\n  }\n\n  &&-detecting {\n    z-index: 1;\n    border-style: dashed;\n    background: var(--color-canvas-detecting-background, rgba(0,121,242,.04));\n  }\n\n  &&-selecting {\n    z-index: 2;\n    border-width: 2px;\n\n    &.dragging {\n      background: var(--color-layer-mask-background, rgba(182, 178, 178, 0.8));\n      border: none;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts",
    "content": "import { ISimulatorHost } from '../../simulator';\nimport { Designer, Point } from '../../designer';\nimport { cursor } from '@alilc/lowcode-utils';\nimport { makeEventsHandler } from '../../utils/misc';\nimport { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';\n\n// 拖动缩放\nexport default class DragResizeEngine {\n  private emitter: IEventBus;\n\n  private dragResizing = false;\n\n  private designer: Designer;\n\n  constructor(designer: Designer) {\n    this.designer = designer;\n    this.emitter = createModuleEventBus('DragResizeEngine');\n  }\n\n  isDragResizing() {\n    return this.dragResizing;\n  }\n\n  /**\n   * drag reszie from\n   * @param shell\n   * @param direction n/s/e/w\n   * @param boost (e: MouseEvent) => VE.Node\n   */\n  from(shell: Element, direction: string, boost: (e: MouseEvent) => any) {\n    let node: any;\n    let startEvent: Point;\n\n    if (!shell) {\n      return () => {};\n    }\n\n    const move = (e: MouseEvent) => {\n      const x = createResizeEvent(e);\n      const moveX = x.clientX - startEvent.clientX;\n      const moveY = x.clientY - startEvent.clientY;\n\n      this.emitter.emit('resize', e, direction, node, moveX, moveY);\n    };\n\n    const masterSensors = this.getMasterSensors();\n\n    /* istanbul ignore next */\n    const createResizeEvent = (e: MouseEvent | DragEvent): Point => {\n      const sourceDocument = e.view?.document;\n\n      if (!sourceDocument || sourceDocument === document) {\n        return e;\n      }\n      const srcSim = masterSensors.find(sim => sim.contentDocument === sourceDocument);\n      if (srcSim) {\n        return srcSim.viewport.toGlobalPoint(e);\n      }\n      return e;\n    };\n\n    const over = (e: MouseEvent) => {\n      const handleEvents = makeEventsHandler(e, masterSensors);\n      handleEvents(doc => {\n        doc.removeEventListener('mousemove', move, true);\n        doc.removeEventListener('mouseup', over, true);\n      });\n\n      this.dragResizing = false;\n      this.designer.detecting.enable = true;\n      cursor.release();\n\n      this.emitter.emit('resizeEnd', e, direction, node);\n    };\n\n    const mousedown = (e: MouseEvent) => {\n      node = boost(e);\n      startEvent = createResizeEvent(e);\n      const handleEvents = makeEventsHandler(e, masterSensors);\n      handleEvents(doc => {\n        doc.addEventListener('mousemove', move, true);\n        doc.addEventListener('mouseup', over, true);\n      });\n\n      this.emitter.emit('resizeStart', e, direction, node);\n      this.dragResizing = true;\n      this.designer.detecting.enable = false;\n      cursor.addState('ew-resize');\n    };\n    shell.addEventListener('mousedown', mousedown);\n    return () => {\n      shell.removeEventListener('mousedown', mousedown);\n    };\n  }\n\n  onResizeStart(func: (e: MouseEvent, direction: string, node: any) => any) {\n    this.emitter.on('resizeStart', func);\n    return () => {\n      this.emitter.removeListener('resizeStart', func);\n    };\n  }\n\n  onResize(\n    func: (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => any,\n  ) {\n    this.emitter.on('resize', func);\n    return () => {\n      this.emitter.removeListener('resize', func);\n    };\n  }\n\n  onResizeEnd(func: (e: MouseEvent, direction: string, node: any) => any) {\n    this.emitter.on('resizeEnd', func);\n    return () => {\n      this.emitter.removeListener('resizeEnd', func);\n    };\n  }\n\n  private getMasterSensors(): ISimulatorHost[] {\n    return this.designer.project.documents\n      .map(doc => {\n        if (doc.active && doc.simulator?.sensorAvailable) {\n          return doc.simulator;\n        }\n        return null;\n      })\n      .filter(Boolean) as any;\n  }\n}\n\n// new DragResizeEngine();\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/index.tsx",
    "content": "import React, { Component } from 'react';\nimport { observer, engineConfig } from '@alilc/lowcode-editor-core';\nimport { BorderDetecting } from './border-detecting';\nimport { BorderContainer } from './border-container';\nimport { BuiltinSimulatorHost } from '../host';\nimport { BorderSelecting } from './border-selecting';\nimport BorderResizing from './border-resizing';\nimport { InsertionView } from './insertion';\nimport './bem-tools.less';\nimport './borders.less';\n\n@observer\nexport class BemTools extends Component<{ host: BuiltinSimulatorHost }> {\n  render() {\n    const { host } = this.props;\n    const { designMode } = host;\n    const { scrollX, scrollY, scale } = host.viewport;\n    if (designMode === 'live') {\n      return null;\n    }\n    return (\n      <div className=\"lc-bem-tools\" style={{ transform: `translate(${-scrollX * scale}px,${-scrollY * scale}px)` }}>\n        { !engineConfig.get('disableDetecting') && <BorderDetecting key=\"hovering\" host={host} /> }\n        <BorderSelecting key=\"selecting\" host={host} />\n        { engineConfig.get('enableReactiveContainer') && <BorderContainer key=\"reactive-container-border\" host={host} /> }\n        <InsertionView key=\"insertion\" host={host} />\n        <BorderResizing key=\"resizing\" host={host} />\n        {\n          host.designer.bemToolsManager.getAllBemTools().map(tools => {\n            const ToolsCls = tools.item;\n            return <ToolsCls key={tools.name} host={host} />;\n          })\n        }\n      </div>\n    );\n  }\n}"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/insertion.less",
    "content": ".lc-insertion {\n  position: absolute;\n  top: -2px;\n  left: 0;\n  z-index: 12;\n  pointer-events: none !important;\n  background-color: var(--color-brand-light);\n  height: 4px;\n\n  &.cover {\n    top: 0;\n    height: auto;\n    width: auto;\n    border: none;\n    opacity: 0.3;\n  }\n\n  &.vertical {\n    top: 0;\n    left: -2px;\n    width: 4px;\n    height: auto;\n  }\n\n  &.invalid {\n    background-color: var(--color-error, var(--color-function-error, red));\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/insertion.tsx",
    "content": "import { Component } from 'react';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { BuiltinSimulatorHost } from '../host';\nimport {\n  DropLocation,\n  isVertical,\n} from '../../designer';\nimport { ISimulatorHost } from '../../simulator';\nimport { INode } from '../../document';\nimport './insertion.less';\nimport { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicTypeLocationChildrenDetail, IPublicTypeRect } from '@alilc/lowcode-types';\nimport { isLocationChildrenDetail } from '@alilc/lowcode-utils';\n\ninterface InsertionData {\n  edge?: DOMRect;\n  insertType?: string;\n  vertical?: boolean;\n  nearRect?: IPublicTypeRect;\n  coverRect?: DOMRect;\n  nearNode?: IPublicTypeNodeData;\n}\n\n/**\n * 处理拖拽子节点(INode)情况\n */\nfunction processChildrenDetail(sim: ISimulatorHost, container: INode, detail: IPublicTypeLocationChildrenDetail): InsertionData {\n  let edge = detail.edge || null;\n\n  if (!edge) {\n    edge = sim.computeRect(container);\n    if (!edge) {\n      return {};\n    }\n  }\n\n  const ret: any = {\n    edge,\n    insertType: 'before',\n  };\n\n  if (detail.near) {\n    const { node, pos, rect, align } = detail.near;\n    ret.nearRect = rect || sim.computeRect(node);\n    ret.nearNode = node;\n    if (pos === 'replace') {\n      // FIXME: ret.nearRect mybe null\n      ret.coverRect = ret.nearRect;\n      ret.insertType = 'cover';\n    } else if (!ret.nearRect || (ret.nearRect.width === 0 && ret.nearRect.height === 0)) {\n      ret.nearRect = ret.edge;\n      ret.insertType = 'after';\n      ret.vertical = isVertical(ret.nearRect);\n    } else {\n      ret.insertType = pos;\n      ret.vertical = align ? align === 'V' : isVertical(ret.nearRect);\n    }\n    return ret;\n  }\n\n  // from outline-tree: has index, but no near\n  // TODO: think of shadowNode & ConditionFlow\n  const { index } = detail;\n  if (index == null) {\n    ret.coverRect = ret.edge;\n    ret.insertType = 'cover';\n    return ret;\n  }\n  let nearNode = container.children.get(index);\n  if (!nearNode) {\n    // index = 0, eg. nochild,\n    nearNode = container.children.get(index > 0 ? index - 1 : 0);\n    if (!nearNode) {\n      ret.insertType = 'cover';\n      ret.coverRect = edge;\n      return ret;\n    }\n    ret.insertType = 'after';\n  }\n  if (nearNode) {\n    ret.nearRect = sim.computeRect(nearNode);\n    if (!ret.nearRect || (ret.nearRect.width === 0 && ret.nearRect.height === 0)) {\n      ret.nearRect = ret.edge;\n      ret.insertType = 'after';\n    }\n    ret.vertical = isVertical(ret.nearRect);\n    ret.nearNode = nearNode;\n  } else {\n    ret.insertType = 'cover';\n    ret.coverRect = edge;\n  }\n  return ret;\n}\n\n/**\n * 将 detail 信息转换为页面\"坐标\"信息\n */\nfunction processDetail({ target, detail, document }: DropLocation): InsertionData {\n  const sim = document.simulator;\n  if (!sim) {\n    return {};\n  }\n  if (isLocationChildrenDetail(detail)) {\n    return processChildrenDetail(sim, target, detail);\n  } else {\n    // TODO: others...\n    const instances = sim.getComponentInstances(target);\n    if (!instances) {\n      return {};\n    }\n    const edge = sim.computeComponentInstanceRect(instances[0], target.componentMeta.rootSelector);\n    return edge ? { edge, insertType: 'cover', coverRect: edge } : {};\n  }\n}\n\n@observer\nexport class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {\n  render() {\n    const { host } = this.props;\n    const loc = host.currentDocument?.dropLocation;\n    if (!loc) {\n      return null;\n    }\n    // 如果是个绝对定位容器，不需要渲染插入标记\n    if (loc.target?.componentMeta?.advanced.isAbsoluteLayoutContainer) {\n      return null;\n    }\n\n    const { scale, scrollX, scrollY } = host.viewport;\n    const { edge, insertType, coverRect, nearRect, vertical, nearNode } = processDetail(loc);\n\n    if (!edge) {\n      return null;\n    }\n\n    let className = 'lc-insertion';\n    if ((loc.detail as any)?.valid === false) {\n      className += ' invalid';\n    }\n    const style: any = {};\n    let x: number;\n    let y: number;\n    if (insertType === 'cover') {\n      className += ' cover';\n      x = (coverRect!.left + scrollX) * scale;\n      y = (coverRect!.top + scrollY) * scale;\n      style.width = coverRect!.width * scale;\n      style.height = coverRect!.height * scale;\n    } else {\n      if (!nearRect) {\n        return null;\n      }\n      if (vertical) {\n        className += ' vertical';\n        x = ((insertType === 'before' ? nearRect.left : nearRect.right) + scrollX) * scale;\n        y = (nearRect.top + scrollY) * scale;\n        style.height = nearRect!.height * scale;\n      } else {\n        x = (nearRect.left + scrollX) * scale;\n        y = ((insertType === 'before' ? nearRect.top : nearRect.bottom) + scrollY) * scale;\n        style.width = nearRect.width * scale;\n      }\n      if (y === 0 && (nearNode as IPublicTypeNodeSchema)?.componentMeta?.isTopFixed) {\n        return null;\n      }\n    }\n    style.transform = `translate3d(${x}px, ${y}px, 0)`;\n    // style.transition = 'all 0.2s ease-in-out';\n\n    return <div className={className} style={style} />;\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/bem-tools/manager.ts",
    "content": "import { ComponentType } from 'react';\nimport { Designer } from '../../designer';\nimport { invariant } from '../../utils';\nimport { BuiltinSimulatorHost } from '../../builtin-simulator/host';\n\nexport type BemToolsData = {\n  name: string;\n  item: ComponentType<{ host: BuiltinSimulatorHost }>;\n};\n\nexport class BemToolsManager {\n  private designer: Designer;\n\n  private toolsContainer: BemToolsData[] = [];\n\n  constructor(designer: Designer) {\n    this.designer = designer;\n  }\n\n  addBemTools(toolsData: BemToolsData) {\n    const found = this.toolsContainer.find(item => item.name === toolsData.name);\n    invariant(!found, `${toolsData.name} already exists`);\n\n    this.toolsContainer.push(toolsData);\n  }\n\n  removeBemTools(name: string) {\n    const index = this.toolsContainer.findIndex(item => item.name === name);\n    if (index !== -1) {\n      this.toolsContainer.splice(index, 1);\n    }\n  }\n\n  getAllBemTools() {\n    return this.toolsContainer;\n  }\n}"
  },
  {
    "path": "packages/designer/src/builtin-simulator/context.ts",
    "content": "import { createContext } from 'react';\nimport { BuiltinSimulatorHost } from './host';\n\nexport const SimulatorContext = createContext<BuiltinSimulatorHost>({} as any);\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/create-simulator.ts",
    "content": "// NOTE: 仅用作类型标注，切勿作为实体使用\nimport { BuiltinSimulatorHost } from './host';\nimport {\n  AssetLevel,\n  AssetLevels,\n  AssetList,\n  isAssetBundle,\n  isAssetItem,\n  AssetType,\n  assetItem,\n  isCSSUrl,\n} from '@alilc/lowcode-utils';\n\nimport { BuiltinSimulatorRenderer } from './renderer';\n\nexport function createSimulator(\n  host: BuiltinSimulatorHost,\n  iframe: HTMLIFrameElement,\n  vendors: AssetList = [],\n): Promise<BuiltinSimulatorRenderer> {\n  const win: any = iframe.contentWindow;\n  const doc = iframe.contentDocument!;\n  const innerPlugins = host.designer.editor.get('innerPlugins');\n\n  win.AliLowCodeEngine = innerPlugins._getLowCodePluginContext({});\n  win.LCSimulatorHost = host;\n  win._ = window._;\n\n  const styles: any = {};\n  const scripts: any = {};\n  AssetLevels.forEach((lv) => {\n    styles[lv] = [];\n    scripts[lv] = [];\n  });\n\n  function parseAssetList(assets: AssetList, level?: AssetLevel) {\n    for (let asset of assets) {\n      if (!asset) {\n        continue;\n      }\n      if (isAssetBundle(asset)) {\n        if (asset.assets) {\n          parseAssetList(\n            Array.isArray(asset.assets) ? asset.assets : [asset.assets],\n            asset.level || level,\n          );\n        }\n        continue;\n      }\n      if (Array.isArray(asset)) {\n        parseAssetList(asset, level);\n        continue;\n      }\n      if (!isAssetItem(asset)) {\n        asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!;\n      }\n      const id = asset.id ? ` data-id=\"${asset.id}\"` : '';\n      const lv = asset.level || level || AssetLevel.Environment;\n      const scriptType = asset.scriptType ? ` type=\"${asset.scriptType}\"` : '';\n      if (asset.type === AssetType.JSUrl) {\n        scripts[lv].push(\n          `<script src=\"${asset.content}\"${id}${scriptType}></script>`,\n        );\n      } else if (asset.type === AssetType.JSText) {\n        scripts[lv].push(`<script${id}${scriptType}>${asset.content}</script>`);\n      } else if (asset.type === AssetType.CSSUrl) {\n        styles[lv].push(\n          `<link rel=\"stylesheet\" href=\"${asset.content}\"${id} />`,\n        );\n      } else if (asset.type === AssetType.CSSText) {\n        styles[lv].push(\n          `<style type=\"text/css\"${id}>${asset.content}</style>`,\n        );\n      }\n    }\n  }\n\n  parseAssetList(vendors);\n\n  const styleFrags = Object.keys(styles)\n    .map((key) => {\n      return `${styles[key].join('\\n')}<meta level=\"${key}\" />`;\n    })\n    .join('');\n  const scriptFrags = Object.keys(scripts)\n    .map((key) => {\n      return scripts[key].join('\\n');\n    })\n    .join('');\n\n  doc.open();\n  doc.write(`\n<!doctype html>\n<html class=\"engine-design-mode\">\n  <head><meta charset=\"utf-8\"/>\n    ${styleFrags}\n  </head>\n  <body>\n    ${scriptFrags}\n  </body>\n</html>`);\n  doc.close();\n\n  return new Promise((resolve) => {\n    const renderer = win.SimulatorRenderer;\n    if (renderer) {\n      return resolve(renderer);\n    }\n    const loaded = () => {\n      resolve(win.SimulatorRenderer || host.renderer);\n      win.removeEventListener('load', loaded);\n    };\n    win.addEventListener('load', loaded);\n  });\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/host-view.tsx",
    "content": "import React, { Component } from 'react';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { BuiltinSimulatorHost, BuiltinSimulatorProps } from './host';\nimport { BemTools } from './bem-tools';\nimport { Project } from '../project';\nimport './host.less';\n\n/*\n  Simulator 模拟器，可替换部件，有协议约束，包含画布的容器，使用场景：当 Canvas 大小变化时，用来居中处理 或 定位 Canvas\n  Canvas(DeviceShell) 设备壳层，通过背景图片来模拟，通过设备预设样式改变宽度、高度及定位 CanvasViewport\n  CanvasViewport 页面编排场景中宽高不可溢出 Canvas 区\n  Content(Shell) 内容外层，宽高紧贴 CanvasViewport，禁用边框，禁用 margin\n  BemTools 辅助显示层，初始相对 Content 位置 0,0，紧贴 Canvas, 根据 Content 滚动位置，改变相对位置\n*/\n\ntype SimulatorHostProps = BuiltinSimulatorProps & {\n  project: Project;\n  onMount?: (host: BuiltinSimulatorHost) => void;\n};\n\nexport class BuiltinSimulatorHostView extends Component<SimulatorHostProps> {\n  readonly host: BuiltinSimulatorHost;\n\n  constructor(props: any) {\n    super(props);\n    const { project, onMount, designer } = this.props;\n    this.host = (project.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(project, designer);\n    this.host.setProps(this.props);\n    onMount?.(this.host);\n  }\n\n  shouldComponentUpdate(nextProps: BuiltinSimulatorProps) {\n    this.host.setProps(nextProps);\n    return false;\n  }\n\n  render() {\n    return (\n      <div className=\"lc-simulator\">\n        {/* progressing.visible ? <PreLoaderView /> : null */}\n        <Canvas host={this.host} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Canvas extends Component<{ host: BuiltinSimulatorHost }> {\n  render() {\n    const sim = this.props.host;\n    let className = 'lc-simulator-canvas';\n    const { canvas = {}, viewport = {} } = sim.deviceStyle || {};\n    if (sim.deviceClassName) {\n      className += ` ${sim.deviceClassName}`;\n    } else if (sim.device) {\n      className += ` lc-simulator-device-${sim.device}`;\n    }\n\n    return (\n      <div className={className} style={canvas}>\n        <div ref={(elmt) => sim.mountViewport(elmt)} className=\"lc-simulator-canvas-viewport\" style={viewport}>\n          <BemTools host={sim} />\n          <Content host={sim} />\n        </div>\n      </div>\n    );\n  }\n}\n\n@observer\nclass Content extends Component<{ host: BuiltinSimulatorHost }> {\n  state = {\n    disabledEvents: false,\n  };\n\n  private dispose?: () => void;\n\n  componentDidMount() {\n    const editor = this.props.host.designer.editor;\n    const onEnableEvents = (type: boolean) => {\n      this.setState({\n        disabledEvents: type,\n      });\n    };\n\n    editor.eventBus.on('designer.builtinSimulator.disabledEvents', onEnableEvents);\n\n    this.dispose = () => {\n      editor.removeListener('designer.builtinSimulator.disabledEvents', onEnableEvents);\n    };\n  }\n\n  componentWillUnmount() {\n    this.dispose?.();\n  }\n\n  render() {\n    const sim = this.props.host;\n    const { disabledEvents } = this.state;\n    const { viewport, designer } = sim;\n    const frameStyle: any = {\n      transform: `scale(${viewport.scale})`,\n      height: viewport.contentHeight,\n      width: viewport.contentWidth,\n    };\n    if (disabledEvents) {\n      frameStyle.pointerEvents = 'none';\n    }\n\n    const { viewName } = designer;\n\n    return (\n      <div className=\"lc-simulator-content\">\n        <iframe\n          name={`${viewName}-SimulatorRenderer`}\n          className=\"lc-simulator-content-frame\"\n          style={frameStyle}\n          ref={(frame) => sim.mountContentFrame(frame)}\n        />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/host.less",
    "content": "@scope: lc-simulator;\n\n.@{scope} {\n  position: relative;\n  height: 100%;\n  width: 100%;\n  overflow: auto;\n\n  &-canvas {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    width: 100%;\n    overflow: hidden;\n\n    &-viewport {\n      position: absolute;\n      top: 0;\n      bottom: 0;\n      left: 0;\n      width: 100%;\n    }\n  }\n\n  &-device-mobile {\n    left: 50%;\n    width: 375px;\n    top: 16px;\n    bottom: 16px;\n    max-height: calc(100% - 32px);\n    max-width: calc(100% - 32px);\n    transform: translateX(-50%);\n    box-shadow: 0 2px 10px 0 var(--color-block-background-shallow, rgba(31,56,88,.15));\n  }\n\n  &-device-iphonex { // 增加默认的小程序的壳\n    left: 50%;\n    top: 50%;\n    transform: translate(-50%, -50%);\n    width: 375px;\n    height: 812px;\n    max-height: calc(100vh - 50px);\n    background: url(https://img.alicdn.com/tfs/TB1b4DHilFR4u4jSZFPXXanzFXa-750-1574.png) no-repeat top;\n    background-size: 375px 812px;\n    border-radius: 44px;\n    box-shadow: var(--color-block-background-shallow, rgba(0, 0, 0, 0.1)) 0 36px 42px;\n    .@{scope}-canvas-viewport {\n      width: auto;\n      top: 50px;\n      left: 0;\n      right: 0;\n      margin-top: 40px;\n      max-height: 688px;\n    }\n  }\n\n  &-device-iphone6 {\n    left: 50%;\n    width: 375px;\n    transform: translateX(-50%);\n    background: url(https://img.alicdn.com/tps/TB12GetLpXXXXXhXFXXXXXXXXXX-756-1544.png) no-repeat top;\n    background-size: 375px 772px;\n    top: 8px;\n    .@{scope}-canvas-viewport {\n      width: auto;\n      top: 114px;\n      left: 25px;\n      right: 25px;\n      max-height: 561px;\n      border-radius: 0 0 2px 2px;\n    }\n  }\n\n  &-device-default {\n    top: var(--simulator-top-distance, 16px);\n    right: var(--simulator-right-distance, 16px);\n    bottom: var(--simulator-bottom-distance, 16px);\n    left: var(--simulator-left-distance, 16px);\n    width: auto;\n    box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.125));\n  }\n\n  &-content {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    width: 100%;\n    overflow: hidden;\n    &-frame {\n      border: none;\n      transform-origin: 0 0;\n      height: 100%;\n      width: 100%;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/host.ts",
    "content": "import {\n  obx,\n  autorun,\n  reaction,\n  computed,\n  getPublicPath,\n  engineConfig,\n  globalLocale,\n  IReactionPublic,\n  IReactionOptions,\n  IReactionDisposer,\n  makeObservable,\n  createModuleEventBus,\n  IEventBus,\n} from '@alilc/lowcode-editor-core';\n\nimport {\n  ISimulatorHost,\n  Component,\n  DropContainer,\n} from '../simulator';\nimport Viewport from './viewport';\nimport { createSimulator } from './create-simulator';\nimport { Node, INode, contains, isRootNode, isLowCodeComponent } from '../document';\nimport ResourceConsumer from './resource-consumer';\nimport {\n  AssetLevel,\n  Asset,\n  AssetList,\n  assetBundle,\n  assetItem,\n  AssetType,\n  isElement,\n  isFormEvent,\n  hasOwnProperty,\n  UtilsMetadata,\n  getClosestNode,\n  transactionManager,\n  isDragAnyObject,\n  isDragNodeObject,\n  isLocationData,\n  Logger,\n} from '@alilc/lowcode-utils';\nimport {\n  isShaken,\n  ILocateEvent,\n  isChildInline,\n  isRowContainer,\n  getRectTarget,\n  CanvasPoint,\n  Designer,\n  IDesigner,\n} from '../designer';\nimport { parseMetadata } from './utils/parse-metadata';\nimport { getClosestClickableNode } from './utils/clickable';\nimport {\n  IPublicTypeComponentMetadata,\n  IPublicTypePackage,\n  IPublicEnumTransitionType,\n  IPublicEnumDragObjectType,\n  IPublicTypeNodeInstance,\n  IPublicTypeComponentInstance,\n  IPublicTypeLocationChildrenDetail,\n  IPublicTypeLocationDetailType,\n  IPublicTypeRect,\n  IPublicModelNode,\n} from '@alilc/lowcode-types';\nimport { BuiltinSimulatorRenderer } from './renderer';\nimport { clipboard } from '../designer/clipboard';\nimport { LiveEditing } from './live-editing/live-editing';\nimport { IProject, Project } from '../project';\nimport { IScroller } from '../designer/scroller';\nimport { isElementNode, isDOMNodeVisible } from '../utils/misc';\nimport { debounce } from 'lodash';\n\nconst logger = new Logger({ level: 'warn', bizName: 'designer' });\n\nexport type LibraryItem = IPublicTypePackage & {\n  package: string;\n  library: string;\n  urls?: Asset;\n  editUrls?: Asset;\n};\n\nexport interface DeviceStyleProps {\n  canvas?: object;\n  viewport?: object;\n}\n\nexport interface BuiltinSimulatorProps {\n  // 从 documentModel 上获取\n  // suspended?: boolean;\n  designMode?: 'live' | 'design' | 'preview' | 'extend' | 'border';\n  device?: 'mobile' | 'iphone' | string;\n  deviceClassName?: string;\n  environment?: Asset;\n  // @TODO 补充类型\n  /** @property 请求处理器配置 */\n  requestHandlersMap?: any;\n  extraEnvironment?: Asset;\n  library?: LibraryItem[];\n  utilsMetadata?: UtilsMetadata;\n  simulatorUrl?: Asset;\n  theme?: Asset;\n  componentsAsset?: Asset;\n  // eslint-disable-next-line @typescript-eslint/member-ordering\n  [key: string]: any;\n}\n\nconst defaultSimulatorUrl = (() => {\n  const publicPath = getPublicPath();\n  let urls;\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  const [_, prefix = '', dev] = /^(.+?)(\\/js)?\\/?$/.exec(publicPath) || [];\n  if (dev) {\n    urls = [\n      `${prefix}/css/react-simulator-renderer.css`,\n      `${prefix}/js/react-simulator-renderer.js`,\n    ];\n  } else if (process.env.NODE_ENV === 'production') {\n    urls = [`${prefix}/react-simulator-renderer.css`, `${prefix}/react-simulator-renderer.js`];\n  } else {\n    urls = [`${prefix}/react-simulator-renderer.css`, `${prefix}/react-simulator-renderer.js`];\n  }\n  return urls;\n})();\n\nconst defaultEnvironment = [\n  // https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js\n  assetItem(\n    AssetType.JSText,\n    'window.React=parent.React;window.ReactDOM=parent.ReactDOM;window.__is_simulator_env__=true;',\n    undefined,\n    'react',\n  ),\n  assetItem(\n    AssetType.JSText,\n    'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',\n  ),\n];\n\nexport class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> {\n  readonly isSimulator = true;\n\n  readonly project: IProject;\n\n  readonly designer: IDesigner;\n\n  readonly viewport = new Viewport();\n\n  readonly scroller: IScroller;\n\n  readonly emitter: IEventBus = createModuleEventBus('BuiltinSimulatorHost');\n\n  readonly componentsConsumer: ResourceConsumer;\n\n  readonly injectionConsumer: ResourceConsumer;\n\n  readonly i18nConsumer: ResourceConsumer;\n\n  /**\n   * 是否为画布自动渲染\n   */\n  autoRender = true;\n\n  get currentDocument() {\n    return this.project.currentDocument;\n  }\n\n  @computed get renderEnv(): string {\n    return this.get('renderEnv') || 'default';\n  }\n\n  @computed get device(): string {\n    return this.get('device') || 'default';\n  }\n\n  @computed get locale(): string {\n    return this.get('locale') || globalLocale.getLocale();\n  }\n\n  @computed get deviceClassName(): string | undefined {\n    return this.get('deviceClassName');\n  }\n\n  @computed get designMode(): 'live' | 'design' | 'preview' {\n    // renderer 依赖\n    // TODO: 需要根据 design mode 不同切换鼠标响应情况\n    return this.get('designMode') || 'design';\n  }\n\n  @computed get requestHandlersMap(): any {\n    // renderer 依赖\n    // TODO: 需要根据 design mode 不同切换鼠标响应情况\n    return this.get('requestHandlersMap') || null;\n  }\n\n  get thisRequiredInJSE(): boolean {\n    return engineConfig.get('thisRequiredInJSE') ?? true;\n  }\n\n  get enableStrictNotFoundMode(): any {\n    return engineConfig.get('enableStrictNotFoundMode') ?? false;\n  }\n\n  get notFoundComponent(): any {\n    return engineConfig.get('notFoundComponent') ?? null;\n  }\n\n  get faultComponent(): any {\n    return engineConfig.get('faultComponent') ?? null;\n  }\n\n  get faultComponentMap(): any {\n    return engineConfig.get('faultComponentMap') ?? null;\n  }\n\n  @computed get componentsAsset(): Asset | undefined {\n    return this.get('componentsAsset');\n  }\n\n  @computed get theme(): Asset | undefined {\n    return this.get('theme');\n  }\n\n  @computed get componentsMap() {\n    // renderer 依赖\n    return this.designer.componentsMap;\n  }\n\n  @computed get deviceStyle(): DeviceStyleProps | undefined {\n    return this.get('deviceStyle');\n  }\n\n  @obx.ref _props: BuiltinSimulatorProps = {};\n\n  @obx.ref private _contentWindow?: Window;\n\n  get contentWindow() {\n    return this._contentWindow;\n  }\n\n  @obx.ref private _contentDocument?: Document;\n\n  @obx.ref private _appHelper?: any;\n\n  get contentDocument() {\n    return this._contentDocument;\n  }\n\n  private _renderer?: BuiltinSimulatorRenderer;\n\n  get renderer() {\n    return this._renderer;\n  }\n\n  readonly asyncLibraryMap: { [key: string]: {} } = {};\n\n  readonly libraryMap: { [key: string]: string } = {};\n\n  private _iframe?: HTMLIFrameElement;\n\n  private disableHovering?: () => void;\n\n  private disableDetecting?: () => void;\n\n  readonly liveEditing = new LiveEditing();\n\n  @obx private instancesMap: {\n    [docId: string]: Map<string, IPublicTypeComponentInstance[]>;\n  } = {};\n\n  private tryScrollAgain: number | null = null;\n\n  private _sensorAvailable = true;\n\n  /**\n   * @see IPublicModelSensor\n   */\n  get sensorAvailable(): boolean {\n    return this._sensorAvailable;\n  }\n\n  private sensing = false;\n\n  constructor(project: Project, designer: Designer) {\n    makeObservable(this);\n    this.project = project;\n    this.designer = designer;\n    this.scroller = this.designer.createScroller(this.viewport);\n    this.autoRender = !engineConfig.get('disableAutoRender', false);\n    this._appHelper = engineConfig.get('appHelper');\n    this.componentsConsumer = new ResourceConsumer<Asset | undefined>(() => this.componentsAsset);\n    this.injectionConsumer = new ResourceConsumer(() => {\n      return {\n        appHelper: this._appHelper,\n      };\n    });\n\n    engineConfig.onGot('appHelper', (data) => {\n      // appHelper被config.set修改后触发injectionConsumer.consume回调\n      this._appHelper = data;\n    });\n\n    this.i18nConsumer = new ResourceConsumer(() => this.project.i18n);\n\n    transactionManager.onStartTransaction(() => {\n      this.stopAutoRepaintNode();\n    }, IPublicEnumTransitionType.REPAINT);\n    // 防止批量调用 transaction 时，执行多次 rerender\n    const rerender = debounce(this.rerender.bind(this), 28);\n    transactionManager.onEndTransaction(() => {\n      rerender();\n      this.enableAutoRepaintNode();\n    }, IPublicEnumTransitionType.REPAINT);\n  }\n\n  stopAutoRepaintNode() {\n    this.renderer?.stopAutoRepaintNode();\n  }\n\n  enableAutoRepaintNode() {\n    this.renderer?.enableAutoRepaintNode();\n  }\n\n  /**\n   * @see ISimulator\n   */\n  setProps(props: BuiltinSimulatorProps) {\n    this._props = props;\n  }\n\n  set(key: string, value: any) {\n    this._props = {\n      ...this._props,\n      [key]: value,\n    };\n  }\n\n  get(key: string): any {\n    if (key === 'device') {\n      return (\n        this.designer?.editor?.get('deviceMapper')?.transform?.(this._props.device) ||\n        this._props.device\n      );\n    }\n    return this._props[key];\n  }\n\n  /**\n   * 有 Renderer 进程连接进来，设置同步机制\n   */\n  connect(\n    renderer: BuiltinSimulatorRenderer,\n    effect: (reaction: IReactionPublic) => void, options?: IReactionOptions,\n  ) {\n    this._renderer = renderer;\n    return autorun(effect, options);\n  }\n\n  reaction(expression: (reaction: IReactionPublic) => unknown, effect: (value: unknown, prev: unknown, reaction: IReactionPublic) => void,\n    opts?: IReactionOptions | undefined): IReactionDisposer {\n    return reaction(expression, effect, opts);\n  }\n\n  autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer {\n    return autorun(effect, options);\n  }\n\n  purge(): void {\n    // todo\n\n  }\n\n  mountViewport(viewport: HTMLElement | null) {\n    this.viewport.mount(viewport);\n  }\n\n  /**\n   * {\n   *   \"title\":\"BizCharts\",\n   *   \"package\":\"bizcharts\",\n   *   \"exportName\":\"bizcharts\",\n   *   \"version\":\"4.0.14\",\n   *   \"urls\":[\n   *      \"https://g.alicdn.com/code/lib/bizcharts/4.0.14/BizCharts.js\"\n   *   ],\n   *   \"library\":\"BizCharts\"\n   * }\n   * package：String 资源 npm 包名\n   * exportName：String umd 包导出名字，用于适配部分物料包 define name 不一致的问题，例如把 BizCharts 改成 bizcharts，用来兼容物料用 define 声明的 bizcharts\n   * version：String 版本号\n   * urls：Array 资源 cdn 地址，必须是 umd 类型，可以是.js 或者.css\n   * library：String umd 包直接导出的 name\n   */\n  buildLibrary(library?: LibraryItem[]) {\n    const _library = library || (this.get('library') as LibraryItem[]);\n    const libraryAsset: AssetList = [];\n    const libraryExportList: string[] = [];\n    const functionCallLibraryExportList: string[] = [];\n\n    if (_library && _library.length) {\n      _library.forEach((item) => {\n        const { exportMode, exportSourceLibrary } = item;\n        this.libraryMap[item.package] = item.library;\n        if (item.async) {\n          this.asyncLibraryMap[item.package] = item;\n        }\n        if (item.exportName && item.library) {\n          libraryExportList.push(\n            `Object.defineProperty(window,'${item.exportName}',{get:()=>window.${item.library}});`,\n          );\n        }\n        if (exportMode === 'functionCall' && exportSourceLibrary) {\n          functionCallLibraryExportList.push(\n            `window[\"${item.library}\"] = window[\"${exportSourceLibrary}\"](\"${item.library}\", \"${item.package}\");`,\n          );\n        }\n        if (item.editUrls) {\n          libraryAsset.push(item.editUrls);\n        } else if (item.urls) {\n          libraryAsset.push(item.urls);\n        }\n      });\n    }\n    libraryAsset.unshift(assetItem(AssetType.JSText, libraryExportList.join('')));\n    libraryAsset.push(assetItem(AssetType.JSText, functionCallLibraryExportList.join('')));\n    return libraryAsset;\n  }\n\n  rerender() {\n    this.designer.refreshComponentMetasMap();\n    this.renderer?.rerender?.();\n  }\n\n  async mountContentFrame(iframe: HTMLIFrameElement | null): Promise<void> {\n    if (!iframe || this._iframe === iframe) {\n      return;\n    }\n    this._iframe = iframe;\n\n    this._contentWindow = iframe.contentWindow!;\n    this._contentDocument = this._contentWindow.document;\n\n    const libraryAsset: AssetList = this.buildLibrary();\n\n    if (this.renderEnv === 'rax') {\n      logger.error('After LowcodeEngine v1.3.0, Rax is no longer supported.');\n    }\n\n    const vendors = [\n      // required & use once\n      assetBundle(\n        this.get('environment') ||\n        defaultEnvironment,\n        AssetLevel.Environment,\n      ),\n      // required & use once\n      assetBundle(this.get('extraEnvironment'), AssetLevel.Environment),\n\n      // required & use once\n      assetBundle(libraryAsset, AssetLevel.Library),\n      // required & TODO: think of update\n      assetBundle(this.theme, AssetLevel.Theme),\n      // required & use once\n      assetBundle(\n        this.get('simulatorUrl') ||\n        defaultSimulatorUrl,\n        AssetLevel.Runtime,\n      ),\n    ];\n\n    // wait 准备 iframe 内容、依赖库注入\n    const renderer = await createSimulator(this, iframe, vendors);\n\n    // TODO: !!! thinkof reload onloa\n\n    // wait 业务组件被第一次消费，否则会渲染出错\n    await this.componentsConsumer.waitFirstConsume();\n\n    // wait 运行时上下文\n    await this.injectionConsumer.waitFirstConsume();\n\n    if (Object.keys(this.asyncLibraryMap).length > 0) {\n      // 加载异步 Library\n      await renderer.loadAsyncLibrary(this.asyncLibraryMap);\n      Object.keys(this.asyncLibraryMap).forEach((key) => {\n        delete this.asyncLibraryMap[key];\n      });\n    }\n\n    // step 5 ready & render\n    renderer.run();\n\n    // init events, overlays\n    this.viewport.setScrollTarget(this._contentWindow);\n    this.setupEvents();\n\n    // bind hotkey & clipboard\n    const hotkey = this.designer.editor.get('innerHotkey');\n    hotkey.mount(this._contentWindow);\n    const innerSkeleton = this.designer.editor.get('skeleton');\n    innerSkeleton.focusTracker.mount(this._contentWindow);\n    clipboard.injectCopyPaster(this._contentDocument);\n\n    // TODO: dispose the bindings\n  }\n\n  async setupComponents(library: LibraryItem[]) {\n    const libraryAsset: AssetList = this.buildLibrary(library);\n    await this.renderer?.load(libraryAsset);\n    if (Object.keys(this.asyncLibraryMap).length > 0) {\n      // 加载异步 Library\n      await this.renderer?.loadAsyncLibrary(this.asyncLibraryMap);\n      Object.keys(this.asyncLibraryMap).forEach((key) => {\n        delete this.asyncLibraryMap[key];\n      });\n    }\n  }\n\n  setupEvents() {\n    // TODO: Thinkof move events control to simulator renderer\n    //       just listen special callback\n    // because iframe maybe reload\n    this.setupDragAndClick();\n    this.setupDetecting();\n    this.setupLiveEditing();\n    this.setupContextMenu();\n  }\n\n  postEvent(eventName: string, ...data: any[]) {\n    this.emitter.emit(eventName, ...data);\n  }\n\n  setupDragAndClick() {\n    const { designer } = this;\n    const doc = this.contentDocument!;\n\n    // TODO: think of lock when edit a node\n    // 事件路由\n    doc.addEventListener(\n      'mousedown',\n      (downEvent: MouseEvent) => {\n        // fix for popups close logic\n        document.dispatchEvent(new Event('mousedown'));\n        const documentModel = this.project.currentDocument;\n        if (this.liveEditing.editing || !documentModel) {\n          return;\n        }\n        const { selection } = documentModel;\n        let isMulti = false;\n        if (this.designMode === 'design') {\n          isMulti = downEvent.metaKey || downEvent.ctrlKey;\n        } else if (!downEvent.metaKey) {\n          return;\n        }\n        // FIXME: dirty fix remove label-for fro liveEditing\n        downEvent.target?.removeAttribute('for');\n        const nodeInst = this.getNodeInstanceFromElement(downEvent.target);\n        const { focusNode } = documentModel;\n        const node = getClosestClickableNode(nodeInst?.node || focusNode, downEvent);\n        // 如果找不到可点击的节点，直接返回\n        if (!node) {\n          return;\n        }\n        // 触发 onMouseDownHook 钩子\n        const onMouseDownHook = node.componentMeta.advanced.callbacks?.onMouseDownHook;\n        if (onMouseDownHook) {\n          onMouseDownHook(downEvent, node.internalToShellNode());\n        }\n        const rglNode = node?.getParent();\n        const isRGLNode = rglNode?.isRGLContainer;\n        if (isRGLNode) {\n          // 如果拖拽的是磁铁块的右下角 handle，则直接跳过\n          if (downEvent.target?.classList.contains('react-resizable-handle')) return;\n          // 禁止多选\n          isMulti = false;\n          designer.dragon.emitter.emit('rgl.switch', {\n            action: 'start',\n            rglNode,\n          });\n        } else {\n          // stop response document focus event\n          // 禁止原生拖拽\n          downEvent.stopPropagation();\n          downEvent.preventDefault();\n        }\n        // if (!node?.isValidComponent()) {\n        //   // 对于未注册组件直接返回\n        //   return;\n        // }\n        const isLeftButton = downEvent.which === 1 || downEvent.button === 0;\n        const checkSelect = (e: MouseEvent) => {\n          doc.removeEventListener('mouseup', checkSelect, true);\n          // 取消移动;\n          designer.dragon.emitter.emit('rgl.switch', {\n            action: 'end',\n            rglNode,\n          });\n          // 鼠标是否移动 ? - 鼠标抖动应该也需要支持选中事件，偶尔点击不能选中，磁帖块移除 shaken 检测\n          if (!isShaken(downEvent, e) || isRGLNode) {\n            let { id } = node;\n            designer.activeTracker.track({ node, instance: nodeInst?.instance });\n            if (isMulti && focusNode && !node.contains(focusNode) && selection.has(id)) {\n              selection.remove(id);\n            } else {\n              // TODO: 避免选中 Page 组件，默认选中第一个子节点；新增规则 或 判断 Live 模式\n              if (node.isPage() && node.getChildren()?.notEmpty() && this.designMode === 'live') {\n                const firstChildId = node.getChildren()?.get(0)?.getId();\n                if (firstChildId) id = firstChildId;\n              }\n              if (focusNode) {\n                selection.select(node.contains(focusNode) ? focusNode.id : id);\n              }\n\n              // dirty code should refector\n              const editor = this.designer?.editor;\n              const npm = node?.componentMeta?.npm;\n              const selected =\n                [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||\n                node?.componentMeta?.componentName ||\n                '';\n              editor?.eventBus.emit('designer.builtinSimulator.select', {\n                selected,\n              });\n            }\n          }\n        };\n\n        if (isLeftButton && focusNode && !node.contains(focusNode)) {\n          let nodes: INode[] = [node];\n          let ignoreUpSelected = false;\n          if (isMulti) {\n            // multi select mode, directily add\n            if (!selection.has(node.id)) {\n              designer.activeTracker.track({ node, instance: nodeInst?.instance });\n              selection.add(node.id);\n              ignoreUpSelected = true;\n            }\n            focusNode?.id && selection.remove(focusNode.id);\n            // 获得顶层 nodes\n            nodes = selection.getTopNodes();\n          } else if (selection.containsNode(node, true)) {\n            nodes = selection.getTopNodes();\n          } else {\n            // will clear current selection & select dragment in dragstart\n          }\n          designer.dragon.boost(\n            {\n              type: IPublicEnumDragObjectType.Node,\n              nodes,\n            },\n            downEvent,\n            isRGLNode ? rglNode : undefined,\n          );\n          if (ignoreUpSelected) {\n            // multi select mode has add selected, should return\n            return;\n          }\n        }\n\n        doc.addEventListener('mouseup', checkSelect, true);\n      },\n      true,\n    );\n\n    doc.addEventListener(\n      'click',\n      (e) => {\n        // fix for popups close logic\n        const x = new Event('click');\n        x.initEvent('click', true);\n        this._iframe?.dispatchEvent(x);\n        const { target } = e;\n\n        const customizeIgnoreSelectors = engineConfig.get('customizeIgnoreSelectors');\n        // TODO: need more elegant solution to ignore click events of components in designer\n        const defaultIgnoreSelectors: string[] = [\n          '.next-input-group',\n          '.next-checkbox-group',\n          '.next-checkbox-wrapper',\n          '.next-date-picker',\n          '.next-input',\n          '.next-month-picker',\n          '.next-number-picker',\n          '.next-radio-group',\n          '.next-range',\n          '.next-range-picker',\n          '.next-rating',\n          '.next-select',\n          '.next-switch',\n          '.next-time-picker',\n          '.next-upload',\n          '.next-year-picker',\n          '.next-breadcrumb-item',\n          '.next-calendar-header',\n          '.next-calendar-table',\n          '.editor-container', // 富文本组件\n        ];\n        const ignoreSelectors = customizeIgnoreSelectors?.(defaultIgnoreSelectors, e) || defaultIgnoreSelectors;\n        const ignoreSelectorsString = ignoreSelectors.join(',');\n        // 提供了 customizeIgnoreSelectors 的情况下，忽略 isFormEvent() 判断\n        if ((!customizeIgnoreSelectors && isFormEvent(e)) || target?.closest(ignoreSelectorsString)) {\n          e.preventDefault();\n          e.stopPropagation();\n        }\n        // stop response document click event\n        // todo: catch link redirect\n      },\n      true,\n    );\n  }\n\n  /**\n   * 设置悬停处理\n   */\n  setupDetecting() {\n    const doc = this.contentDocument!;\n    const { detecting, dragon } = this.designer;\n    const hover = (e: MouseEvent) => {\n      if (!detecting.enable || this.designMode !== 'design') {\n        return;\n      }\n      const nodeInst = this.getNodeInstanceFromElement(e.target as Element);\n      if (nodeInst?.node) {\n        let { node } = nodeInst;\n        const focusNode = node.document?.focusNode;\n        if (focusNode && node.contains(focusNode)) {\n          node = focusNode;\n        }\n        detecting.capture(node);\n      } else {\n        detecting.capture(null);\n      }\n      if (!engineConfig.get('enableMouseEventPropagationInCanvas', false) || dragon.dragging) {\n        e.stopPropagation();\n      }\n    };\n    const leave = () => {\n      this.project.currentDocument && detecting.leave(this.project.currentDocument);\n    };\n\n    doc.addEventListener('mouseover', hover, true);\n    doc.addEventListener('mouseleave', leave, false);\n\n    // TODO: refactor this line, contains click, mousedown, mousemove\n    doc.addEventListener(\n      'mousemove',\n      (e: Event) => {\n        if (!engineConfig.get('enableMouseEventPropagationInCanvas', false) || dragon.dragging) {\n          e.stopPropagation();\n        }\n      },\n      true,\n    );\n\n    // this.disableDetecting = () => {\n    //   detecting.leave(this.project.currentDocument);\n    //   doc.removeEventListener('mouseover', hover, true);\n    //   doc.removeEventListener('mouseleave', leave, false);\n    //   this.disableDetecting = undefined;\n    // };\n  }\n\n  setupLiveEditing() {\n    const doc = this.contentDocument!;\n    // cause edit\n    doc.addEventListener(\n      'dblclick',\n      (e: MouseEvent) => {\n        // stop response document dblclick event\n        e.stopPropagation();\n        e.preventDefault();\n\n        const targetElement = e.target as HTMLElement;\n        const nodeInst = this.getNodeInstanceFromElement(targetElement);\n        if (!nodeInst) {\n          return;\n        }\n        const focusNode = this.project.currentDocument?.focusNode;\n        const node = nodeInst.node || focusNode;\n        if (!node || isLowCodeComponent(node)) {\n          return;\n        }\n\n        const rootElement = this.findDOMNodes(\n          nodeInst.instance,\n          node.componentMeta.rootSelector,\n        )?.find(\n          (item) =>\n            // 可能是 [null];\n            item && item.contains(targetElement),\n        ) as HTMLElement;\n        if (!rootElement) {\n          return;\n        }\n\n        this.liveEditing.apply({\n          node,\n          rootElement,\n          event: e,\n        });\n      },\n      true,\n    );\n  }\n\n  /**\n   * @see ISimulator\n   */\n  setSuspense(/** _suspended: boolean */) {\n    return false;\n    // if (suspended) {\n    //   /*\n    //   if (this.disableDetecting) {\n    //     this.disableDetecting();\n    //   }\n    //   */\n    //   // sleep some autorun reaction\n    // } else {\n    //   // weekup some autorun reaction\n    //   /*\n    //   if (!this.disableDetecting) {\n    //     this.setupDetecting();\n    //   }\n    //   */\n    // }\n  }\n\n  setupContextMenu() {\n    const doc = this.contentDocument!;\n    doc.addEventListener('contextmenu', (e: MouseEvent) => {\n      const targetElement = e.target as HTMLElement;\n      const nodeInst = this.getNodeInstanceFromElement(targetElement);\n      const editor = this.designer?.editor;\n      if (!nodeInst) {\n        editor?.eventBus.emit('designer.builtinSimulator.contextmenu', {\n          originalEvent: e,\n        });\n        return;\n      }\n      const node = nodeInst.node || this.project.currentDocument?.focusNode;\n      if (!node) {\n        editor?.eventBus.emit('designer.builtinSimulator.contextmenu', {\n          originalEvent: e,\n        });\n        return;\n      }\n\n      // dirty code should refector\n      const npm = node?.componentMeta?.npm;\n      const selected =\n        [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||\n        node?.componentMeta?.componentName ||\n        '';\n      editor?.eventBus.emit('designer.builtinSimulator.contextmenu', {\n        selected,\n        ...nodeInst,\n        instanceRect: this.computeComponentInstanceRect(nodeInst.instance),\n        originalEvent: e,\n      });\n    });\n  }\n\n  /**\n   * @see ISimulator\n   */\n  generateComponentMetadata(componentName: string): IPublicTypeComponentMetadata {\n    // if html tags\n    if (isHTMLTag(componentName)) {\n      return {\n        componentName,\n        // TODO: read builtins html metadata\n      };\n    }\n\n    const component = this.getComponent(componentName);\n\n    if (!component) {\n      return {\n        componentName,\n      };\n    }\n\n    // TODO:\n    // 1. generate builtin div/p/h1/h2\n    // 2. read propTypes\n\n    return {\n      componentName,\n      ...parseMetadata(component),\n    };\n  }\n\n  /**\n   * @see ISimulator\n   */\n  getComponent(componentName: string): Component | null {\n    return this.renderer?.getComponent(componentName) || null;\n  }\n\n  createComponent(/** _schema: IPublicTypeComponentSchema */): Component | null {\n    return null;\n    // return this.renderer?.createComponent(schema) || null;\n  }\n\n  setInstance(docId: string, id: string, instances: IPublicTypeComponentInstance[] | null) {\n    if (!hasOwnProperty(this.instancesMap, docId)) {\n      this.instancesMap[docId] = new Map();\n    }\n    if (instances == null) {\n      this.instancesMap[docId].delete(id);\n    } else {\n      this.instancesMap[docId].set(id, instances.slice());\n    }\n  }\n\n  /**\n   * @see ISimulator\n   */\n  getComponentInstances(node: INode, context?: IPublicTypeNodeInstance): IPublicTypeComponentInstance[] | null {\n    const docId = node.document?.id;\n    if (!docId) {\n      return null;\n    }\n\n    const instances = this.instancesMap[docId]?.get(node.id) || null;\n    if (!instances || !context) {\n      return instances;\n    }\n\n    // filter with context\n    return instances.filter((instance) => {\n      return this.getClosestNodeInstance(instance, context?.nodeId)?.instance === context.instance;\n    });\n  }\n\n  /**\n   * @see ISimulator\n   */\n  getComponentContext(/* node: Node */): any {\n    throw new Error('Method not implemented.');\n  }\n\n  /**\n   * @see ISimulator\n   */\n  getClosestNodeInstance(\n    from: IPublicTypeComponentInstance,\n    specId?: string,\n  ): IPublicTypeNodeInstance<IPublicTypeComponentInstance> | null {\n    return this.renderer?.getClosestNodeInstance(from, specId) || null;\n  }\n\n  /**\n   * @see ISimulator\n   */\n  computeRect(node: INode): IPublicTypeRect | null {\n    const instances = this.getComponentInstances(node);\n    if (!instances) {\n      return null;\n    }\n    return this.computeComponentInstanceRect(instances[0], node.componentMeta.rootSelector);\n  }\n\n  /**\n   * @see ISimulator\n   */\n  computeComponentInstanceRect(instance: IPublicTypeComponentInstance, selector?: string): IPublicTypeRect | null {\n    const renderer = this.renderer!;\n    const elements = this.findDOMNodes(instance, selector);\n    if (!elements) {\n      return null;\n    }\n\n    const elems = elements.slice();\n    let rects: DOMRect[] | undefined;\n    let last: { x: number; y: number; r: number; b: number } | undefined;\n    let _computed = false;\n    while (true) {\n      if (!rects || rects.length < 1) {\n        const elem = elems.pop();\n        if (!elem) {\n          break;\n        }\n        rects = renderer.getClientRects(elem);\n      }\n      const rect = rects.pop();\n      if (!rect) {\n        break;\n      }\n      if (rect.width === 0 && rect.height === 0) {\n        continue;\n      }\n      if (!last) {\n        last = {\n          x: rect.left,\n          y: rect.top,\n          r: rect.right,\n          b: rect.bottom,\n        };\n        continue;\n      }\n      if (rect.left < last.x) {\n        last.x = rect.left;\n        _computed = true;\n      }\n      if (rect.top < last.y) {\n        last.y = rect.top;\n        _computed = true;\n      }\n      if (rect.right > last.r) {\n        last.r = rect.right;\n        _computed = true;\n      }\n      if (rect.bottom > last.b) {\n        last.b = rect.bottom;\n        _computed = true;\n      }\n    }\n\n    if (last) {\n      const r: IPublicTypeRect = new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y);\n      r.elements = elements;\n      r.computed = _computed;\n      return r;\n    }\n\n    return null;\n  }\n\n  /**\n   * @see ISimulator\n   */\n  findDOMNodes(instance: IPublicTypeComponentInstance, selector?: string): Array<Element | Text> | null {\n    const elements = this._renderer?.findDOMNodes(instance);\n    if (!elements) {\n      return null;\n    }\n\n    if (selector) {\n      const matched = getMatched(elements, selector);\n      if (!matched) {\n        return null;\n      }\n      return [matched];\n    }\n    return elements;\n  }\n\n  /**\n   * 通过 DOM 节点获取节点，依赖 simulator 的接口\n   */\n  getNodeInstanceFromElement(target: Element | null): IPublicTypeNodeInstance<IPublicTypeComponentInstance, INode> | null {\n    if (!target) {\n      return null;\n    }\n\n    const nodeInstance = this.getClosestNodeInstance(target);\n    if (!nodeInstance) {\n      return null;\n    }\n    const { docId } = nodeInstance;\n    const doc = this.project.getDocument(docId)!;\n    const node = doc.getNode(nodeInstance.nodeId);\n    return {\n      ...nodeInstance,\n      node,\n    };\n  }\n\n  /**\n   * @see ISimulator\n   */\n  /* istanbul ignore next */\n  scrollToNode(node: Node, detail?: any /* , tryTimes = 0 */) {\n    this.tryScrollAgain = null;\n    if (this.sensing) {\n      // active sensor\n      return;\n    }\n\n    const opt: any = {};\n    let scroll = false;\n\n    const componentInstance = this.getComponentInstances(detail?.near?.node || node)?.[0];\n    if (!componentInstance) return;\n    const domNode = this.findDOMNodes(componentInstance)?.[0] as Element;\n    if (!domNode) return;\n    if (isElementNode(domNode) && !isDOMNodeVisible(domNode, this.viewport)) {\n      const { left, top } = domNode.getBoundingClientRect();\n      const { scrollTop = 0, scrollLeft = 0 } = this.contentDocument?.documentElement || {};\n      opt.left = left + scrollLeft;\n      opt.top = top + scrollTop;\n      scroll = true;\n    }\n\n    if (scroll && this.scroller) {\n      this.scroller.scrollTo(opt);\n    }\n  }\n\n  // #region ========= drag and drop helpers =============\n  /**\n   * @see ISimulator\n   */\n  setNativeSelection(enableFlag: boolean) {\n    this.renderer?.setNativeSelection(enableFlag);\n  }\n\n  /**\n   * @see ISimulator\n   */\n  setDraggingState(state: boolean) {\n    this.renderer?.setDraggingState(state);\n  }\n\n  /**\n   * @see ISimulator\n   */\n  setCopyState(state: boolean) {\n    this.renderer?.setCopyState(state);\n  }\n\n  /**\n   * @see ISimulator\n   */\n  clearState() {\n    this.renderer?.clearState();\n  }\n\n  /**\n   * @see IPublicModelSensor\n   */\n  fixEvent(e: ILocateEvent): ILocateEvent {\n    if (e.fixed) {\n      return e;\n    }\n\n    const notMyEvent = e.originalEvent.view?.document !== this.contentDocument;\n    // fix canvasX canvasY : 当前激活文档画布坐标系\n    if (notMyEvent || !('canvasX' in e) || !('canvasY' in e)) {\n      const l = this.viewport.toLocalPoint({\n        clientX: e.globalX,\n        clientY: e.globalY,\n      });\n      e.canvasX = l.clientX;\n      e.canvasY = l.clientY;\n    }\n\n    // fix target : 浏览器事件响应目标\n    if (!e.target || notMyEvent) {\n      if (!isNaN(e.canvasX!) && !isNaN(e.canvasY!)) {\n        e.target = this.contentDocument?.elementFromPoint(e.canvasX!, e.canvasY!);\n      }\n    }\n\n    // 事件已订正\n    e.fixed = true;\n    return e;\n  }\n\n  /**\n   * @see IPublicModelSensor\n   */\n  isEnter(e: ILocateEvent): boolean {\n    const rect = this.viewport.bounds;\n    return (\n      e.globalY >= rect.top &&\n      e.globalY <= rect.bottom &&\n      e.globalX >= rect.left &&\n      e.globalX <= rect.right\n    );\n  }\n\n  /**\n   * @see IPublicModelSensor\n   */\n  deactiveSensor() {\n    this.sensing = false;\n    this.scroller.cancel();\n  }\n\n  // ========= drag location logic: helper for locate ==========\n\n  /**\n   * @see IPublicModelSensor\n   */\n  locate(e: ILocateEvent): any {\n    const { dragObject } = e;\n\n    const nodes = dragObject?.nodes;\n\n    const operationalNodes = nodes?.filter((node) => {\n      const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook;\n      const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node.internalToShellNode()) : true;\n\n      let parentContainerNode: INode | null = null;\n      let parentNode = node.parent;\n\n      while (parentNode) {\n        if (parentNode.isContainer()) {\n          parentContainerNode = parentNode;\n          break;\n        }\n\n        parentNode = parentNode.parent;\n      }\n\n      const onChildMoveHook = parentContainerNode?.componentMeta?.advanced.callbacks?.onChildMoveHook;\n\n      const childrenCanMove = onChildMoveHook && parentContainerNode && typeof onChildMoveHook === 'function' ? onChildMoveHook(node.internalToShellNode(), parentContainerNode.internalToShellNode()) : true;\n\n      return canMove && childrenCanMove;\n    });\n\n    if (nodes && (!operationalNodes || operationalNodes.length === 0)) {\n      return;\n    }\n\n    this.sensing = true;\n    this.scroller.scrolling(e);\n    const document = this.project.currentDocument;\n    if (!document) {\n      return null;\n    }\n    const dropContainer = this.getDropContainer(e);\n    const lockedNode = getClosestNode(dropContainer?.container, (node) => node.isLocked);\n    if (lockedNode) return null;\n    if (\n      !dropContainer\n    ) {\n      return null;\n    }\n\n    if (isLocationData(dropContainer)) {\n      return this.designer.createLocation(dropContainer);\n    }\n\n    const { container, instance: containerInstance } = dropContainer;\n\n    const edge = this.computeComponentInstanceRect(\n      containerInstance,\n      container.componentMeta.rootSelector,\n    );\n\n    if (!edge) {\n      return null;\n    }\n\n    const { children } = container;\n\n    const detail: IPublicTypeLocationChildrenDetail = {\n      type: IPublicTypeLocationDetailType.Children,\n      index: 0,\n      edge,\n    };\n\n    const locationData = {\n      target: container,\n      detail,\n      source: `simulator${document.id}`,\n      event: e,\n    };\n\n    if (\n      e.dragObject &&\n      e.dragObject.nodes &&\n      e.dragObject.nodes.length &&\n      e.dragObject.nodes[0].componentMeta.isModal &&\n      document.focusNode\n    ) {\n      return this.designer.createLocation({\n        target: document.focusNode,\n        detail,\n        source: `simulator${document.id}`,\n        event: e,\n      });\n    }\n\n    if (!children || children.size < 1 || !edge) {\n      return this.designer.createLocation(locationData);\n    }\n\n    let nearRect: IPublicTypeRect | null = null;\n    let nearIndex: number = 0;\n    let nearNode: INode | null = null;\n    let nearDistance: number | null = null;\n    let minTop: number | null = null;\n    let maxBottom: number | null = null;\n\n    for (let i = 0, l = children.size; i < l; i++) {\n      const node = children.get(i)!;\n      const index = i;\n      const instances = this.getComponentInstances(node);\n      const inst = instances\n        ? instances.length > 1\n          ? instances.find(\n            (_inst) => this.getClosestNodeInstance(_inst, container.id)?.instance === containerInstance,\n          )\n          : instances[0]\n        : null;\n      const rect = inst\n        ? this.computeComponentInstanceRect(inst, node.componentMeta.rootSelector)\n        : null;\n\n      if (!rect) {\n        continue;\n      }\n\n      const distance = isPointInRect(e as any, rect) ? 0 : distanceToRect(e as any, rect);\n\n      if (distance === 0) {\n        nearDistance = distance;\n        nearNode = node;\n        nearIndex = index;\n        nearRect = rect;\n        break;\n      }\n\n      // 标记子节点最顶\n      if (minTop === null || rect.top < minTop) {\n        minTop = rect.top;\n      }\n      // 标记子节点最底\n      if (maxBottom === null || rect.bottom > maxBottom) {\n        maxBottom = rect.bottom;\n      }\n\n      if (nearDistance === null || distance < nearDistance) {\n        nearDistance = distance;\n        nearNode = node;\n        nearIndex = index;\n        nearRect = rect;\n      }\n    }\n\n    detail.index = nearIndex;\n\n    if (nearNode && nearRect) {\n      const el = getRectTarget(nearRect);\n      const inline = el ? isChildInline(el) : false;\n      const row = el ? isRowContainer(el.parentElement!) : false;\n      const vertical = inline || row;\n\n      // TODO: fix type\n      const near: {\n        node: IPublicModelNode;\n        pos: 'before' | 'after' | 'replace';\n        rect?: IPublicTypeRect;\n        align?: 'V' | 'H';\n      } = {\n        node: nearNode.internalToShellNode()!,\n        pos: 'before',\n        align: vertical ? 'V' : 'H',\n      };\n      detail.near = near;\n      if (isNearAfter(e as any, nearRect, vertical)) {\n        near.pos = 'after';\n        detail.index = nearIndex + 1;\n      }\n      if (!row && nearDistance !== 0) {\n        const edgeDistance = distanceToEdge(e as any, edge);\n        if (edgeDistance.distance < nearDistance!) {\n          const { nearAfter } = edgeDistance;\n          if (minTop == null) {\n            minTop = edge.top;\n          }\n          if (maxBottom == null) {\n            maxBottom = edge.bottom;\n          }\n          near.rect = new DOMRect(edge.left, minTop, edge.width, maxBottom - minTop);\n          near.align = 'H';\n          near.pos = nearAfter ? 'after' : 'before';\n          detail.index = nearAfter ? children.size : 0;\n        }\n      }\n    }\n\n    return this.designer.createLocation(locationData);\n  }\n\n  /**\n   * 查找合适的投放容器\n   */\n  getDropContainer(e: ILocateEvent): DropContainer | null {\n    const { target, dragObject } = e;\n    const isAny = isDragAnyObject(dragObject);\n    const document = this.project.currentDocument!;\n    const { currentRoot } = document;\n    let container: INode | null;\n    let nodeInstance: IPublicTypeNodeInstance<IPublicTypeComponentInstance, INode> | undefined;\n\n    if (target) {\n      const ref = this.getNodeInstanceFromElement(target);\n      if (ref?.node) {\n        nodeInstance = ref;\n        container = ref.node;\n      } else if (isAny) {\n        return null;\n      } else {\n        container = currentRoot;\n      }\n    } else if (isAny) {\n      return null;\n    } else {\n      container = currentRoot;\n    }\n\n    if (!container?.isParental()) {\n      container = container?.parent || currentRoot;\n    }\n\n    // TODO: use spec container to accept specialData\n    if (isAny) {\n      // will return locationData\n      return null;\n    }\n\n    // get common parent, avoid drop container contains by dragObject\n    const drillDownExcludes = new Set<INode>();\n    if (isDragNodeObject(dragObject)) {\n      const { nodes } = dragObject;\n      let i = nodes.length;\n      let p: any = container;\n      while (i-- > 0) {\n        if (contains(nodes[i], p)) {\n          p = nodes[i].parent;\n        }\n      }\n      if (p !== container) {\n        container = p || document.focusNode;\n        container && drillDownExcludes.add(container);\n      }\n    }\n\n    let instance: any;\n    if (nodeInstance) {\n      if (nodeInstance.node === container) {\n        instance = nodeInstance.instance;\n      } else {\n        instance = this.getClosestNodeInstance(\n          nodeInstance.instance as any,\n          container?.id,\n        )?.instance;\n      }\n    } else {\n      instance = container && this.getComponentInstances(container)?.[0];\n    }\n\n    let dropContainer: DropContainer = {\n      container: container as any,\n      instance,\n    };\n\n    let res: any;\n    let upward: DropContainer | null = null;\n    while (container) {\n      res = this.handleAccept(dropContainer, e);\n      // if (isLocationData(res)) {\n      //   return res;\n      // }\n      if (res === true) {\n        return dropContainer;\n      }\n      if (!res) {\n        drillDownExcludes.add(container);\n        if (upward) {\n          dropContainer = upward;\n          container = dropContainer.container;\n          upward = null;\n        } else if (container.parent) {\n          container = container.parent;\n          instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance;\n          dropContainer = {\n            container,\n            instance,\n          };\n        } else {\n          return null;\n        }\n      }\n    }\n    return null;\n  }\n\n  isAcceptable(): boolean {\n    return false;\n  }\n\n  /**\n   * 控制接受\n   */\n  handleAccept({ container }: DropContainer, e: ILocateEvent): boolean {\n    const { dragObject } = e;\n    const document = this.currentDocument!;\n    const { focusNode } = document;\n    if (isRootNode(container) || container.contains(focusNode)) {\n      return document.checkNesting(focusNode!, dragObject as any);\n    }\n\n    const meta = (container as Node).componentMeta;\n\n    // FIXME: get containerInstance for accept logic use\n    const acceptable: boolean = this.isAcceptable(container);\n    if (!meta.isContainer && !acceptable) {\n      return false;\n    }\n\n    // check nesting\n    return document.checkNesting(container, dragObject as any);\n  }\n\n  /**\n   * 查找邻近容器\n   */\n  getNearByContainer(\n    { container, instance }: DropContainer,\n    drillDownExcludes: Set<INode>,\n  ) {\n    const { children } = container;\n    if (!children || children.isEmpty()) {\n      return null;\n    }\n\n    const nearBy: any = null;\n    for (let i = 0, l = children.size; i < l; i++) {\n      let child = children.get(i);\n\n      if (!child) {\n        continue;\n      }\n      if (child.conditionGroup) {\n        const bn = child.conditionGroup;\n        i = (bn.index || 0) + bn.length - 1;\n        child = bn.visibleNode;\n      }\n      if (!child.isParental() || drillDownExcludes.has(child)) {\n        continue;\n      }\n      // TODO:\n      this.findDOMNodes(instance);\n      this.getComponentInstances(child);\n      const rect = this.computeRect(child);\n      if (!rect) {\n        continue;\n      }\n    }\n\n    return nearBy;\n  }\n  // #endregion\n}\n\nfunction isHTMLTag(name: string) {\n  return /^[a-z]\\w*$/.test(name);\n}\n\nfunction isPointInRect(point: CanvasPoint, rect: IPublicTypeRect) {\n  return (\n    point.canvasY >= rect.top &&\n    point.canvasY <= rect.bottom &&\n    point.canvasX >= rect.left &&\n    point.canvasX <= rect.right\n  );\n}\n\nfunction distanceToRect(point: CanvasPoint, rect: IPublicTypeRect) {\n  let minX = Math.min(Math.abs(point.canvasX - rect.left), Math.abs(point.canvasX - rect.right));\n  let minY = Math.min(Math.abs(point.canvasY - rect.top), Math.abs(point.canvasY - rect.bottom));\n  if (point.canvasX >= rect.left && point.canvasX <= rect.right) {\n    minX = 0;\n  }\n  if (point.canvasY >= rect.top && point.canvasY <= rect.bottom) {\n    minY = 0;\n  }\n\n  return Math.sqrt(minX ** 2 + minY ** 2);\n}\n\nfunction distanceToEdge(point: CanvasPoint, rect: IPublicTypeRect) {\n  const distanceTop = Math.abs(point.canvasY - rect.top);\n  const distanceBottom = Math.abs(point.canvasY - rect.bottom);\n\n  return {\n    distance: Math.min(distanceTop, distanceBottom),\n    nearAfter: distanceBottom < distanceTop,\n  };\n}\n\nfunction isNearAfter(point: CanvasPoint, rect: IPublicTypeRect, inline: boolean) {\n  if (inline) {\n    return (\n      Math.abs(point.canvasX - rect.left) + Math.abs(point.canvasY - rect.top) >\n      Math.abs(point.canvasX - rect.right) + Math.abs(point.canvasY - rect.bottom)\n    );\n  }\n  return Math.abs(point.canvasY - rect.top) > Math.abs(point.canvasY - rect.bottom);\n}\n\nfunction getMatched(elements: Array<Element | Text>, selector: string): Element | null {\n  let firstQueried: Element | null = null;\n  for (const elem of elements) {\n    if (isElement(elem)) {\n      if (elem.matches(selector)) {\n        return elem;\n      }\n\n      if (!firstQueried) {\n        firstQueried = elem.querySelector(selector);\n      }\n    }\n  }\n  return firstQueried;\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/index.ts",
    "content": "export * from './host';\nexport * from './host-view';\nexport * from './renderer';\nexport * from './live-editing/live-editing';\nexport { LowcodeTypes } from './utils/parse-metadata';\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/live-editing/live-editing.ts",
    "content": "import { obx } from '@alilc/lowcode-editor-core';\nimport { IPublicTypePluginConfig, IPublicTypeLiveTextEditingConfig } from '@alilc/lowcode-types';\nimport { INode, Prop } from '../../document';\n\nconst EDITOR_KEY = 'data-setter-prop';\n\nfunction getSetterPropElement(ele: HTMLElement, root: HTMLElement): HTMLElement | null {\n  const box = ele.closest(`[${EDITOR_KEY}]`);\n  if (!box || !root.contains(box)) {\n    return null;\n  }\n  return box as HTMLElement;\n}\n\nfunction defaultSaveContent(content: string, prop: Prop) {\n  prop.setValue(content);\n}\n\nexport interface EditingTarget {\n  node: INode;\n  rootElement: HTMLElement;\n  event: MouseEvent;\n}\n\nlet saveHandlers: SaveHandler[] = [];\nfunction addLiveEditingSaveHandler(handler: SaveHandler) {\n  saveHandlers.push(handler);\n}\nfunction clearLiveEditingSaveHandler() {\n  saveHandlers = [];\n}\n\nlet specificRules: SpecificRule[] = [];\nfunction addLiveEditingSpecificRule(rule: SpecificRule) {\n  specificRules.push(rule);\n}\nfunction clearLiveEditingSpecificRule() {\n  specificRules = [];\n}\n\nexport class LiveEditing {\n  static addLiveEditingSpecificRule = addLiveEditingSpecificRule;\n  static clearLiveEditingSpecificRule = clearLiveEditingSpecificRule;\n\n  static addLiveEditingSaveHandler = addLiveEditingSaveHandler;\n  static clearLiveEditingSaveHandler = clearLiveEditingSaveHandler;\n\n  @obx.ref private _editing: Prop | null = null;\n\n  private _dispose?: () => void;\n\n  private _save?: () => void;\n\n  apply(target: EditingTarget) {\n    const { node, event, rootElement } = target;\n    const targetElement = event.target as HTMLElement;\n    const { liveTextEditing } = node.componentMeta;\n\n    const editor = node.document?.designer.editor;\n    const npm = node?.componentMeta?.npm;\n    const selected =\n      [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';\n    editor?.eventBus.emit('designer.builtinSimulator.liveEditing', {\n      selected,\n    });\n\n    let setterPropElement = getSetterPropElement(targetElement, rootElement);\n    let propTarget = setterPropElement?.dataset.setterProp;\n    let matched: (IPublicTypePluginConfig & { propElement?: HTMLElement }) | undefined | null;\n    if (liveTextEditing) {\n      if (propTarget) {\n        // 已埋点命中 data-setter-prop=\"proptarget\", 从 liveTextEditing 读取配置（mode|onSaveContent）\n        matched = liveTextEditing.find(config => config.propTarget == propTarget);\n      } else {\n        // 执行 embedTextEditing selector 规则，获得第一个节点 是否 contains e.target，若匹配，读取配置\n        matched = liveTextEditing.find(config => {\n          if (!config.selector) {\n            return false;\n          }\n          setterPropElement = queryPropElement(rootElement, targetElement, config.selector);\n          return !!setterPropElement;\n        });\n        propTarget = matched?.propTarget;\n      }\n    } else {\n      specificRules.some((rule) => {\n        matched = rule(target);\n        return !!matched;\n      });\n      if (matched) {\n        propTarget = matched.propTarget;\n        setterPropElement = matched.propElement || queryPropElement(rootElement, targetElement, matched.selector);\n      }\n    }\n\n    // if (!propTarget) {\n    //   // 自动纯文本编辑满足一下情况：\n    //   //  1. children 内容都是 Leaf 且都是文本（一期）\n    //   //  2. DOM 节点是单层容器，子集都是文本节点 (已满足)\n    //   const isAllText = node.children?.every(item => {\n    //     return item.isLeaf() && item.getProp('children')?.type === 'literal';\n    //   });\n    //   // TODO:\n    // }\n\n    if (propTarget && setterPropElement) {\n      const prop = node.getProp(propTarget, true)!;\n\n      if (this._editing === prop) {\n        return;\n      }\n\n      // 进入编辑\n      //  1. 设置 contentEditable=\"plaintext|...\"\n      //  2. 添加类名\n      //  3. focus & cursor locate\n      //  4. 监听 blur 事件\n      //  5. 设置编辑锁定：disable hover | disable select | disable canvas drag\n\n      const onSaveContent = matched?.onSaveContent || saveHandlers.find(item => item.condition(prop))?.onSaveContent || defaultSaveContent;\n\n      setterPropElement.setAttribute('contenteditable', matched?.mode && matched.mode !== 'plaintext' ? 'true' : 'plaintext-only');\n      setterPropElement.classList.add('engine-live-editing');\n      // be sure\n      setterPropElement.focus();\n      setCaret(event);\n\n      this._save = () => {\n        onSaveContent(setterPropElement!.innerText, prop);\n      };\n\n      const keydown = (e: KeyboardEvent) => {\n        console.info(e.code);\n        switch (e.code) {\n          case 'Enter':\n            break;\n            // TODO: check is richtext?\n          case 'Escape':\n            break;\n          case 'Tab':\n            setterPropElement?.blur();\n        }\n        // esc\n        // enter\n        // tab\n      };\n      const focusout = (/* e: FocusEvent */) => {\n        this.saveAndDispose();\n      };\n      setterPropElement.addEventListener('focusout', focusout);\n      setterPropElement.addEventListener('keydown', keydown, true);\n\n      this._dispose = () => {\n        setterPropElement!.classList.remove('engine-live-editing');\n        setterPropElement!.removeAttribute('contenteditable');\n        setterPropElement!.removeEventListener('focusout', focusout);\n        setterPropElement!.removeEventListener('keydown', keydown, true);\n      };\n\n      this._editing = prop;\n    }\n\n    // TODO: process enter | esc events & joint the FocusTracker\n\n    // TODO: upward testing for b/i/a html elements\n  }\n\n  get editing() {\n    return this._editing;\n  }\n\n  saveAndDispose() {\n    if (this._save) {\n      this._save();\n      this._save = undefined;\n    }\n    this.dispose();\n  }\n\n  dispose() {\n    if (this._dispose) {\n      this._dispose();\n      this._dispose = undefined;\n    }\n    this._editing = null;\n  }\n}\n\nexport type SpecificRule = (target: EditingTarget) => (IPublicTypeLiveTextEditingConfig & {\n  propElement?: HTMLElement;\n}) | null;\n\nexport interface SaveHandler {\n  condition: (prop: Prop) => boolean;\n  onSaveContent: (content: string, prop: Prop) => void;\n}\n\nfunction setCaret(event: MouseEvent) {\n  const doc = event.view?.document;\n  if (!doc) return;\n  const range = doc.caretRangeFromPoint(event.clientX, event.clientY);\n  if (range) {\n    selectRange(doc, range);\n    setTimeout(() => selectRange(doc, range), 1);\n  }\n}\n\nfunction selectRange(doc: Document, range: Range) {\n  const selection = doc.getSelection();\n  if (selection) {\n    selection.removeAllRanges();\n    selection.addRange(range);\n  }\n}\n\nfunction queryPropElement(rootElement: HTMLElement, targetElement: HTMLElement, selector?: string) {\n  if (!selector) {\n    return null;\n  }\n  let propElement = selector === ':root' ? rootElement : rootElement.querySelector(selector);\n  if (!propElement) {\n    return null;\n  }\n  if (!propElement.contains(targetElement)) {\n    // try selectorAll\n    propElement = Array.from(rootElement.querySelectorAll(selector)).find(item => item.contains(targetElement)) as HTMLElement;\n    if (!propElement) {\n      return null;\n    }\n  }\n  return propElement as HTMLElement;\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/node-selector/index.less",
    "content": "@import '../../less-variables.less';\n\n// 样式直接沿用之前的样式，优化了下命名\n.instance-node-selector {\n  position: relative;\n  margin-right: 2px;\n  color: var(--color-icon-white, @title-bgcolor);\n  border-radius: @global-border-radius;\n  pointer-events: auto;\n  flex-grow: 0;\n  flex-shrink: 0;\n\n  svg {\n    width: 16px;\n    height: 16px;\n    margin-right: 5px;\n    flex-grow: 0;\n    flex-shrink: 0;\n    max-width: inherit;\n    path {\n      fill: var(--color-icon-white, @title-bgcolor);\n    }\n  }\n  .instance-node-selector-current {\n    background: var(--color-brand, @brand-color-1);\n    padding: 0 6px;\n    display: flex;\n    align-items: center;\n    height: 20px;\n    cursor: pointer;\n    color: var(--color-icon-white, @title-bgcolor);\n    border-radius: 3px;\n\n    &-title {\n      padding-right: 6px;\n      color: var(--color-icon-white, @title-bgcolor);\n    }\n  }\n  .instance-node-selector-list {\n    position: absolute;\n    left: 0;\n    right: 0;\n    opacity: 0;\n    visibility: hidden;\n  }\n  .instance-node-selector-node {\n    height: 20px;\n    margin-top: 2px;\n    &-content {\n      padding-left: 6px;\n      background: var(--color-layer-tooltip-background, #78869a);\n      display: inline-flex;\n      border-radius: 3px;\n      align-items: center;\n      height: 20px;\n      color: var(--color-icon-white, @title-bgcolor);\n      cursor: pointer;\n      overflow: visible;\n    }\n    &-title {\n      padding-right: 6px;\n      // margin-left: 5px;\n      color: var(--color-icon-white, @title-bgcolor);\n      cursor: pointer;\n      overflow: visible;\n    }\n    &:hover {\n      opacity: 0.8;\n    }\n  }\n\n  &:hover {\n    .instance-node-selector-current {\n      color: ar(--color-text-reverse, @white-alpha-2);\n    }\n    .instance-node-selector-popup {\n      visibility: visible;\n      opacity: 1;\n      transition: 0.2s all ease-in;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/node-selector/index.tsx",
    "content": "import { Overlay } from '@alifd/next';\nimport React, { MouseEvent } from 'react';\nimport { Title, observer } from '@alilc/lowcode-editor-core';\nimport { canClickNode } from '@alilc/lowcode-utils';\nimport './index.less';\n\nimport { INode } from '@alilc/lowcode-designer';\n\nconst { Popup } = Overlay;\n\nexport interface IProps {\n  node: INode;\n}\n\nexport interface IState {\n  parentNodes: INode[];\n}\n\ntype UnionNode = INode | null;\n\n@observer\nexport default class InstanceNodeSelector extends React.Component<IProps, IState> {\n  state: IState = {\n    parentNodes: [],\n  };\n\n  componentDidMount() {\n    const parentNodes = this.getParentNodes(this.props.node);\n    this.setState({\n      parentNodes: parentNodes ?? [],\n    });\n  }\n\n  // 获取节点的父级节点（最多获取 5 层）\n  getParentNodes = (node: INode) => {\n    const parentNodes: any[] = [];\n    const focusNode = node.document?.focusNode;\n\n    if (!focusNode) {\n      return null;\n    }\n\n    if (node.contains(focusNode) || !focusNode.contains(node)) {\n      return parentNodes;\n    }\n\n    let currentNode: UnionNode = node;\n\n    while (currentNode && parentNodes.length < 5) {\n      currentNode = currentNode.getParent();\n      if (currentNode) {\n        parentNodes.push(currentNode);\n      }\n      if (currentNode === focusNode) {\n        break;\n      }\n    }\n    return parentNodes;\n  };\n\n  onSelect = (node: INode) => (event: MouseEvent) => {\n    if (!node) {\n      return;\n    }\n\n    const canClick = canClickNode(node.internalToShellNode()!, event);\n\n    if (canClick && typeof node.select === 'function') {\n      node.select();\n      const editor = node.document?.designer.editor;\n      const npm = node?.componentMeta?.npm;\n      const selected =\n        [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||\n        node?.componentMeta?.componentName ||\n        '';\n      editor?.eventBus.emit('designer.border.action', {\n        name: 'select',\n        selected,\n      });\n    }\n  };\n\n  onMouseOver = (node: INode) => (_: any, flag = true) => {\n    if (node && typeof node.hover === 'function') {\n      node.hover(flag);\n    }\n  };\n\n  onMouseOut = (node: INode) => (_: any, flag = false) => {\n    if (node && typeof node.hover === 'function') {\n      node.hover(flag);\n    }\n  };\n\n  renderNodes = () => {\n    const nodes = this.state.parentNodes;\n    if (!nodes || nodes.length < 1) {\n      return null;\n    }\n    const children = nodes.map((node, key) => {\n      return (\n        <div\n          key={key}\n          onClick={this.onSelect(node)}\n          onMouseEnter={this.onMouseOver(node)}\n          onMouseLeave={this.onMouseOut(node)}\n          className=\"instance-node-selector-node\"\n        >\n          <div className=\"instance-node-selector-node-content\">\n            <Title\n              className=\"instance-node-selector-node-title\"\n              title={{\n                label: node.title,\n                icon: node.icon,\n              }}\n            />\n          </div>\n        </div>\n      );\n    });\n    return children;\n  };\n\n  render() {\n    const { node } = this.props;\n    return (\n      <div className=\"instance-node-selector\">\n        <Popup\n          trigger={\n            <div className=\"instance-node-selector-current\">\n              <Title\n                className=\"instance-node-selector-node-title\"\n                title={{\n                  label: node.title,\n                  icon: node.icon,\n                }}\n              />\n            </div>\n          }\n          triggerType=\"hover\"\n          offset={[0, 0]}\n        >\n          <div className=\"instance-node-selector\">{this.renderNodes()}</div>\n        </Popup>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/renderer.ts",
    "content": "import { Component } from '../simulator';\nimport { IPublicTypeComponentInstance, IPublicTypeSimulatorRenderer } from '@alilc/lowcode-types';\n\nexport type BuiltinSimulatorRenderer = IPublicTypeSimulatorRenderer<Component, IPublicTypeComponentInstance>;\n\nexport function isSimulatorRenderer(obj: any): obj is BuiltinSimulatorRenderer {\n  return obj && obj.isSimulatorRenderer;\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/resource-consumer.ts",
    "content": "import { autorun, makeObservable, obx, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';\nimport { BuiltinSimulatorHost } from './host';\nimport { BuiltinSimulatorRenderer, isSimulatorRenderer } from './renderer';\n\nconst UNSET = Symbol('unset');\nexport type MasterProvider = (master: BuiltinSimulatorHost) => any;\nexport type RendererConsumer<T> = (renderer: BuiltinSimulatorRenderer, data: T) => Promise<any>;\n\n// master 进程\n//  0. 初始化该对象，因为需要响应变更发生在 master 进程\n//  1. 提供消费数据或数据提供器，比如 Asset 资源，如果不是数据提供器，会持续提供\n//  2. 收到成功通知\n// renderer 进程\n//  1. 持续消费，并持续监听数据\n//  2. 消费\n\n// 这里涉及俩个自定义项\n//  1. 被消费数据协议\n//  2. 消费机制（渲染进程自定 + 传递进入）\n\nexport default class ResourceConsumer<T = any> {\n  private emitter: IEventBus = createModuleEventBus('ResourceConsumer');\n\n  @obx.ref private _data: T | typeof UNSET = UNSET;\n\n  private _providing?: () => void;\n\n  private _consuming?: () => void;\n\n  private _firstConsumed = false;\n\n  private resolveFirst?: (resolve?: any) => void;\n\n  constructor(provider: () => T, private consumer?: RendererConsumer<T>) {\n    makeObservable(this);\n    this._providing = autorun(() => {\n      this._data = provider();\n    });\n  }\n\n  consume(consumerOrRenderer: BuiltinSimulatorRenderer | ((data: T) => any)) {\n    if (this._consuming) {\n      return;\n    }\n    let consumer: (data: T) => any;\n    if (isSimulatorRenderer(consumerOrRenderer)) {\n      if (!this.consumer) {\n        // TODO: throw error\n        return;\n      }\n      const rendererConsumer = this.consumer!;\n\n      consumer = (data) => rendererConsumer(consumerOrRenderer, data);\n    } else {\n      consumer = consumerOrRenderer;\n    }\n    this._consuming = autorun(async () => {\n      if (this._data === UNSET) {\n        return;\n      }\n      await consumer(this._data);\n      // TODO: catch error and report\n      if (this.resolveFirst) {\n        this.resolveFirst();\n      } else {\n        this._firstConsumed = true;\n      }\n    });\n  }\n\n  dispose() {\n    if (this._providing) {\n      this._providing();\n    }\n    if (this._consuming) {\n      this._consuming();\n    }\n    this.emitter.removeAllListeners();\n  }\n\n  waitFirstConsume(): Promise<any> {\n    if (this._firstConsumed) {\n      return Promise.resolve();\n    }\n    return new Promise((resolve) => {\n      this.resolveFirst = resolve;\n    });\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/utils/clickable.ts",
    "content": "import { getClosestNode, canClickNode } from '@alilc/lowcode-utils';\nimport { INode } from '../../document';\n\n/**\n * 获取离当前节点最近的可点击节点\n * @param currentNode\n * @param event\n */\nexport const getClosestClickableNode = (\n  currentNode: INode | undefined | null,\n  event: MouseEvent,\n) => {\n  let node = currentNode;\n  while (node) {\n    // 判断当前节点是否可点击\n    let canClick = canClickNode(node, event);\n    // eslint-disable-next-line no-loop-func\n    const lockedNode = getClosestNode(node!, (n) => {\n      // 假如当前节点就是 locked 状态，要从当前节点的父节点开始查找\n      return !!(node?.isLocked ? n.parent?.isLocked : n.isLocked);\n    });\n    if (lockedNode && lockedNode.getId() !== node.getId()) {\n      canClick = false;\n    }\n    if (canClick) {\n      break;\n    }\n    // 对于不可点击的节点，继续向上找\n    node = node.parent;\n  }\n  return node;\n};\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/utils/parse-metadata.ts",
    "content": "import PropTypes from 'prop-types';\nimport { isValidElement } from 'react';\nimport { isElement } from '@alilc/lowcode-utils';\nimport { IPublicTypePropConfig } from '@alilc/lowcode-types';\n\nexport const primitiveTypes = [\n  'string',\n  'number',\n  'array',\n  'bool',\n  'func',\n  'object',\n  'node',\n  'element',\n  'symbol',\n  'any',\n];\n\ninterface LowcodeCheckType {\n  // isRequired, props, propName, componentName, location, propFullName, secret\n  (props: any, propName: string, componentName: string, ...rest: any[]): Error | null;\n  // (...reset: any[]): Error | null;\n  isRequired?: LowcodeCheckType;\n  type?: string | object;\n}\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nfunction makeRequired(propType: any, lowcodeType: string | object): LowcodeCheckType {\n  function lowcodeCheckTypeIsRequired(...rest: any[]) {\n    return propType.isRequired(...rest);\n  }\n  if (typeof lowcodeType === 'string') {\n    lowcodeType = {\n      type: lowcodeType,\n    };\n  }\n  lowcodeCheckTypeIsRequired.lowcodeType = {\n    ...lowcodeType,\n    isRequired: true,\n  };\n  return lowcodeCheckTypeIsRequired;\n}\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nfunction define(propType: any = PropTypes.any, lowcodeType: string | object = {}): LowcodeCheckType {\n  if (!propType._inner && propType.name !== 'lowcodeCheckType') {\n    propType.lowcodeType = lowcodeType;\n  }\n  function lowcodeCheckType(...rest: any[]) {\n    return propType(...rest);\n  }\n  lowcodeCheckType.lowcodeType = lowcodeType;\n  lowcodeCheckType.isRequired = makeRequired(propType, lowcodeType);\n  return lowcodeCheckType;\n}\n\nexport const LowcodeTypes: any = {\n  ...PropTypes,\n  define,\n};\n\n(window as any).PropTypes = LowcodeTypes;\nif ((window as any).React) {\n  (window as any).React.PropTypes = LowcodeTypes;\n}\n\n// override primitive type checkers\nprimitiveTypes.forEach((type) => {\n  const propType = (PropTypes as any)[type];\n  if (!propType) {\n    return;\n  }\n  propType._inner = true;\n  LowcodeTypes[type] = define(propType, type);\n});\n\n// You can ensure that your prop is limited to specific values by treating\n// it as an enum.\nLowcodeTypes.oneOf = (list: any[]) => {\n  return define(PropTypes.oneOf(list), {\n    type: 'oneOf',\n    value: list,\n  });\n};\n\n// An array of a certain type\nLowcodeTypes.arrayOf = (type: any) => {\n  return define(PropTypes.arrayOf(type), {\n    type: 'arrayOf',\n    value: type.lowcodeType || 'any',\n  });\n};\n\n// An object with property values of a certain type\nLowcodeTypes.objectOf = (type: any) => {\n  return define(PropTypes.objectOf(type), {\n    type: 'objectOf',\n    value: type.lowcodeType || 'any',\n  });\n};\n\n// An object that could be one of many types\nLowcodeTypes.oneOfType = (types: any[]) => {\n  const itemTypes = types.map((type) => type.lowcodeType || 'any');\n  return define(PropTypes.oneOfType(types), {\n    type: 'oneOfType',\n    value: itemTypes,\n  });\n};\n\n// An object with warnings on extra properties\nLowcodeTypes.exact = (typesMap: any) => {\n  const configs = Object.keys(typesMap).map((key) => {\n    return {\n      name: key,\n      propType: typesMap[key]?.lowcodeType || 'any',\n    };\n  });\n  return define(PropTypes.exact(typesMap), {\n    type: 'exact',\n    value: configs,\n  });\n};\n\n// An object taking on a particular shape\nLowcodeTypes.shape = (typesMap: any = {}) => {\n  const configs = Object.keys(typesMap).map((key) => {\n    return {\n      name: key,\n      propType: typesMap[key]?.lowcodeType || 'any',\n    };\n  });\n  return define(PropTypes.shape(typesMap), {\n    type: 'shape',\n    value: configs,\n  });\n};\n\nconst BasicTypes = ['string', 'number', 'object'];\nexport function parseProps(component: any): IPublicTypePropConfig[] {\n  if (!component) {\n    return [];\n  }\n  const propTypes = component.propTypes || ({} as any);\n  const defaultProps = component.defaultProps || ({} as any);\n  const result: any = {};\n  if (!propTypes) return [];\n  Object.keys(propTypes).forEach((key) => {\n    const propTypeItem = propTypes[key];\n    const defaultValue = defaultProps[key];\n    const { lowcodeType } = propTypeItem;\n    if (lowcodeType) {\n      result[key] = {\n        name: key,\n        propType: lowcodeType,\n      };\n      if (defaultValue != null) {\n        result[key].defaultValue = defaultValue;\n      }\n      return;\n    }\n\n    let i = primitiveTypes.length;\n    while (i-- > 0) {\n      const k = primitiveTypes[i];\n      if ((LowcodeTypes as any)[k] === propTypeItem) {\n        result[key] = {\n          name: key,\n          propType: k,\n        };\n        if (defaultValue != null) {\n          result[key].defaultValue = defaultValue;\n        }\n        return;\n      }\n    }\n    result[key] = {\n      name: key,\n      propType: 'any',\n    };\n    if (defaultValue != null) {\n      result[key].defaultValue = defaultValue;\n    }\n  });\n\n  Object.keys(defaultProps).forEach((key) => {\n    if (result[key]) return;\n    const defaultValue = defaultProps[key];\n    let type: string = typeof defaultValue;\n    if (type === 'boolean') {\n      type = 'bool';\n    } else if (type === 'function') {\n      type = 'func';\n    } else if (type === 'object' && Array.isArray(defaultValue)) {\n      type = 'array';\n    } else if (defaultValue && isValidElement(defaultValue)) {\n      type = 'node';\n    } else if (defaultValue && isElement(defaultValue)) {\n      type = 'element';\n    } else if (!BasicTypes.includes(type)) {\n      type = 'any';\n    }\n\n    result[key] = {\n      name: key,\n      propType: type || 'any',\n      defaultValue,\n    };\n  });\n\n  return Object.keys(result).map((key) => result[key]);\n}\n\nexport function parseMetadata(component: any): any {\n  return {\n    props: parseProps(component),\n    ...component.componentMetadata,\n  };\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/utils/path.ts",
    "content": "/**\n * Check whether a component is external package, e.g. @ali/uxcore\n * @param path Component path\n */\nexport function isPackagePath(path: string): boolean {\n  return !path.startsWith('.') && !path.startsWith('/');\n}\n\n/**\n * Title cased string\n * @param s original string\n */\nexport function toTitleCase(s: string): string {\n  return s\n    .split(/[-_ .]+/)\n    .map((token) => token[0].toUpperCase() + token.substring(1))\n    .join('');\n}\n\n/**\n * Make up an import name/tag for components\n * @param path Original path name\n */\nexport function generateComponentName(path: string): string {\n  const parts = path.split('/');\n  let name = parts.pop();\n  if (name && /^index\\./.test(name)) {\n    name = parts.pop();\n  }\n  return name ? toTitleCase(name) : 'Component';\n}\n\n/**\n * normalizing import path for easier comparison\n */\nexport function getNormalizedImportPath(path: string): string {\n  const segments = path.split('/');\n  let basename = segments.pop();\n  if (!basename) {\n    return path;\n  }\n  const ignoredExtensions = ['.ts', '.js', '.tsx', '.jsx'];\n  const extIndex = basename.lastIndexOf('.');\n  if (extIndex > -1) {\n    const ext = basename.slice(extIndex);\n    if (ignoredExtensions.includes(ext)) {\n      basename = basename.slice(0, extIndex);\n    }\n  }\n  if (basename !== 'index') {\n    segments.push(basename);\n  }\n  return segments.join('/');\n}\n\n/**\n * make a relative path\n *\n * @param toPath abolute path\n * @param fromPath absolute path\n */\nexport function makeRelativePath(toPath: string, fromPath: string) {\n  // not a absolute path, eg. @ali/uxcore\n  if (!toPath.startsWith('/')) {\n    return toPath;\n  }\n  const toParts = toPath.split('/');\n  const fromParts = fromPath.split('/');\n\n  // find shared path header\n  const length = Math.min(fromParts.length, toParts.length);\n  let sharedUpTo = length;\n  for (let i = 0; i < length; i++) {\n    if (fromParts[i] !== toParts[i]) {\n      sharedUpTo = i;\n      break;\n    }\n  }\n\n  // find how many levels to go up from\n  // minus another 1 since we do not include the final\n  const numGoUp = fromParts.length - sharedUpTo - 1;\n\n  // generate final path\n  let outputParts = [];\n  if (numGoUp === 0) {\n    // in the same dir\n    outputParts.push('.');\n  } else {\n    // needs to go up\n    for (let i = 0; i < numGoUp; ++i) {\n      outputParts.push('..');\n    }\n  }\n\n  outputParts = outputParts.concat(toParts.slice(sharedUpTo));\n\n  return outputParts.join('/');\n}\n\nfunction normalizeArray(parts: string[], allowAboveRoot: boolean) {\n  const res = [];\n  for (let i = 0; i < parts.length; i++) {\n    const p = parts[i];\n\n    // ignore empty parts\n    if (!p || p === '.') {\n      continue;\n    }\n\n    if (p === '..') {\n      if (res.length && res[res.length - 1] !== '..') {\n        res.pop();\n      } else if (allowAboveRoot) {\n        res.push('..');\n      }\n    } else {\n      res.push(p);\n    }\n  }\n\n  return res;\n}\n\nfunction normalize(path: string): string {\n  const isAbsolute = path[0] === '/';\n\n  const segments = normalizeArray(path.split('/'), !isAbsolute);\n  if (isAbsolute) {\n    segments.unshift('');\n  } else if (segments.length < 1 || segments[0] !== '..') {\n    segments.unshift('.');\n  }\n\n  return segments.join('/');\n}\n\n/**\n * Resolve component with absolute path to relative path\n * @param path absolute path of component from project\n */\nexport function resolveAbsoluatePath(path: string, base: string): string {\n  if (!path.startsWith('.')) {\n    // eg.  /usr/path/to, @ali/button\n    return path;\n  }\n  path = path.replace(/\\\\/g, '/');\n  if (base.slice(-1) !== '/') {\n    base += '/';\n  }\n  return normalize(base + path);\n}\n\nexport function joinPath(...segments: string[]) {\n  let path = '';\n  for (const seg of segments) {\n    if (seg) {\n      if (path === '') {\n        path += seg;\n      } else {\n        path += `/${ seg}`;\n      }\n    }\n  }\n  return normalize(path);\n}\n\nexport function removeVersion(path: string): string {\n  if (path.lastIndexOf('@') > 0) {\n    path = path.replace(/(@?[^@]+)(@[\\w.-]+)(.+)/, '$1$3');\n  }\n  return path;\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/utils/throttle.ts",
    "content": "const useRAF = typeof requestAnimationFrame === 'function';\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function throttle(func: Function, delay: number) {\n  let lastArgs: any;\n  let lastThis: any;\n  let result: any;\n  let timerId: number | undefined;\n  let lastCalled: number | undefined;\n  let lastInvoked = 0;\n\n  function invoke(time: number) {\n    const args = lastArgs;\n    const thisArg = lastThis;\n\n    lastArgs = undefined;\n    lastThis = undefined;\n    lastInvoked = time;\n    result = func.apply(thisArg, args);\n    return result;\n  }\n\n  function startTimer(pendingFunc: any, wait: number): number {\n    if (useRAF) {\n      return requestAnimationFrame(pendingFunc);\n    }\n    return setTimeout(pendingFunc, wait) as any;\n  }\n\n  function leadingEdge(time: number) {\n    lastInvoked = time;\n    timerId = startTimer(timerExpired, delay);\n    return invoke(time);\n  }\n\n  function shouldInvoke(time: number) {\n    const timeSinceLastCalled = time - lastCalled!;\n    const timeSinceLastInvoked = time - lastInvoked;\n\n    return (\n      lastCalled === undefined ||\n      timeSinceLastCalled >= delay ||\n      timeSinceLastCalled < 0 ||\n      timeSinceLastInvoked >= delay\n    );\n  }\n\n  function remainingWait(time: number) {\n    const timeSinceLastCalled = time - lastCalled!;\n    const timeSinceLastInvoked = time - lastInvoked;\n\n    return Math.min(delay - timeSinceLastCalled, delay - timeSinceLastInvoked);\n  }\n\n  function timerExpired() {\n    const time = Date.now();\n    if (shouldInvoke(time)) {\n      return trailingEdge(time);\n    }\n\n    timerId = startTimer(timerExpired, remainingWait(time));\n  }\n\n  function trailingEdge(time: number) {\n    timerId = undefined;\n\n    if (lastArgs) {\n      return invoke(time);\n    }\n\n    lastArgs = undefined;\n    lastThis = undefined;\n    return result;\n  }\n\n  function debounced(this: any, ...args: any[]) {\n    const time = Date.now();\n    const isInvoking = shouldInvoke(time);\n\n    lastArgs = args;\n    lastThis = this;\n    lastCalled = time;\n\n    if (isInvoking) {\n      if (timerId === undefined) {\n        return leadingEdge(lastCalled);\n      }\n\n      timerId = startTimer(timerExpired, delay);\n      return invoke(lastCalled);\n    }\n\n    if (timerId === undefined) {\n      timerId = startTimer(timerExpired, delay);\n    }\n\n    return result;\n  }\n\n  return debounced;\n}\n"
  },
  {
    "path": "packages/designer/src/builtin-simulator/viewport.ts",
    "content": "import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';\nimport { Point, ScrollTarget } from '../designer';\nimport { AutoFit, IViewport } from '../simulator';\n\nexport default class Viewport implements IViewport {\n  @obx.ref private rect?: DOMRect;\n\n  private _bounds?: DOMRect;\n\n  get bounds(): DOMRect {\n    if (this._bounds) {\n      return this._bounds;\n    }\n    this._bounds = this.viewportElement!.getBoundingClientRect();\n    requestAnimationFrame(() => {\n      this._bounds = undefined;\n    });\n    return this._bounds;\n  }\n\n  get contentBounds(): DOMRect {\n    const { bounds, scale } = this;\n    return new DOMRect(0, 0, bounds.width / scale, bounds.height / scale);\n  }\n\n  private viewportElement?: HTMLElement;\n\n  constructor() {\n    makeObservable(this);\n  }\n\n  mount(viewportElement: HTMLElement | null) {\n    if (!viewportElement || this.viewportElement === viewportElement) {\n      return;\n    }\n    this.viewportElement = viewportElement;\n    this.touch();\n  }\n\n  touch() {\n    if (this.viewportElement) {\n      this.rect = this.bounds;\n    }\n  }\n\n  @computed get height(): number {\n    if (!this.rect) {\n      return 600;\n    }\n    return this.rect.height;\n  }\n\n  set height(newHeight: number) {\n    this._contentHeight = newHeight / this.scale;\n    if (this.viewportElement) {\n      this.viewportElement.style.height = `${newHeight}px`;\n      this.touch();\n    }\n  }\n\n  @computed get width(): number {\n    if (!this.rect) {\n      return 1000;\n    }\n    return this.rect.width;\n  }\n\n  set width(newWidth: number) {\n    this._contentWidth = newWidth / this.scale;\n    if (this.viewportElement) {\n      this.viewportElement.style.width = `${newWidth}px`;\n      this.touch();\n    }\n  }\n\n  @obx.ref private _scale = 1;\n\n  /**\n   * 缩放比例\n   */\n  @computed get scale(): number {\n    return this._scale;\n  }\n\n  set scale(newScale: number) {\n    if (isNaN(newScale) || newScale <= 0) {\n      throw new Error(`invalid new scale \"${newScale}\"`);\n    }\n\n    this._scale = newScale;\n    this._contentWidth = this.width / this.scale;\n    this._contentHeight = this.height / this.scale;\n  }\n\n  @obx.ref private _contentWidth: number | AutoFit = AutoFit;\n\n  @obx.ref private _contentHeight: number | AutoFit = AutoFit;\n\n  @computed get contentHeight(): number | AutoFit {\n    return this._contentHeight;\n  }\n\n  set contentHeight(newContentHeight: number | AutoFit) {\n    this._contentHeight = newContentHeight;\n  }\n\n  @computed get contentWidth(): number | AutoFit {\n    return this._contentWidth;\n  }\n\n  set contentWidth(val: number | AutoFit) {\n    this._contentWidth = val;\n  }\n\n  @obx.ref private _scrollX = 0;\n\n  @obx.ref private _scrollY = 0;\n\n  get scrollX() {\n    return this._scrollX;\n  }\n\n  get scrollY() {\n    return this._scrollY;\n  }\n\n  private _scrollTarget?: ScrollTarget;\n\n  /**\n   * 滚动对象\n   */\n  get scrollTarget(): ScrollTarget | undefined {\n    return this._scrollTarget;\n  }\n\n  @obx private _scrolling = false;\n\n  get scrolling(): boolean {\n    return this._scrolling;\n  }\n\n  setScrollTarget(target: Window) {\n    const scrollTarget = new ScrollTarget(target);\n    this._scrollX = scrollTarget.left;\n    this._scrollY = scrollTarget.top;\n\n    let scrollTimer: any;\n    target.addEventListener('scroll', () => {\n      this._scrollX = scrollTarget.left;\n      this._scrollY = scrollTarget.top;\n      this._scrolling = true;\n      if (scrollTimer) {\n        clearTimeout(scrollTimer);\n      }\n      scrollTimer = setTimeout(() => {\n        this._scrolling = false;\n      }, 80);\n    });\n    target.addEventListener('resize', () => this.touch());\n    this._scrollTarget = scrollTarget;\n  }\n\n  toGlobalPoint(point: Point): Point {\n    if (!this.viewportElement) {\n      return point;\n    }\n\n    const rect = this.bounds;\n    return {\n      clientX: point.clientX * this.scale + rect.left,\n      clientY: point.clientY * this.scale + rect.top,\n    };\n  }\n\n  toLocalPoint(point: Point): Point {\n    if (!this.viewportElement) {\n      return point;\n    }\n\n    const rect = this.bounds;\n    return {\n      clientX: (point.clientX - rect.left) / this.scale,\n      clientY: (point.clientY - rect.top) / this.scale,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/component-actions.ts",
    "content": "import { IPublicModelNode, IPublicTypeComponentAction, IPublicTypeMetadataTransducer } from '@alilc/lowcode-types';\nimport { engineConfig } from '@alilc/lowcode-editor-core';\nimport { intlNode } from './locale';\nimport {\n  IconLock,\n  IconUnlock,\n  IconRemove,\n  IconClone,\n  IconHidden,\n} from './icons';\nimport { componentDefaults, legacyIssues } from './transducers';\n\nfunction deduplicateRef(node: IPublicModelNode | null | undefined) {\n  const currentRef = node?.getPropValue('ref');\n  if (currentRef) {\n    node?.setPropValue('ref', `${node.componentName.toLowerCase()}-${Math.random().toString(36).slice(2, 9)}`);\n  }\n  node?.children?.forEach(deduplicateRef);\n}\n\nexport class ComponentActions {\n  private metadataTransducers: IPublicTypeMetadataTransducer[] = [];\n\n  actions: IPublicTypeComponentAction[] = [\n    {\n      name: 'remove',\n      content: {\n        icon: IconRemove,\n        title: intlNode('remove'),\n        /* istanbul ignore next */\n        action(node: IPublicModelNode) {\n          node.remove();\n        },\n      },\n      important: true,\n    },\n    {\n      name: 'hide',\n      content: {\n        icon: IconHidden,\n        title: intlNode('hide'),\n        /* istanbul ignore next */\n        action(node: IPublicModelNode) {\n          node.visible = false;\n        },\n      },\n      /* istanbul ignore next */\n      condition: (node: IPublicModelNode) => {\n        return node.componentMeta?.isModal;\n      },\n      important: true,\n    },\n    {\n      name: 'copy',\n      content: {\n        icon: IconClone,\n        title: intlNode('copy'),\n        /* istanbul ignore next */\n        action(node: IPublicModelNode) {\n          // node.remove();\n          const { document: doc, parent, index } = node;\n          if (parent) {\n            const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true);\n            deduplicateRef(newNode);\n            newNode?.select();\n            const { isRGL, rglNode } = node?.getRGL();\n            if (isRGL) {\n              // 复制 layout 信息\n              const layout: any = rglNode?.getPropValue('layout') || [];\n              const curLayout = layout.filter((item: any) => item.i === node.getPropValue('fieldId'));\n              if (curLayout && curLayout[0]) {\n                layout.push({\n                  ...curLayout[0],\n                  i: newNode?.getPropValue('fieldId'),\n                });\n                rglNode?.setPropValue('layout', layout);\n                // 如果是磁贴块复制，则需要滚动到影响位置\n                setTimeout(() => newNode?.document?.project?.simulatorHost?.scrollToNode(newNode), 10);\n              }\n            }\n          }\n        },\n      },\n      important: true,\n    },\n    {\n      name: 'lock',\n      content: {\n        icon: IconLock, // 锁定 icon\n        title: intlNode('lock'),\n        /* istanbul ignore next */\n        action(node: IPublicModelNode) {\n          node.lock();\n        },\n      },\n      /* istanbul ignore next */\n      condition: (node: IPublicModelNode) => {\n        return engineConfig.get('enableCanvasLock', false) && node.isContainerNode && !node.isLocked;\n      },\n      important: true,\n    },\n    {\n      name: 'unlock',\n      content: {\n        icon: IconUnlock, // 解锁 icon\n        title: intlNode('unlock'),\n        /* istanbul ignore next */\n        action(node: IPublicModelNode) {\n          node.lock(false);\n        },\n      },\n      /* istanbul ignore next */\n      condition: (node: IPublicModelNode) => {\n        return engineConfig.get('enableCanvasLock', false) && node.isContainerNode && node.isLocked;\n      },\n      important: true,\n    },\n  ];\n\n  constructor() {\n    this.registerMetadataTransducer(legacyIssues, 2, 'legacy-issues'); // should use a high level priority, eg: 2\n    this.registerMetadataTransducer(componentDefaults, 100, 'component-defaults');\n  }\n\n  removeBuiltinComponentAction(name: string) {\n    const i = this.actions.findIndex((action) => action.name === name);\n    if (i > -1) {\n      this.actions.splice(i, 1);\n    }\n  }\n  addBuiltinComponentAction(action: IPublicTypeComponentAction) {\n    this.actions.push(action);\n  }\n\n  modifyBuiltinComponentAction(\n    actionName: string,\n    handle: (action: IPublicTypeComponentAction) => void,\n  ) {\n    const builtinAction = this.actions.find((action) => action.name === actionName);\n    if (builtinAction) {\n      handle(builtinAction);\n    }\n  }\n\n  registerMetadataTransducer(\n    transducer: IPublicTypeMetadataTransducer,\n    level = 100,\n    id?: string,\n  ) {\n    transducer.level = level;\n    transducer.id = id;\n    const i = this.metadataTransducers.findIndex((item) => item.level != null && item.level > level);\n    if (i < 0) {\n      this.metadataTransducers.push(transducer);\n    } else {\n      this.metadataTransducers.splice(i, 0, transducer);\n    }\n  }\n\n  getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[] {\n    return this.metadataTransducers;\n  }\n}"
  },
  {
    "path": "packages/designer/src/component-meta.ts",
    "content": "import { ReactElement } from 'react';\nimport {\n  IPublicTypeComponentMetadata,\n  IPublicTypeNpmInfo,\n  IPublicTypeNodeData,\n  IPublicTypeNodeSchema,\n  IPublicTypeTitleContent,\n  IPublicTypeTransformedComponentMetadata,\n  IPublicTypeNestingFilter,\n  IPublicTypeI18nData,\n  IPublicTypeFieldConfig,\n  IPublicModelComponentMeta,\n  IPublicTypeAdvanced,\n  IPublicTypeDisposable,\n  IPublicTypeLiveTextEditingConfig,\n} from '@alilc/lowcode-types';\nimport { deprecate, isRegExp, isTitleConfig, isNode } from '@alilc/lowcode-utils';\nimport { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';\nimport { Node, INode } from './document';\nimport { Designer } from './designer';\nimport {\n  IconContainer,\n  IconPage,\n  IconComponent,\n} from './icons';\n\nexport function ensureAList(list?: string | string[]): string[] | null {\n  if (!list) {\n    return null;\n  }\n  if (!Array.isArray(list)) {\n    if (typeof list !== 'string') {\n      return null;\n    }\n    list = list.split(/ *[ ,|] */).filter(Boolean);\n  }\n  if (list.length < 1) {\n    return null;\n  }\n  return list;\n}\n\nexport function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNestingFilter) {\n  if (!rule) {\n    return null;\n  }\n  if (typeof rule === 'function') {\n    return rule;\n  }\n  if (isRegExp(rule)) {\n    return (testNode: Node | IPublicTypeNodeSchema) => {\n      return rule.test(testNode.componentName);\n    };\n  }\n  const list = ensureAList(rule);\n  if (!list) {\n    return null;\n  }\n  return (testNode: Node | IPublicTypeNodeSchema) => {\n    return list.includes(testNode.componentName);\n  };\n}\n\nexport interface IComponentMeta extends IPublicModelComponentMeta<INode> {\n  prototype?: any;\n\n  liveTextEditing?: IPublicTypeLiveTextEditingConfig[];\n\n  get rootSelector(): string | undefined;\n\n  setMetadata(metadata: IPublicTypeComponentMetadata): void;\n\n  onMetadataChange(fn: (args: any) => void): IPublicTypeDisposable;\n}\n\nexport class ComponentMeta implements IComponentMeta {\n  readonly isComponentMeta = true;\n\n  private _npm?: IPublicTypeNpmInfo;\n\n  private emitter: IEventBus = createModuleEventBus('ComponentMeta');\n\n  get npm() {\n    return this._npm;\n  }\n\n  set npm(_npm: any) {\n    this.setNpm(_npm);\n  }\n\n  private _componentName?: string;\n\n  get componentName(): string {\n    return this._componentName!;\n  }\n\n  private _isContainer?: boolean;\n\n  get isContainer(): boolean {\n    return this._isContainer! || this.isRootComponent();\n  }\n\n  get isMinimalRenderUnit(): boolean {\n    return this._isMinimalRenderUnit || false;\n  }\n\n  private _isModal?: boolean;\n\n  get isModal(): boolean {\n    return this._isModal!;\n  }\n\n  private _descriptor?: string;\n\n  get descriptor(): string | undefined {\n    return this._descriptor;\n  }\n\n  private _rootSelector?: string;\n\n  get rootSelector(): string | undefined {\n    return this._rootSelector;\n  }\n\n  private _transformedMetadata?: IPublicTypeTransformedComponentMetadata;\n\n  get configure(): IPublicTypeFieldConfig[] {\n    const config = this._transformedMetadata?.configure;\n    return config?.combined || config?.props || [];\n  }\n\n  private _liveTextEditing?: IPublicTypeLiveTextEditingConfig[];\n\n  get liveTextEditing() {\n    return this._liveTextEditing;\n  }\n\n  private _isTopFixed?: boolean;\n\n  get isTopFixed(): boolean {\n    return !!(this._isTopFixed);\n  }\n\n  private parentWhitelist?: IPublicTypeNestingFilter | null;\n\n  private childWhitelist?: IPublicTypeNestingFilter | null;\n\n  private _title?: IPublicTypeTitleContent;\n\n  private _isMinimalRenderUnit?: boolean;\n\n  get title(): string | IPublicTypeI18nData | ReactElement {\n    // string | i18nData | ReactElement\n    // TitleConfig title.label\n    if (isTitleConfig(this._title)) {\n      return (this._title?.label as any) || this.componentName;\n    }\n    return this._title || this.componentName;\n  }\n\n  @computed get icon() {\n    // give Slot default icon\n    // if _title is TitleConfig  get _title.icon\n    return (\n      this._transformedMetadata?.icon ||\n      // eslint-disable-next-line\n      (this.componentName === 'Page' ? IconPage : this.isContainer ? IconContainer : IconComponent)\n    );\n  }\n\n  private _acceptable?: boolean;\n\n  get acceptable(): boolean {\n    return this._acceptable!;\n  }\n\n  get advanced(): IPublicTypeAdvanced {\n    return this.getMetadata().configure.advanced || {};\n  }\n\n  /**\n   * @legacy compatiable for vision\n   * @deprecated\n   */\n  prototype?: any;\n\n  constructor(readonly designer: Designer, metadata: IPublicTypeComponentMetadata) {\n    this.parseMetadata(metadata);\n  }\n\n  setNpm(info: IPublicTypeNpmInfo) {\n    if (!this._npm) {\n      this._npm = info;\n    }\n  }\n\n  private parseMetadata(metadata: IPublicTypeComponentMetadata) {\n    const { componentName, npm, ...others } = metadata;\n    let _metadata = metadata;\n    if ((metadata as any).prototype) {\n      this.prototype = (metadata as any).prototype;\n    }\n    if (!npm && !Object.keys(others).length) {\n      // 没有注册的组件，只能删除，不支持复制、移动等操作\n      _metadata = {\n        componentName,\n        configure: {\n          component: {\n            disableBehaviors: ['copy', 'move', 'lock', 'unlock'],\n          },\n          advanced: {\n            callbacks: {\n              onMoveHook: () => false,\n            },\n          },\n        },\n      };\n    }\n    this._npm = npm || this._npm;\n    this._componentName = componentName;\n\n    // 额外转换逻辑\n    this._transformedMetadata = this.transformMetadata(_metadata);\n\n    const { title } = this._transformedMetadata;\n    if (title) {\n      this._title =\n        typeof title === 'string'\n          ? {\n              type: 'i18n',\n              'en-US': this.componentName,\n              'zh-CN': title,\n            }\n          : title;\n    }\n\n    const liveTextEditing = this.advanced.liveTextEditing || [];\n\n    function collectLiveTextEditing(items: IPublicTypeFieldConfig[]) {\n      items.forEach((config) => {\n        if (config?.items) {\n          collectLiveTextEditing(config.items);\n        } else {\n          const liveConfig = config.liveTextEditing || config.extraProps?.liveTextEditing;\n          if (liveConfig) {\n            liveTextEditing.push({\n              propTarget: String(config.name),\n              ...liveConfig,\n            });\n          }\n        }\n      });\n    }\n    collectLiveTextEditing(this.configure);\n    this._liveTextEditing = liveTextEditing.length > 0 ? liveTextEditing : undefined;\n\n    const isTopFixed = this.advanced.isTopFixed;\n\n    if (isTopFixed) {\n      this._isTopFixed = isTopFixed;\n    }\n\n    const { configure = {} } = this._transformedMetadata;\n    this._acceptable = false;\n\n    const { component } = configure;\n    if (component) {\n      this._isContainer = !!component.isContainer;\n      this._isModal = !!component.isModal;\n      this._descriptor = component.descriptor;\n      this._rootSelector = component.rootSelector;\n      this._isMinimalRenderUnit = component.isMinimalRenderUnit;\n      if (component.nestingRule) {\n        const { parentWhitelist, childWhitelist } = component.nestingRule;\n        this.parentWhitelist = buildFilter(parentWhitelist);\n        this.childWhitelist = buildFilter(childWhitelist);\n      }\n    } else {\n      this._isContainer = false;\n      this._isModal = false;\n    }\n    this.emitter.emit('metadata_change');\n  }\n\n  refreshMetadata() {\n    this.parseMetadata(this.getMetadata());\n  }\n\n  private transformMetadata(\n      metadta: IPublicTypeComponentMetadata,\n    ): IPublicTypeTransformedComponentMetadata {\n    const registeredTransducers = this.designer.componentActions.getRegisteredMetadataTransducers();\n    const result = registeredTransducers.reduce((prevMetadata, current) => {\n      return current(prevMetadata);\n    }, preprocessMetadata(metadta));\n\n    if (!result.configure) {\n      result.configure = {};\n    }\n    if (result.experimental && !result.configure.advanced) {\n      deprecate(result.experimental, '.experimental', '.configure.advanced');\n      result.configure.advanced = result.experimental;\n    }\n    return result as any;\n  }\n\n  isRootComponent(includeBlock = true): boolean {\n    return (\n      this.componentName === 'Page' ||\n      this.componentName === 'Component' ||\n      (includeBlock && this.componentName === 'Block')\n    );\n  }\n\n  @computed get availableActions() {\n    // eslint-disable-next-line prefer-const\n    let { disableBehaviors, actions } = this._transformedMetadata?.configure.component || {};\n    const disabled =\n      ensureAList(disableBehaviors) ||\n      (this.isRootComponent(false) ? ['copy', 'remove', 'lock', 'unlock'] : null);\n    actions = this.designer.componentActions.actions.concat(\n      this.designer.getGlobalComponentActions() || [],\n      actions || [],\n    );\n\n    if (disabled) {\n      if (disabled.includes('*')) {\n        return actions.filter((action) => action.condition === 'always');\n      }\n      return actions.filter((action) => disabled.indexOf(action.name) < 0);\n    }\n    return actions;\n  }\n\n  setMetadata(metadata: IPublicTypeComponentMetadata) {\n    this.parseMetadata(metadata);\n  }\n\n  getMetadata(): IPublicTypeTransformedComponentMetadata {\n    return this._transformedMetadata!;\n  }\n\n  checkNestingUp(my: INode | IPublicTypeNodeData, parent: INode) {\n    // 检查父子关系，直接约束型，在画布中拖拽直接掠过目标容器\n    if (this.parentWhitelist) {\n      return this.parentWhitelist(\n        parent.internalToShellNode(),\n        isNode<INode>(my) ? my.internalToShellNode() : my,\n      );\n    }\n    return true;\n  }\n\n  checkNestingDown(my: INode, target: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[]): boolean {\n    // 检查父子关系，直接约束型，在画布中拖拽直接掠过目标容器\n    if (this.childWhitelist) {\n      const _target: any = !Array.isArray(target) ? [target] : target;\n      return _target.every((item: Node | IPublicTypeNodeSchema) => {\n        const _item = !isNode<INode>(item) ? new Node(my.document, item) : item;\n        return (\n          this.childWhitelist &&\n          this.childWhitelist(_item.internalToShellNode(), my.internalToShellNode())\n        );\n      });\n    }\n    return true;\n  }\n\n  onMetadataChange(fn: (args: any) => void): IPublicTypeDisposable {\n    this.emitter.on('metadata_change', fn);\n    return () => {\n      this.emitter.removeListener('metadata_change', fn);\n    };\n  }\n\n}\n\nexport function isComponentMeta(obj: any): obj is ComponentMeta {\n  return obj && obj.isComponentMeta;\n}\n\nfunction preprocessMetadata(metadata: IPublicTypeComponentMetadata): IPublicTypeTransformedComponentMetadata {\n  if (metadata.configure) {\n    if (Array.isArray(metadata.configure)) {\n      return {\n        ...metadata,\n        configure: {\n          props: metadata.configure,\n        },\n      };\n    }\n    return metadata as any;\n  }\n\n  return {\n    ...metadata,\n    configure: {},\n  };\n}\n"
  },
  {
    "path": "packages/designer/src/context-menu-actions.scss",
    "content": ".engine-context-menu {\n  &.next-menu.next-ver .next-menu-item {\n    padding-right: 30px;\n\n    .next-menu-item-inner {\n      height: var(--context-menu-item-height, 30px);\n      line-height: var(--context-menu-item-height, 30px);\n    }\n  }\n}"
  },
  {
    "path": "packages/designer/src/context-menu-actions.ts",
    "content": "import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial, IPublicModelPluginContext } from '@alilc/lowcode-types';\nimport { IDesigner, INode } from './designer';\nimport { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils';\nimport { Menu } from '@alifd/next';\nimport { engineConfig } from '@alilc/lowcode-editor-core';\nimport './context-menu-actions.scss';\n\nexport interface IContextMenuActions {\n  actions: IPublicTypeContextMenuAction[];\n\n  adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[];\n\n  addMenuAction: IPublicApiMaterial['addContextMenuOption'];\n\n  removeMenuAction: IPublicApiMaterial['removeContextMenuOption'];\n\n  adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout'];\n}\n\nlet adjustMenuLayoutFn: Function = (actions: IPublicTypeContextMenuAction[]) => actions;\n\nexport class GlobalContextMenuActions {\n  enableContextMenu: boolean;\n\n  dispose: Function[];\n\n  contextMenuActionsMap: Map<string, ContextMenuActions> = new Map();\n\n  constructor() {\n    this.dispose = [];\n\n    engineConfig.onGot('enableContextMenu', (enable) => {\n      if (this.enableContextMenu === enable) {\n        return;\n      }\n      this.enableContextMenu = enable;\n      this.dispose.forEach(d => d());\n      if (enable) {\n        this.initEvent();\n      }\n    });\n  }\n\n  handleContextMenu = (\n    event: MouseEvent,\n  ) => {\n    event.stopPropagation();\n    event.preventDefault();\n\n    const actions: IPublicTypeContextMenuAction[] = [];\n    let contextMenu: ContextMenuActions = this.contextMenuActionsMap.values().next().value;\n    this.contextMenuActionsMap.forEach((contextMenu) => {\n      actions.push(...contextMenu.actions);\n    });\n\n    let destroyFn: Function | undefined;\n\n    const destroy = () => {\n      destroyFn?.();\n    };\n    const pluginContext: IPublicModelPluginContext = contextMenu.designer.editor.get('pluginContext') as IPublicModelPluginContext;\n\n    const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {\n      nodes: [],\n      destroy,\n      event,\n      pluginContext,\n    });\n\n    if (!menus.length) {\n      return;\n    }\n\n    const layoutMenu = adjustMenuLayoutFn(menus);\n\n    const menuNode = parseContextMenuAsReactNode(layoutMenu, {\n      destroy,\n      nodes: [],\n      pluginContext,\n    });\n\n    const target = event.target;\n\n    const { top, left } = target?.getBoundingClientRect();\n\n    const menuInstance = Menu.create({\n      target: event.target,\n      offset: [event.clientX - left, event.clientY - top],\n      children: menuNode,\n      className: 'engine-context-menu',\n    });\n\n    destroyFn = (menuInstance as any).destroy;\n  };\n\n  initEvent() {\n    this.dispose.push(\n      (() => {\n        const handleContextMenu = (e: MouseEvent) => {\n          this.handleContextMenu(e);\n        };\n\n        document.addEventListener('contextmenu', handleContextMenu);\n\n        return () => {\n          document.removeEventListener('contextmenu', handleContextMenu);\n        };\n      })(),\n    );\n  }\n\n  registerContextMenuActions(contextMenu: ContextMenuActions) {\n    this.contextMenuActionsMap.set(contextMenu.id, contextMenu);\n  }\n}\n\nconst globalContextMenuActions = new GlobalContextMenuActions();\n\nexport class ContextMenuActions implements IContextMenuActions {\n  actions: IPublicTypeContextMenuAction[] = [];\n\n  designer: IDesigner;\n\n  dispose: Function[];\n\n  enableContextMenu: boolean;\n\n  id: string = uniqueId('contextMenu');;\n\n  constructor(designer: IDesigner) {\n    this.designer = designer;\n    this.dispose = [];\n\n    engineConfig.onGot('enableContextMenu', (enable) => {\n      if (this.enableContextMenu === enable) {\n        return;\n      }\n      this.enableContextMenu = enable;\n      this.dispose.forEach(d => d());\n      if (enable) {\n        this.initEvent();\n      }\n    });\n\n    globalContextMenuActions.registerContextMenuActions(this);\n  }\n\n  handleContextMenu = (\n    nodes: INode[],\n    event: MouseEvent,\n  ) => {\n    const designer = this.designer;\n    event.stopPropagation();\n    event.preventDefault();\n\n    const actions = designer.contextMenuActions.actions;\n\n    const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } };\n    const { left: simulatorLeft, top: simulatorTop } = bounds;\n\n    let destroyFn: Function | undefined;\n\n    const destroy = () => {\n      destroyFn?.();\n    };\n\n    const pluginContext: IPublicModelPluginContext = this.designer.editor.get('pluginContext') as IPublicModelPluginContext;\n\n    const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {\n      nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),\n      destroy,\n      event,\n      pluginContext,\n    });\n\n    if (!menus.length) {\n      return;\n    }\n\n    const layoutMenu = adjustMenuLayoutFn(menus);\n\n    const menuNode = parseContextMenuAsReactNode(layoutMenu, {\n      destroy,\n      nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),\n      pluginContext,\n    });\n\n    destroyFn = createContextMenu(menuNode, {\n      event,\n      offset: [simulatorLeft, simulatorTop],\n    });\n  };\n\n  initEvent() {\n    const designer = this.designer;\n    this.dispose.push(\n      designer.editor.eventBus.on('designer.builtinSimulator.contextmenu', ({\n        node,\n        originalEvent,\n      }: {\n        node: INode;\n        originalEvent: MouseEvent;\n      }) => {\n        originalEvent.stopPropagation();\n        originalEvent.preventDefault();\n        // 如果右键的节点不在 当前选中的节点中，选中该节点\n        if (!designer.currentSelection.has(node.id)) {\n          designer.currentSelection.select(node.id);\n        }\n        const nodes = designer.currentSelection.getNodes();\n        this.handleContextMenu(nodes, originalEvent);\n      }),\n    );\n  }\n\n  addMenuAction(action: IPublicTypeContextMenuAction) {\n    this.actions.push({\n      type: IPublicEnumContextMenuType.MENU_ITEM,\n      ...action,\n    });\n  }\n\n  removeMenuAction(name: string) {\n    const i = this.actions.findIndex((action) => action.name === name);\n    if (i > -1) {\n      this.actions.splice(i, 1);\n    }\n  }\n\n  adjustMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) {\n    adjustMenuLayoutFn = fn;\n  }\n}"
  },
  {
    "path": "packages/designer/src/designer/active-tracker.ts",
    "content": "import { INode } from '../document/node/node';\nimport { obx, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicTypeActiveTarget,\n  IPublicModelActiveTracker,\n} from '@alilc/lowcode-types';\nimport { isNode } from '@alilc/lowcode-utils';\n\nexport interface IActiveTracker extends Omit< IPublicModelActiveTracker, 'track' | 'onChange' > {\n  _target: ActiveTarget | INode;\n\n  track(originalTarget: ActiveTarget | INode): void;\n\n  onChange(fn: (target: ActiveTarget) => void): () => void;\n}\n\nexport interface ActiveTarget extends Omit< IPublicTypeActiveTarget, 'node' > {\n  node: INode;\n}\n\nexport class ActiveTracker implements IActiveTracker {\n  @obx.ref private _target?: ActiveTarget | INode;\n\n  private emitter: IEventBus = createModuleEventBus('ActiveTracker');\n\n  track(originalTarget: ActiveTarget | INode) {\n    let target = originalTarget;\n    if (isNode(originalTarget)) {\n      target = { node: originalTarget as INode };\n    }\n    this._target = target;\n    this.emitter.emit('change', target);\n  }\n\n  get currentNode() {\n    return (this._target as ActiveTarget)?.node;\n  }\n\n  get detail() {\n    return (this._target as ActiveTarget)?.detail;\n  }\n\n  /**\n   * @deprecated\n   */\n  /* istanbul ignore next */\n  get intance() {\n    return this.instance;\n  }\n\n  get instance() {\n    return (this._target as ActiveTarget)?.instance;\n  }\n\n  onChange(fn: (target: ActiveTarget) => void): () => void {\n    this.emitter.addListener('change', fn);\n    return () => {\n      this.emitter.removeListener('change', fn);\n    };\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/clipboard.ts",
    "content": "import { IPublicModelClipboard } from '@alilc/lowcode-types';\n\nfunction getDataFromPasteEvent(event: ClipboardEvent) {\n  const { clipboardData } = event;\n  if (!clipboardData) {\n    return null;\n  }\n\n  try {\n    // { componentsMap, componentsTree, ... }\n    const data = JSON.parse(clipboardData.getData('text/plain'));\n    if (!data) {\n      return {};\n    }\n    if (data.componentsTree) {\n      return data;\n    } else if (data.componentName) {\n      return {\n        componentsTree: [data],\n      };\n    }\n  } catch (error) {\n    // TODO: open the parser implement\n    return { };\n  }\n}\n\nexport interface IClipboard extends IPublicModelClipboard {\n\n  initCopyPaster(el: HTMLTextAreaElement): void;\n\n  injectCopyPaster(document: Document): void;\n}\nclass Clipboard implements IClipboard {\n  private copyPasters: HTMLTextAreaElement[] = [];\n\n  private waitFn?: (data: any, e: ClipboardEvent) => void;\n\n  constructor() {\n    this.injectCopyPaster(document);\n  }\n\n  isCopyPasteEvent(e: Event) {\n    this.isCopyPaster(e.target);\n  }\n\n  private isCopyPaster(el: any) {\n    return this.copyPasters.includes(el);\n  }\n\n  initCopyPaster(el: HTMLTextAreaElement) {\n    this.copyPasters.push(el);\n    const onPaste = (e: ClipboardEvent) => {\n      if (this.waitFn) {\n        this.waitFn(getDataFromPasteEvent(e), e);\n        this.waitFn = undefined;\n      }\n      el.blur();\n    };\n    el.addEventListener('paste', onPaste, false);\n    return () => {\n      el.removeEventListener('paste', onPaste, false);\n      const i = this.copyPasters.indexOf(el);\n      if (i > -1) {\n        this.copyPasters.splice(i, 1);\n      }\n    };\n  }\n\n  injectCopyPaster(document: Document) {\n    if (this.copyPasters.find((x) => x.ownerDocument === document)) {\n      return;\n    }\n    const copyPaster = document.createElement<'textarea'>('textarea');\n    copyPaster.style.cssText = 'position: absolute;left: -9999px;top:-100px';\n    if (document.body) {\n      document.body.appendChild(copyPaster);\n    } else {\n      document.addEventListener('DOMContentLoaded', () => {\n        document.body.appendChild(copyPaster);\n      });\n    }\n    const dispose = this.initCopyPaster(copyPaster);\n    return () => {\n      dispose();\n      document.removeChild(copyPaster);\n    };\n  }\n\n  setData(data: any): void {\n    const copyPaster = this.copyPasters.find((x) => x.ownerDocument);\n    if (!copyPaster) {\n      return;\n    }\n    copyPaster.value = typeof data === 'string' ? data : JSON.stringify(data);\n    copyPaster.select();\n    copyPaster.ownerDocument!.execCommand('copy');\n\n    copyPaster.blur();\n  }\n\n  waitPasteData(keyboardEvent: KeyboardEvent, cb: (data: any, e: ClipboardEvent) => void) {\n    const win = keyboardEvent.view;\n    if (!win) {\n      return;\n    }\n    const copyPaster = this.copyPasters.find((cp) => cp.ownerDocument === win.document);\n    if (copyPaster) {\n      copyPaster.select();\n      this.waitFn = cb;\n    }\n  }\n}\n\nexport const clipboard = new Clipboard();\n"
  },
  {
    "path": "packages/designer/src/designer/designer-view.tsx",
    "content": "import { Component } from 'react';\nimport classNames from 'classnames';\nimport BuiltinDragGhostComponent from './drag-ghost';\nimport { Designer, DesignerProps } from './designer';\nimport { ProjectView } from '../project';\nimport './designer.less';\n\ntype IProps = DesignerProps & {\n  designer?: Designer;\n};\n\nexport class DesignerView extends Component<IProps> {\n  readonly designer: Designer;\n  readonly viewName: string | undefined;\n\n  constructor(props: IProps) {\n    super(props);\n    const { designer, ...designerProps } = props;\n    this.viewName = designer?.viewName;\n    if (designer) {\n      this.designer = designer;\n      designer.setProps(designerProps);\n    } else {\n      this.designer = new Designer(designerProps);\n    }\n  }\n\n  shouldComponentUpdate(nextProps: DesignerProps) {\n    this.designer.setProps(nextProps);\n    const { props } = this;\n    if (\n      nextProps.className !== props.className ||\n      nextProps.style !== props.style ||\n      nextProps.dragGhostComponent !== props.dragGhostComponent\n    ) {\n      return true;\n    }\n    return false;\n  }\n\n  componentDidMount() {\n    const { onMount } = this.props;\n    if (onMount) {\n      onMount(this.designer);\n    }\n    this.designer.postEvent('mount', this.designer);\n  }\n\n  UNSAFE_componentWillMount() {\n    this.designer.purge();\n  }\n\n  render() {\n    const { className, style, dragGhostComponent } = this.props;\n    const DragGhost = dragGhostComponent || BuiltinDragGhostComponent;\n\n    return (\n      <div className={classNames('lc-designer', className)} style={style}>\n        <DragGhost designer={this.designer} />\n        <ProjectView designer={this.designer} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/designer.less",
    "content": ".lc-designer {\n  position: relative;\n  font-family: var(--font-family);\n  font-size: var(--font-size-text);\n  box-sizing: border-box;\n\n  * {\n    box-sizing: border-box;\n  }\n}\n\n\n\n"
  },
  {
    "path": "packages/designer/src/designer/designer.ts",
    "content": "import { ComponentType } from 'react';\nimport { obx, computed, autorun, makeObservable, IReactionPublic, IReactionOptions, IReactionDisposer } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicTypeProjectSchema,\n  IPublicTypeComponentMetadata,\n  IPublicTypeComponentAction,\n  IPublicTypeNpmInfo,\n  IPublicModelEditor,\n  IPublicTypeCompositeObject,\n  IPublicTypePropsList,\n  IPublicTypeNodeSchema,\n  IPublicTypePropsTransducer,\n  IShellModelFactory,\n  IPublicModelDragObject,\n  IPublicTypeScrollable,\n  IPublicModelScroller,\n  IPublicTypeLocationData,\n  IPublicEnumTransformStage,\n  IPublicModelLocateEvent,\n} from '@alilc/lowcode-types';\nimport { mergeAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils';\nimport { IProject, Project } from '../project';\nimport { Node, DocumentModel, insertChildren, INode, ISelection } from '../document';\nimport { ComponentMeta, IComponentMeta } from '../component-meta';\nimport { INodeSelector, Component } from '../simulator';\nimport { Scroller } from './scroller';\nimport { Dragon, IDragon } from './dragon';\nimport { ActiveTracker, IActiveTracker } from './active-tracker';\nimport { Detecting } from './detecting';\nimport { DropLocation } from './location';\nimport { OffsetObserver, createOffsetObserver } from './offset-observer';\nimport { ISettingTopEntry, SettingTopEntry } from './setting';\nimport { BemToolsManager } from '../builtin-simulator/bem-tools/manager';\nimport { ComponentActions } from '../component-actions';\nimport { ContextMenuActions, IContextMenuActions } from '../context-menu-actions';\n\nconst logger = new Logger({ level: 'warn', bizName: 'designer' });\n\nexport interface DesignerProps {\n  [key: string]: any;\n  editor: IPublicModelEditor;\n  shellModelFactory: IShellModelFactory;\n  className?: string;\n  style?: object;\n  defaultSchema?: IPublicTypeProjectSchema;\n  hotkeys?: object;\n  viewName?: string;\n  simulatorProps?: Record<string, any> | ((document: DocumentModel) => object);\n  simulatorComponent?: ComponentType<any>;\n  dragGhostComponent?: ComponentType<any>;\n  suspensed?: boolean;\n  componentMetadatas?: IPublicTypeComponentMetadata[];\n  globalComponentActions?: IPublicTypeComponentAction[];\n  onMount?: (designer: Designer) => void;\n  onDragstart?: (e: IPublicModelLocateEvent) => void;\n  onDrag?: (e: IPublicModelLocateEvent) => void;\n  onDragend?: (\n      e: { dragObject: IPublicModelDragObject; copy: boolean },\n      loc?: DropLocation,\n    ) => void;\n}\n\nexport interface IDesigner {\n  readonly shellModelFactory: IShellModelFactory;\n\n  viewName: string | undefined;\n\n  readonly project: IProject;\n\n  get dragon(): IDragon;\n\n  get activeTracker(): IActiveTracker;\n\n  get componentActions(): ComponentActions;\n\n  get contextMenuActions(): ContextMenuActions;\n\n  get editor(): IPublicModelEditor;\n\n  get detecting(): Detecting;\n\n  get simulatorComponent(): ComponentType<any> | undefined;\n\n  get currentSelection(): ISelection;\n\n  createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller;\n\n  refreshComponentMetasMap(): void;\n\n  createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null;\n\n  /**\n   * 创建插入位置，考虑放到 dragon 中\n   */\n  createLocation(locationData: IPublicTypeLocationData<INode>): DropLocation;\n\n  get componentsMap(): { [key: string]: IPublicTypeNpmInfo | Component };\n\n  loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise<void>;\n\n  getComponentMeta(\n    componentName: string,\n    generateMetadata?: () => IPublicTypeComponentMetadata | null,\n  ): IComponentMeta;\n\n  clearLocation(): void;\n\n  createComponentMeta(data: IPublicTypeComponentMetadata): IComponentMeta | null;\n\n  getComponentMetasMap(): Map<string, IComponentMeta>;\n\n  addPropsReducer(reducer: IPublicTypePropsTransducer, stage: IPublicEnumTransformStage): void;\n\n  postEvent(event: string, ...args: any[]): void;\n\n  transformProps(props: IPublicTypeCompositeObject | IPublicTypePropsList, node: Node, stage: IPublicEnumTransformStage): IPublicTypeCompositeObject | IPublicTypePropsList;\n\n  createSettingEntry(nodes: INode[]): ISettingTopEntry;\n\n  autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions<any, any>): IReactionDisposer;\n}\n\nexport class Designer implements IDesigner {\n  dragon: IDragon;\n\n  viewName: string | undefined;\n\n  readonly componentActions = new ComponentActions();\n\n  readonly contextMenuActions: IContextMenuActions;\n\n  readonly activeTracker = new ActiveTracker();\n\n  readonly detecting = new Detecting();\n\n  readonly project: IProject;\n\n  readonly editor: IPublicModelEditor;\n\n  readonly bemToolsManager = new BemToolsManager(this);\n\n  readonly shellModelFactory: IShellModelFactory;\n\n  private _dropLocation?: DropLocation;\n\n  private propsReducers = new Map<IPublicEnumTransformStage, IPublicTypePropsTransducer[]>();\n\n  private _lostComponentMetasMap = new Map<string, ComponentMeta>();\n\n  private props?: DesignerProps;\n\n  private oobxList: OffsetObserver[] = [];\n\n  private selectionDispose: undefined | (() => void);\n\n  @obx.ref private _componentMetasMap = new Map<string, IComponentMeta>();\n\n  @obx.ref private _simulatorComponent?: ComponentType<any>;\n\n  @obx.ref private _simulatorProps?: Record<string, any> | ((project: IProject) => object);\n\n  @obx.ref private _suspensed = false;\n\n  get currentDocument() {\n    return this.project.currentDocument;\n  }\n\n  get currentHistory() {\n    return this.currentDocument?.history;\n  }\n\n  get currentSelection() {\n    return this.currentDocument?.selection;\n  }\n\n  constructor(props: DesignerProps) {\n    makeObservable(this);\n    const { editor, viewName, shellModelFactory } = props;\n    this.editor = editor;\n    this.viewName = viewName;\n    this.shellModelFactory = shellModelFactory;\n    this.setProps(props);\n\n    this.project = new Project(this, props.defaultSchema, viewName);\n\n    this.dragon = new Dragon(this);\n    this.dragon.onDragstart((e) => {\n      this.detecting.enable = false;\n      const { dragObject } = e;\n      if (isDragNodeObject(dragObject)) {\n        if (dragObject.nodes.length === 1) {\n          if (dragObject.nodes[0].parent) {\n            // ensure current selecting\n            dragObject.nodes[0].select();\n          } else {\n            this.currentSelection?.clear();\n          }\n        }\n      } else {\n        this.currentSelection?.clear();\n      }\n      if (this.props?.onDragstart) {\n        this.props.onDragstart(e);\n      }\n      this.postEvent('dragstart', e);\n    });\n\n    this.contextMenuActions = new ContextMenuActions(this);\n\n    this.dragon.onDrag((e) => {\n      if (this.props?.onDrag) {\n        this.props.onDrag(e);\n      }\n      this.postEvent('drag', e);\n    });\n\n    this.dragon.onDragend((e) => {\n      const { dragObject, copy } = e;\n      logger.debug('onDragend: dragObject ', dragObject, ' copy ', copy);\n      const loc = this._dropLocation;\n      if (loc) {\n        if (isLocationChildrenDetail(loc.detail) && loc.detail.valid !== false) {\n          let nodes: INode[] | undefined;\n          if (isDragNodeObject(dragObject)) {\n            nodes = insertChildren(loc.target, [...dragObject.nodes], loc.detail.index, copy);\n          } else if (isDragNodeDataObject(dragObject)) {\n            // process nodeData\n            const nodeData = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];\n            const isNotNodeSchema = nodeData.find((item) => !isNodeSchema(item));\n            if (isNotNodeSchema) {\n              return;\n            }\n            nodes = insertChildren(loc.target, nodeData, loc.detail.index);\n          }\n          if (nodes) {\n            loc.document?.selection.selectAll(nodes.map((o) => o.id));\n            setTimeout(() => this.activeTracker.track(nodes![0]), 10);\n          }\n        }\n      }\n      if (this.props?.onDragend) {\n        this.props.onDragend(e, loc);\n      }\n      this.postEvent('dragend', e, loc);\n      this.detecting.enable = true;\n    });\n\n    this.activeTracker.onChange(({ node, detail }) => {\n      node.document?.simulator?.scrollToNode(node, detail);\n    });\n\n    let historyDispose: undefined | (() => void);\n    const setupHistory = () => {\n      if (historyDispose) {\n        historyDispose();\n        historyDispose = undefined;\n      }\n      this.postEvent('history.change', this.currentHistory);\n      if (this.currentHistory) {\n        const { currentHistory } = this;\n        historyDispose = currentHistory.onStateChange(() => {\n          this.postEvent('history.change', currentHistory);\n        });\n      }\n    };\n    this.project.onCurrentDocumentChange(() => {\n      this.postEvent('current-document.change', this.currentDocument);\n      this.postEvent('selection.change', this.currentSelection);\n      this.postEvent('history.change', this.currentHistory);\n      this.setupSelection();\n      setupHistory();\n    });\n    this.postEvent('init', this);\n    this.setupSelection();\n    setupHistory();\n  }\n\n  setupSelection = () => {\n    if (this.selectionDispose) {\n      this.selectionDispose();\n      this.selectionDispose = undefined;\n    }\n    const { currentSelection } = this;\n    // TODO: 避免选中 Page 组件，默认选中第一个子节点；新增规则 或 判断 Live 模式\n    if (\n      currentSelection &&\n      currentSelection.selected.length === 0 &&\n      this.simulatorProps?.designMode === 'live'\n    ) {\n      const rootNodeChildrens = this.currentDocument?.getRoot()?.getChildren()?.children;\n      if (rootNodeChildrens && rootNodeChildrens.length > 0) {\n        currentSelection.select(rootNodeChildrens[0].id);\n      }\n    }\n    this.postEvent('selection.change', currentSelection);\n    if (currentSelection) {\n      this.selectionDispose = currentSelection.onSelectionChange(() => {\n        this.postEvent('selection.change', currentSelection);\n      });\n    }\n  };\n\n  postEvent(event: string, ...args: any[]) {\n    this.editor.eventBus.emit(`designer.${event}`, ...args);\n  }\n\n  get dropLocation() {\n    return this._dropLocation;\n  }\n\n  /**\n   * 创建插入位置，考虑放到 dragon 中\n   */\n  createLocation(locationData: IPublicTypeLocationData<INode>): DropLocation {\n    const loc = new DropLocation(locationData);\n    if (this._dropLocation && this._dropLocation.document && this._dropLocation.document !== loc.document) {\n      this._dropLocation.document.dropLocation = null;\n    }\n    this._dropLocation = loc;\n    this.postEvent('dropLocation.change', loc);\n    if (loc.document) {\n      loc.document.dropLocation = loc;\n    }\n    this.activeTracker.track({ node: loc.target, detail: loc.detail });\n    return loc;\n  }\n\n  /**\n   * 清除插入位置\n   */\n  clearLocation() {\n    if (this._dropLocation && this._dropLocation.document) {\n      this._dropLocation.document.dropLocation = null;\n    }\n    this.postEvent('dropLocation.change', undefined);\n    this._dropLocation = undefined;\n  }\n\n  createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller {\n    return new Scroller(scrollable);\n  }\n\n  createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null {\n    const oobx = createOffsetObserver(nodeInstance);\n    this.clearOobxList();\n    if (oobx) {\n      this.oobxList.push(oobx);\n    }\n    return oobx;\n  }\n\n  private clearOobxList(force?: boolean) {\n    let l = this.oobxList.length;\n    if (l > 20 || force) {\n      while (l-- > 0) {\n        if (this.oobxList[l].isPurged()) {\n          this.oobxList.splice(l, 1);\n        }\n      }\n    }\n  }\n\n  touchOffsetObserver() {\n    this.clearOobxList(true);\n    this.oobxList.forEach((item) => item.compute());\n  }\n\n  createSettingEntry(nodes: INode[]): ISettingTopEntry {\n    return new SettingTopEntry(this.editor, nodes);\n  }\n\n  /**\n   * 获得合适的插入位置\n   * @deprecated\n   */\n  getSuitableInsertion(\n    insertNode?: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[],\n  ): { target: INode; index?: number } | null {\n    const activeDoc = this.project.currentDocument;\n    if (!activeDoc) {\n      return null;\n    }\n    if (\n      Array.isArray(insertNode) &&\n      isNodeSchema(insertNode[0]) &&\n      this.getComponentMeta(insertNode[0].componentName).isModal\n    ) {\n      return {\n        target: activeDoc.rootNode as INode,\n      };\n    }\n    const focusNode = activeDoc.focusNode!;\n    const nodes = activeDoc.selection.getNodes();\n    const refNode = nodes.find((item) => focusNode.contains(item));\n    let target;\n    let index: number | undefined;\n    if (!refNode || refNode === focusNode) {\n      target = focusNode;\n    } else if (refNode.componentMeta.isContainer) {\n      target = refNode;\n    } else {\n      // FIXME!!, parent maybe null\n      target = refNode.parent!;\n      index = (refNode.index || 0) + 1;\n    }\n\n    if (target && insertNode && !target.componentMeta.checkNestingDown(target, insertNode)) {\n      return null;\n    }\n\n    return { target, index };\n  }\n\n  setProps(nextProps: DesignerProps) {\n    const props = this.props ? { ...this.props, ...nextProps } : nextProps;\n    if (this.props) {\n      // check hotkeys\n      // TODO:\n      // check simulatorConfig\n      if (props.simulatorComponent !== this.props.simulatorComponent) {\n        this._simulatorComponent = props.simulatorComponent;\n      }\n      if (props.simulatorProps !== this.props.simulatorProps) {\n        this._simulatorProps = props.simulatorProps;\n        // 重新 setupSelection\n        if (props.simulatorProps?.designMode !== this.props.simulatorProps?.designMode) {\n          this.setupSelection();\n        }\n      }\n      if (props.suspensed !== this.props.suspensed && props.suspensed != null) {\n        this.suspensed = props.suspensed;\n      }\n      if (\n        props.componentMetadatas !== this.props.componentMetadatas &&\n        props.componentMetadatas != null\n      ) {\n        this.buildComponentMetasMap(props.componentMetadatas);\n      }\n    } else {\n      // init hotkeys\n      // todo:\n      // init simulatorConfig\n      if (props.simulatorComponent) {\n        this._simulatorComponent = props.simulatorComponent;\n      }\n      if (props.simulatorProps) {\n        this._simulatorProps = props.simulatorProps;\n      }\n      // init suspensed\n      if (props.suspensed != null) {\n        this.suspensed = props.suspensed;\n      }\n      if (props.componentMetadatas != null) {\n        this.buildComponentMetasMap(props.componentMetadatas);\n      }\n    }\n    this.props = props;\n  }\n\n  async loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise<void> {\n    const { components, packages } = incrementalAssets;\n    components && this.buildComponentMetasMap(components);\n    if (packages) {\n      await this.project.simulator?.setupComponents(packages);\n    }\n\n    if (components) {\n      // 合并 assets\n      let assets = this.editor.get('assets') || {};\n      let newAssets = mergeAssets(assets, incrementalAssets);\n      // 对于 assets 存在需要二次网络下载的过程，必须 await 等待结束之后，再进行事件触发\n      await this.editor.set('assets', newAssets);\n    }\n    // TODO: 因为涉及修改 prototype.view，之后在 renderer 里修改了 vc 的 view 获取逻辑后，可删除\n    this.refreshComponentMetasMap();\n    // 完成加载增量资源后发送事件，方便插件监听并处理相关逻辑\n    this.editor.eventBus.emit('designer.incrementalAssetsReady');\n  }\n\n  /**\n   * 刷新 componentMetasMap，可间接触发模拟器里的 buildComponents\n   */\n  refreshComponentMetasMap() {\n    this._componentMetasMap = new Map(this._componentMetasMap);\n  }\n\n  get(key: string): any {\n    return this.props?.[key];\n  }\n\n  @computed get simulatorComponent(): ComponentType<any> | undefined {\n    return this._simulatorComponent;\n  }\n\n  @computed get simulatorProps(): Record<string, any> {\n    if (typeof this._simulatorProps === 'function') {\n      return this._simulatorProps(this.project);\n    }\n    return this._simulatorProps || {};\n  }\n\n  /**\n   * 提供给模拟器的参数\n   */\n  @computed get projectSimulatorProps(): any {\n    return {\n      ...this.simulatorProps,\n      project: this.project,\n      designer: this,\n      onMount: (simulator: any) => {\n        this.project.mountSimulator(simulator);\n        this.editor.set('simulator', simulator);\n      },\n    };\n  }\n\n  get suspensed(): boolean {\n    return this._suspensed;\n  }\n\n  set suspensed(flag: boolean) {\n    this._suspensed = flag;\n    // Todo afterwards...\n    if (flag) {\n      // this.project.suspensed = true?\n    }\n  }\n\n  get schema(): IPublicTypeProjectSchema {\n    return this.project.getSchema();\n  }\n\n  setSchema(schema?: IPublicTypeProjectSchema) {\n    this.project.load(schema);\n  }\n\n  buildComponentMetasMap(metas: IPublicTypeComponentMetadata[]) {\n    metas.forEach((data) => this.createComponentMeta(data));\n  }\n\n  createComponentMeta(data: IPublicTypeComponentMetadata): IComponentMeta | null {\n    const key = data.componentName;\n    if (!key) {\n      return null;\n    }\n    let meta = this._componentMetasMap.get(key);\n    if (meta) {\n      meta.setMetadata(data);\n\n      this._componentMetasMap.set(key, meta);\n    } else {\n      meta = this._lostComponentMetasMap.get(key);\n\n      if (meta) {\n        meta.setMetadata(data);\n        this._lostComponentMetasMap.delete(key);\n      } else {\n        meta = new ComponentMeta(this, data);\n      }\n\n      this._componentMetasMap.set(key, meta);\n    }\n    return meta;\n  }\n\n  getGlobalComponentActions(): IPublicTypeComponentAction[] | null {\n    return this.props?.globalComponentActions || null;\n  }\n\n  getComponentMeta(\n    componentName: string,\n    generateMetadata?: () => IPublicTypeComponentMetadata | null,\n  ): IComponentMeta {\n    if (this._componentMetasMap.has(componentName)) {\n      return this._componentMetasMap.get(componentName)!;\n    }\n\n    if (this._lostComponentMetasMap.has(componentName)) {\n      return this._lostComponentMetasMap.get(componentName)!;\n    }\n\n    const meta = new ComponentMeta(this, {\n      componentName,\n      ...(generateMetadata ? generateMetadata() : null),\n    });\n\n    this._lostComponentMetasMap.set(componentName, meta);\n\n    return meta;\n  }\n\n  getComponentMetasMap() {\n    return this._componentMetasMap;\n  }\n\n  @computed get componentsMap(): { [key: string]: IPublicTypeNpmInfo | Component } {\n    const maps: any = {};\n    const designer = this;\n    designer._componentMetasMap.forEach((config, key) => {\n      const metaData = config.getMetadata();\n      if (metaData.devMode === 'lowCode') {\n        maps[key] = metaData.schema;\n      } else {\n        const { view } = config.advanced;\n        if (view) {\n          maps[key] = view;\n        } else {\n          maps[key] = config.npm;\n        }\n      }\n    });\n    return maps;\n  }\n\n  transformProps(props: IPublicTypeCompositeObject | IPublicTypePropsList, node: Node, stage: IPublicEnumTransformStage) {\n    if (Array.isArray(props)) {\n      // current not support, make this future\n      return props;\n    }\n\n    const reducers = this.propsReducers.get(stage);\n    if (!reducers) {\n      return props;\n    }\n\n    return reducers.reduce((xprops, reducer) => {\n      try {\n        return reducer(xprops, node.internalToShellNode() as any, { stage });\n      } catch (e) {\n        // todo: add log\n        console.warn(e);\n        return xprops;\n      }\n    }, props);\n  }\n\n  addPropsReducer(reducer: IPublicTypePropsTransducer, stage: IPublicEnumTransformStage) {\n    if (!reducer) {\n      logger.error('reducer is not available');\n      return;\n    }\n    const reducers = this.propsReducers.get(stage);\n    if (reducers) {\n      reducers.push(reducer);\n    } else {\n      this.propsReducers.set(stage, [reducer]);\n    }\n  }\n\n  autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions<any, any>): IReactionDisposer {\n    return autorun(effect, options);\n  }\n\n  purge() {\n    // TODO:\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/detecting.ts",
    "content": "import { makeObservable, obx, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { IPublicModelDetecting } from '@alilc/lowcode-types';\nimport type { IDocumentModel } from '../document/document-model';\nimport type { INode } from '../document/node/node';\n\nconst DETECTING_CHANGE_EVENT = 'detectingChange';\nexport interface IDetecting extends Omit<IPublicModelDetecting<INode>,\n  'capture' |\n  'release' |\n  'leave'\n> {\n  capture(node: INode | null): void;\n\n  release(node: INode | null): void;\n\n  leave(document: IDocumentModel | undefined): void;\n\n  get current(): INode | null;\n}\n\nexport class Detecting implements IDetecting {\n  @obx.ref private _enable = true;\n\n  /**\n   * 控制大纲树 hover 时是否出现悬停效果\n   * TODO: 将该逻辑从设计器中抽离出来\n   */\n  get enable() {\n    return this._enable;\n  }\n\n  set enable(flag: boolean) {\n    this._enable = flag;\n    if (!flag) {\n      this._current = null;\n    }\n  }\n\n  @obx.ref xRayMode = false;\n\n  @obx.ref private _current: INode | null = null;\n\n  private emitter: IEventBus = createModuleEventBus('Detecting');\n\n  constructor() {\n    makeObservable(this);\n  }\n\n  get current() {\n    return this._current;\n  }\n\n  capture(node: INode | null) {\n    if (this._current !== node) {\n      this._current = node;\n      this.emitter.emit(DETECTING_CHANGE_EVENT, this.current);\n    }\n  }\n\n  release(node: INode | null) {\n    if (this._current === node) {\n      this._current = null;\n      this.emitter.emit(DETECTING_CHANGE_EVENT, this.current);\n    }\n  }\n\n  leave(document: IDocumentModel | undefined) {\n    if (this.current && this.current.document === document) {\n      this._current = null;\n    }\n  }\n\n  onDetectingChange(fn: (node: INode) => void) {\n    this.emitter.on(DETECTING_CHANGE_EVENT, fn);\n    return () => {\n      this.emitter.off(DETECTING_CHANGE_EVENT, fn);\n    };\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/drag-ghost/README.md",
    "content": "内置拖拽替身\n"
  },
  {
    "path": "packages/designer/src/designer/drag-ghost/ghost.less",
    "content": ".lc-ghost-group {\n  box-sizing: border-box;\n  position: fixed;\n  z-index: 99999;\n  width: 100px;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  pointer-events: none;\n  background-color: var(--color-block-background-deep-dark, rgba(0, 0, 0, 0.4));\n  box-shadow: 0 0 6px var(--color-block-background-shallow, grey);\n  transform: translate(-10%, -50%);\n  .lc-ghost {\n    .lc-ghost-title {\n      text-align: center;\n      font-size: var(--font-size-text);\n      text-overflow: ellipsis;\n      color: var(--color-text-light);\n      white-space: nowrap;\n      overflow: hidden;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/drag-ghost/index.tsx",
    "content": "import { Component, ReactElement } from 'react';\nimport { observer, obx, Title, makeObservable } from '@alilc/lowcode-editor-core';\nimport { Designer } from '../designer';\nimport { isDragNodeObject } from '../dragon';\nimport { isSimulatorHost } from '../../simulator';\nimport './ghost.less';\nimport { IPublicTypeI18nData, IPublicTypeNodeSchema, IPublicModelDragObject } from '@alilc/lowcode-types';\n\ntype offBinding = () => any;\n\n@observer\nexport default class DragGhost extends Component<{ designer: Designer }> {\n  private dispose: offBinding[] = [];\n\n  @obx.ref private titles: (string | IPublicTypeI18nData | ReactElement)[] | null = null;\n\n  @obx.ref private x = 0;\n\n  @obx.ref private y = 0;\n\n  @obx private isAbsoluteLayoutContainer = false;\n\n  private dragon = this.props.designer.dragon;\n\n  constructor(props: any) {\n    super(props);\n    makeObservable(this);\n    this.dispose = [\n      this.dragon.onDragstart(e => {\n        if (e.originalEvent.type.slice(0, 4) === 'drag') {\n          return;\n        }\n        this.titles = this.getTitles(e.dragObject);\n        this.x = e.globalX;\n        this.y = e.globalY;\n      }),\n      this.dragon.onDrag(e => {\n        this.x = e.globalX;\n        this.y = e.globalY;\n        if (isSimulatorHost(e.sensor)) {\n          const container = e.sensor.getDropContainer(e);\n          if (container?.container.componentMeta.advanced.isAbsoluteLayoutContainer) {\n            this.isAbsoluteLayoutContainer = true;\n            return;\n          }\n        }\n        this.isAbsoluteLayoutContainer = false;\n      }),\n      this.dragon.onDragend(() => {\n        this.titles = null;\n        this.x = 0;\n        this.y = 0;\n      }),\n    ];\n  }\n\n  getTitles(dragObject: IPublicModelDragObject) {\n    if (isDragNodeObject(dragObject)) {\n      return dragObject.nodes.map((node) => node.title);\n    }\n\n    const dataList = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];\n\n    return dataList.map((item: IPublicTypeNodeSchema, i) => (this.props.designer.getComponentMeta(item.componentName).title));\n  }\n\n  componentWillUnmount() {\n    if (this.dispose) {\n      this.dispose.forEach(off => off());\n    }\n  }\n\n  renderGhostGroup() {\n    return this.titles?.map((title, i) => {\n      const ghost = (\n        <div className=\"lc-ghost\" key={i}>\n          <Title title={title} />\n        </div>\n      );\n      return ghost;\n    });\n  }\n\n  render() {\n    if (!this.titles || !this.titles.length) {\n      return null;\n    }\n\n    if (this.isAbsoluteLayoutContainer) {\n      return null;\n    }\n\n    return (\n      <div\n        className=\"lc-ghost-group\"\n        style={{\n          left: this.x,\n          top: this.y,\n        }}\n      >\n        {this.renderGhostGroup()}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/dragon.ts",
    "content": "import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicTypeDragNodeObject,\n  IPublicTypeDragAnyObject,\n  IPublicEnumDragObjectType,\n  IPublicTypeDragNodeDataObject,\n  IPublicModelDragObject,\n  IPublicModelNode,\n  IPublicModelDragon,\n  IPublicModelLocateEvent,\n  IPublicModelSensor,\n} from '@alilc/lowcode-types';\nimport { setNativeSelection, cursor } from '@alilc/lowcode-utils';\nimport { INode, Node } from '../document';\nimport { ISimulatorHost, isSimulatorHost } from '../simulator';\nimport { IDesigner } from './designer';\nimport { makeEventsHandler } from '../utils/misc';\n\nexport interface ILocateEvent extends IPublicModelLocateEvent {\n  readonly type: 'LocateEvent';\n\n  /**\n   * 激活的感应器\n   */\n  sensor?: IPublicModelSensor;\n}\n\n/**\n * @deprecated use same function in @alilc/lowcode-utils\n */\nexport function isDragNodeObject(obj: any): obj is IPublicTypeDragNodeObject {\n  return obj && obj.type === IPublicEnumDragObjectType.Node;\n}\n\n/**\n * @deprecated use same function in @alilc/lowcode-utils\n */\nexport function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject {\n  return obj && obj.type === IPublicEnumDragObjectType.NodeData;\n}\n\n/**\n * @deprecated use same function in @alilc/lowcode-utils\n */\nexport function isDragAnyObject(obj: any): obj is IPublicTypeDragAnyObject {\n  return obj && obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node;\n}\n\nexport function isLocateEvent(e: any): e is ILocateEvent {\n  return e && e.type === 'LocateEvent';\n}\n\nconst SHAKE_DISTANCE = 4;\n\n/**\n * mouse shake check\n */\nexport function isShaken(e1: MouseEvent | DragEvent, e2: MouseEvent | DragEvent): boolean {\n  if ((e1 as any).shaken) {\n    return true;\n  }\n  if (e1.target !== e2.target) {\n    return true;\n  }\n  return (\n    Math.pow(e1.clientY - e2.clientY, 2) + Math.pow(e1.clientX - e2.clientX, 2) > SHAKE_DISTANCE\n  );\n}\n\nexport function isInvalidPoint(e: any, last: any): boolean {\n  return (\n    e.clientX === 0 &&\n    e.clientY === 0 &&\n    last &&\n    (Math.abs(last.clientX - e.clientX) > 5 || Math.abs(last.clientY - e.clientY) > 5)\n  );\n}\n\nexport function isSameAs(e1: MouseEvent | DragEvent, e2: MouseEvent | DragEvent): boolean {\n  return e1.clientY === e2.clientY && e1.clientX === e2.clientX;\n}\n\nexport function setShaken(e: any) {\n  e.shaken = true;\n}\n\nfunction getSourceSensor(dragObject: IPublicModelDragObject): ISimulatorHost | null {\n  if (!isDragNodeObject(dragObject)) {\n    return null;\n  }\n  return dragObject.nodes[0]?.document?.simulator || null;\n}\n\nfunction isDragEvent(e: any): e is DragEvent {\n  return e?.type?.startsWith('drag');\n}\n\nexport interface IDragon extends IPublicModelDragon<\n  INode,\n  ILocateEvent\n> {\n  emitter: IEventBus;\n}\n\n/**\n * Drag-on 拖拽引擎\n */\nexport class Dragon implements IDragon {\n  private sensors: IPublicModelSensor[] = [];\n\n  private nodeInstPointerEvents: boolean;\n\n  key = Math.random();\n\n  /**\n   * current active sensor, 可用于感应区高亮\n   */\n  @obx.ref private _activeSensor: IPublicModelSensor | undefined;\n\n  get activeSensor(): IPublicModelSensor | undefined {\n    return this._activeSensor;\n  }\n\n  @obx.ref private _dragging = false;\n\n  @obx.ref private _canDrop = false;\n\n  get dragging(): boolean {\n    return this._dragging;\n  }\n\n  viewName: string | undefined;\n\n  emitter: IEventBus = createModuleEventBus('Dragon');\n\n  constructor(readonly designer: IDesigner) {\n    makeObservable(this);\n    this.viewName = designer.viewName;\n  }\n\n  /**\n   * Quick listen a shell(container element) drag behavior\n   * @param shell container element\n   * @param boost boost got a drag object\n   */\n  from(shell: Element, boost: (e: MouseEvent) => IPublicModelDragObject | null) {\n    const mousedown = (e: MouseEvent) => {\n      // ESC or RightClick\n      if (e.which === 3 || e.button === 2) {\n        return;\n      }\n\n      // Get a new node to be dragged\n      const dragObject = boost(e);\n      if (!dragObject) {\n        return;\n      }\n\n      this.boost(dragObject, e);\n    };\n    shell.addEventListener('mousedown', mousedown as any);\n    return () => {\n      shell.removeEventListener('mousedown', mousedown as any);\n    };\n  }\n\n  /**\n   * boost your dragObject for dragging(flying) 发射拖拽对象\n   *\n   * @param dragObject 拖拽对象\n   * @param boostEvent 拖拽初始时事件\n   */\n  boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: INode | IPublicModelNode) {\n    const { designer } = this;\n    const masterSensors = this.getMasterSensors();\n    const handleEvents = makeEventsHandler(boostEvent, masterSensors);\n    const newBie = !isDragNodeObject(dragObject);\n    const forceCopyState =\n      isDragNodeObject(dragObject) && dragObject.nodes.some((node: Node | IPublicModelNode) => (typeof node.isSlot === 'function' ? node.isSlot() : node.isSlot));\n    const isBoostFromDragAPI = isDragEvent(boostEvent);\n    let lastSensor: IPublicModelSensor | undefined;\n\n    this._dragging = false;\n\n    const getRGL = (e: MouseEvent | DragEvent) => {\n      const locateEvent = createLocateEvent(e);\n      const sensor = chooseSensor(locateEvent);\n      if (!sensor || !sensor.getNodeInstanceFromElement) return {};\n      const nodeInst = sensor.getNodeInstanceFromElement(e.target as Element);\n      return nodeInst?.node?.getRGL() || {};\n    };\n\n    const checkesc = (e: KeyboardEvent) => {\n      if (e.keyCode === 27) {\n        designer.clearLocation();\n        over();\n      }\n    };\n\n    let copy = false;\n    const checkcopy = (e: MouseEvent | DragEvent | KeyboardEvent) => {\n      /* istanbul ignore next */\n      if (isDragEvent(e) && e.dataTransfer) {\n        if (newBie || forceCopyState) {\n          e.dataTransfer.dropEffect = 'copy';\n        }\n        return;\n      }\n      if (newBie) {\n        return;\n      }\n\n      if (e.altKey || e.ctrlKey) {\n        copy = true;\n        this.setCopyState(true);\n        /* istanbul ignore next */\n        if (isDragEvent(e) && e.dataTransfer) {\n          e.dataTransfer.dropEffect = 'copy';\n        }\n      } else {\n        copy = false;\n        if (!forceCopyState) {\n          this.setCopyState(false);\n          /* istanbul ignore next */\n          if (isDragEvent(e) && e.dataTransfer) {\n            e.dataTransfer.dropEffect = 'move';\n          }\n        }\n      }\n    };\n\n    let lastArrive: any;\n    const drag = (e: MouseEvent | DragEvent) => {\n      // FIXME: donot setcopy when: newbie & no location\n      checkcopy(e);\n\n      if (isInvalidPoint(e, lastArrive)) return;\n\n      if (lastArrive && isSameAs(e, lastArrive)) {\n        lastArrive = e;\n        return;\n      }\n      lastArrive = e;\n\n      const { isRGL, rglNode } = getRGL(e);\n      const locateEvent = createLocateEvent(e);\n      const sensor = chooseSensor(locateEvent);\n\n      /* istanbul ignore next */\n      if (isRGL) {\n        // 禁止被拖拽元素的阻断\n        const nodeInst = dragObject.nodes[0].getDOMNode();\n        if (nodeInst && nodeInst.style) {\n          this.nodeInstPointerEvents = true;\n          nodeInst.style.pointerEvents = 'none';\n        }\n        // 原生拖拽\n        this.emitter.emit('rgl.sleeping', false);\n        if (fromRglNode && fromRglNode.id === rglNode.id) {\n          designer.clearLocation();\n          this.clearState();\n          this.emitter.emit('drag', locateEvent);\n          return;\n        }\n        this._canDrop = !!sensor?.locate(locateEvent);\n        if (this._canDrop) {\n          this.emitter.emit('rgl.add.placeholder', {\n            rglNode,\n            fromRglNode,\n            node: locateEvent.dragObject?.nodes[0],\n            event: e,\n          });\n          designer.clearLocation();\n          this.clearState();\n          this.emitter.emit('drag', locateEvent);\n          return;\n        }\n      } else {\n        this._canDrop = false;\n        this.emitter.emit('rgl.remove.placeholder');\n        this.emitter.emit('rgl.sleeping', true);\n      }\n      if (sensor) {\n        sensor.fixEvent(locateEvent);\n        sensor.locate(locateEvent);\n      } else {\n        designer.clearLocation();\n      }\n      this.emitter.emit('drag', locateEvent);\n    };\n\n    const dragstart = () => {\n      this._dragging = true;\n      setShaken(boostEvent);\n      const locateEvent = createLocateEvent(boostEvent);\n      if (newBie || forceCopyState) {\n        this.setCopyState(true);\n      } else {\n        chooseSensor(locateEvent);\n      }\n      this.setDraggingState(true);\n      // ESC cancel drag\n      if (!isBoostFromDragAPI) {\n        handleEvents((doc) => {\n          doc.addEventListener('keydown', checkesc, false);\n        });\n      }\n\n      this.emitter.emit('dragstart', locateEvent);\n    };\n\n    // route: drag-move\n    const move = (e: MouseEvent | DragEvent) => {\n      /* istanbul ignore next */\n      if (isBoostFromDragAPI) {\n        e.preventDefault();\n      }\n      if (this._dragging) {\n        // process dragging\n        drag(e);\n        return;\n      }\n\n      // first move check is shaken\n      if (isShaken(boostEvent, e)) {\n        // is shaken dragstart\n        dragstart();\n        drag(e);\n      }\n    };\n\n    let didDrop = true;\n    /* istanbul ignore next */\n    const drop = (e: DragEvent) => {\n      e.preventDefault();\n      e.stopPropagation();\n      didDrop = true;\n    };\n\n    // end-tail drag process\n    const over = (e?: any) => {\n      // 禁止被拖拽元素的阻断\n      if (this.nodeInstPointerEvents) {\n        const nodeInst = dragObject.nodes[0].getDOMNode();\n        if (nodeInst && nodeInst.style) {\n          nodeInst.style.pointerEvents = '';\n        }\n        this.nodeInstPointerEvents = false;\n      }\n\n      // 发送drop事件\n      if (e) {\n        const { isRGL, rglNode } = getRGL(e);\n        /* istanbul ignore next */\n        if (isRGL && this._canDrop && this._dragging) {\n          const tarNode = dragObject.nodes[0];\n          if (rglNode.id !== tarNode.id) {\n            // 避免死循环\n            this.emitter.emit('rgl.drop', {\n              rglNode,\n              node: tarNode,\n            });\n            const selection = designer.project.currentDocument?.selection;\n            selection?.select(tarNode.id);\n          }\n        }\n      }\n\n      // 移除磁帖占位消息\n      this.emitter.emit('rgl.remove.placeholder');\n\n      /* istanbul ignore next */\n      if (e && isDragEvent(e)) {\n        e.preventDefault();\n      }\n      if (lastSensor) {\n        lastSensor.deactiveSensor();\n      }\n      /* istanbul ignore next */\n      if (isBoostFromDragAPI) {\n        if (!didDrop) {\n          designer.clearLocation();\n        }\n      } else {\n        this.setNativeSelection(true);\n      }\n      this.clearState();\n\n      let exception;\n      if (this._dragging) {\n        this._dragging = false;\n        try {\n          this.emitter.emit('dragend', { dragObject, copy });\n        } catch (ex) /* istanbul ignore next */ {\n          exception = ex;\n        }\n      }\n      designer.clearLocation();\n\n      handleEvents((doc) => {\n        /* istanbul ignore next */\n        if (isBoostFromDragAPI) {\n          doc.removeEventListener('dragover', move, true);\n          doc.removeEventListener('dragend', over, true);\n          doc.removeEventListener('drop', drop, true);\n        } else {\n          doc.removeEventListener('mousemove', move, true);\n          doc.removeEventListener('mouseup', over, true);\n        }\n        doc.removeEventListener('mousedown', over, true);\n        doc.removeEventListener('keydown', checkesc, false);\n        doc.removeEventListener('keydown', checkcopy, false);\n        doc.removeEventListener('keyup', checkcopy, false);\n      });\n      /* istanbul ignore next */\n      if (exception) {\n        throw exception;\n      }\n    };\n\n    // create drag locate event\n    const createLocateEvent = (e: MouseEvent | DragEvent): ILocateEvent => {\n      const evt: any = {\n        type: 'LocateEvent',\n        dragObject,\n        target: e.target,\n        originalEvent: e,\n      };\n\n      const sourceDocument = e.view?.document;\n\n      // event from current document\n      if (!sourceDocument || sourceDocument === document) {\n        evt.globalX = e.clientX;\n        evt.globalY = e.clientY;\n      } else /* istanbul ignore next */ {\n        // event from simulator sandbox\n        let srcSim: ISimulatorHost | undefined;\n        const lastSim = lastSensor && isSimulatorHost(lastSensor) ? lastSensor : null;\n        // check source simulator\n        if (lastSim && lastSim.contentDocument === sourceDocument) {\n          srcSim = lastSim;\n        } else {\n          srcSim = masterSensors.find((sim) => sim.contentDocument === sourceDocument);\n          if (!srcSim && lastSim) {\n            srcSim = lastSim;\n          }\n        }\n        if (srcSim) {\n          // transform point by simulator\n          const g = srcSim.viewport.toGlobalPoint(e);\n          evt.globalX = g.clientX;\n          evt.globalY = g.clientY;\n          evt.canvasX = e.clientX;\n          evt.canvasY = e.clientY;\n          evt.sensor = srcSim;\n        } else {\n          // this condition will not happen, just make sure ts ok\n          evt.globalX = e.clientX;\n          evt.globalY = e.clientY;\n        }\n      }\n      return evt;\n    };\n\n    const sourceSensor = getSourceSensor(dragObject);\n    /* istanbul ignore next */\n    const chooseSensor = (e: ILocateEvent) => {\n      // this.sensors will change on dragstart\n      const sensors: IPublicModelSensor[] = this.sensors.concat(masterSensors as IPublicModelSensor[]);\n      let sensor =\n        e.sensor && e.sensor.isEnter(e)\n          ? e.sensor\n          : sensors.find((s) => s.sensorAvailable && s.isEnter(e));\n      if (!sensor) {\n        // TODO: enter some area like componentspanel cancel\n        if (lastSensor) {\n          sensor = lastSensor;\n        } else if (e.sensor) {\n          sensor = e.sensor;\n        } else if (sourceSensor) {\n          sensor = sourceSensor;\n        }\n      }\n      if (sensor !== lastSensor) {\n        if (lastSensor) {\n          lastSensor.deactiveSensor();\n        }\n        lastSensor = sensor;\n      }\n      if (sensor) {\n        e.sensor = sensor;\n        sensor.fixEvent(e);\n      }\n      this._activeSensor = sensor;\n      return sensor;\n    };\n\n    /* istanbul ignore next */\n    if (isDragEvent(boostEvent)) {\n      const { dataTransfer } = boostEvent;\n\n      if (dataTransfer) {\n        dataTransfer.effectAllowed = 'all';\n\n        try {\n          dataTransfer.setData('application/json', '{}');\n        } catch (ex) {\n          // ignore\n        }\n      }\n\n      dragstart();\n    } else {\n      this.setNativeSelection(false);\n    }\n\n    handleEvents((doc) => {\n      /* istanbul ignore next */\n      if (isBoostFromDragAPI) {\n        doc.addEventListener('dragover', move, true);\n        // dragexit\n        didDrop = false;\n        doc.addEventListener('drop', drop, true);\n        doc.addEventListener('dragend', over, true);\n      } else {\n        doc.addEventListener('mousemove', move, true);\n        doc.addEventListener('mouseup', over, true);\n      }\n      doc.addEventListener('mousedown', over, true);\n    });\n\n    // future think: drag things from browser-out or a iframe-pane\n\n    if (!newBie && !isBoostFromDragAPI) {\n      handleEvents((doc) => {\n        doc.addEventListener('keydown', checkcopy, false);\n        doc.addEventListener('keyup', checkcopy, false);\n      });\n    }\n  }\n\n  /* istanbul ignore next */\n  private getMasterSensors(): ISimulatorHost[] {\n    return Array.from(\n      new Set(\n        this.designer.project.documents\n          .map((doc) => {\n            if (doc.active && doc.simulator?.sensorAvailable) {\n              return doc.simulator;\n            }\n            return null;\n          })\n          .filter(Boolean) as any,\n      ),\n    );\n  }\n\n  private getSimulators() {\n    return new Set(this.designer.project.documents.map((doc) => doc.simulator));\n  }\n\n  // #region ======== drag and drop helpers ============\n  private setNativeSelection(enableFlag: boolean) {\n    setNativeSelection(enableFlag);\n    this.getSimulators().forEach((sim) => {\n      sim?.setNativeSelection(enableFlag);\n    });\n  }\n\n  /**\n   * 设置拖拽态\n   */\n  private setDraggingState(state: boolean) {\n    cursor.setDragging(state);\n    this.getSimulators().forEach((sim) => {\n      sim?.setDraggingState(state);\n    });\n  }\n\n  /**\n   * 设置拷贝态\n   */\n  private setCopyState(state: boolean) {\n    cursor.setCopy(state);\n    this.getSimulators().forEach((sim) => {\n      sim?.setCopyState(state);\n    });\n  }\n\n  /**\n   * 清除所有态：拖拽态、拷贝态\n   */\n  private clearState() {\n    cursor.release();\n    this.getSimulators().forEach((sim) => {\n      sim?.clearState();\n    });\n  }\n  // #endregion\n\n  /**\n   * 添加投放感应区\n   */\n  addSensor(sensor: any) {\n    this.sensors.push(sensor);\n  }\n\n  /**\n   * 移除投放感应\n   */\n  removeSensor(sensor: any) {\n    const i = this.sensors.indexOf(sensor);\n    if (i > -1) {\n      this.sensors.splice(i, 1);\n    }\n  }\n\n  onDragstart(func: (e: ILocateEvent) => any) {\n    this.emitter.on('dragstart', func);\n    return () => {\n      this.emitter.removeListener('dragstart', func);\n    };\n  }\n\n  onDrag(func: (e: ILocateEvent) => any) {\n    this.emitter.on('drag', func);\n    return () => {\n      this.emitter.removeListener('drag', func);\n    };\n  }\n\n  onDragend(func: (x: { dragObject: IPublicModelDragObject; copy: boolean }) => any) {\n    this.emitter.on('dragend', func);\n    return () => {\n      this.emitter.removeListener('dragend', func);\n    };\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/index.ts",
    "content": "export * from './designer';\nexport * from './designer-view';\nexport * from './dragon';\nexport * from './detecting';\nexport * from './location';\nexport * from './offset-observer';\nexport * from './scroller';\nexport * from './setting';\nexport * from './active-tracker';\nexport * from '../document';\nexport * from './clipboard';\n"
  },
  {
    "path": "packages/designer/src/designer/location.ts",
    "content": "import type { IDocumentModel, INode } from '../document';\nimport { ILocateEvent } from './dragon';\nimport {\n  IPublicModelDropLocation,\n  IPublicTypeLocationDetailType,\n  IPublicTypeRect,\n  IPublicTypeLocationDetail,\n  IPublicTypeLocationData,\n  IPublicModelLocateEvent,\n} from '@alilc/lowcode-types';\n\nexport interface Point {\n  clientX: number;\n  clientY: number;\n}\n\nexport interface CanvasPoint {\n  canvasX: number;\n  canvasY: number;\n}\n\nexport type Rects = DOMRect[] & {\n  elements: Array<Element | Text>;\n};\n\n/**\n * @deprecated use same function in @alilc/lowcode-utils\n */\nexport function isLocationData(obj: any): boolean {\n  return obj && obj.target && obj.detail;\n}\n\n/**\n * @deprecated use same function in @alilc/lowcode-utils\n */\nexport function isLocationChildrenDetail(obj: any): boolean {\n  return obj && obj.type === IPublicTypeLocationDetailType.Children;\n}\n\nexport function isRowContainer(container: Element | Text, win?: Window) {\n  if (isText(container)) {\n    return true;\n  }\n  const style = (win || getWindow(container)).getComputedStyle(container);\n  const display = style.getPropertyValue('display');\n  if (/flex$/.test(display)) {\n    const direction = style.getPropertyValue('flex-direction') || 'row';\n    if (direction === 'row' || direction === 'row-reverse') {\n      return true;\n    }\n  }\n  if (/grid$/.test(display)) {\n    return true;\n  }\n  return false;\n}\n\nexport function isChildInline(child: Element | Text, win?: Window) {\n  if (isText(child)) {\n    return true;\n  }\n  const style = (win || getWindow(child)).getComputedStyle(child);\n  return /^inline/.test(style.getPropertyValue('display')) || /^(left|right)$/.test(style.getPropertyValue('float'));\n}\n\nexport function getRectTarget(rect: IPublicTypeRect | null) {\n  if (!rect || rect.computed) {\n    return null;\n  }\n  const els = rect.elements;\n  return els && els.length > 0 ? els[0]! : null;\n}\n\nexport function isVerticalContainer(rect: IPublicTypeRect | null) {\n  const el = getRectTarget(rect);\n  if (!el) {\n    return false;\n  }\n  return isRowContainer(el);\n}\n\nexport function isVertical(rect: IPublicTypeRect | null) {\n  const el = getRectTarget(rect);\n  if (!el) {\n    return false;\n  }\n  return isChildInline(el) || (el.parentElement ? isRowContainer(el.parentElement) : false);\n}\n\nfunction isText(elem: any): elem is Text {\n  return elem.nodeType === Node.TEXT_NODE;\n}\n\nfunction isDocument(elem: any): elem is Document {\n  return elem.nodeType === Node.DOCUMENT_NODE;\n}\n\nexport function getWindow(elem: Element | Document): Window {\n  return (isDocument(elem) ? elem : elem.ownerDocument!).defaultView!;\n}\nexport interface IDropLocation extends Omit<IPublicModelDropLocation, 'target' | 'clone'> {\n\n  readonly source: string;\n\n  get target(): INode;\n\n  get document(): IDocumentModel | null;\n\n  clone(event: IPublicModelLocateEvent): IDropLocation;\n}\n\nexport class DropLocation implements IDropLocation {\n  readonly target: INode;\n\n  readonly detail: IPublicTypeLocationDetail;\n\n  readonly event: ILocateEvent;\n\n  readonly source: string;\n\n  get document(): IDocumentModel | null {\n    return this.target.document;\n  }\n\n  constructor({ target, detail, source, event }: IPublicTypeLocationData<INode>) {\n    this.target = target;\n    this.detail = detail;\n    this.source = source;\n    this.event = event;\n  }\n\n  clone(event: ILocateEvent): IDropLocation {\n    return new DropLocation({\n      target: this.target,\n      detail: this.detail,\n      source: this.source,\n      event,\n    });\n  }\n\n  /**\n   * @deprecated\n   * 兼容 vision\n   */\n  getContainer() {\n    return this.target;\n  }\n\n  /**\n   * @deprecated\n   * 兼容 vision\n   */\n  getInsertion() {\n    if (!this.detail) {\n      return null;\n    }\n    if (this.detail.type === 'Children') {\n      if (this.detail.index <= 0) {\n        return null;\n      }\n      return this.target.children?.get(this.detail.index - 1);\n    }\n    return (this.detail as any)?.near?.node;\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/offset-observer.ts",
    "content": "import requestIdleCallback, { cancelIdleCallback } from 'ric-shim';\nimport { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';\nimport { uniqueId } from '@alilc/lowcode-utils';\nimport { INodeSelector, IViewport } from '../simulator';\nimport { INode } from '../document';\n\nexport class OffsetObserver {\n  readonly id = uniqueId('oobx');\n\n  private lastOffsetLeft?: number;\n\n  private lastOffsetTop?: number;\n\n  private lastOffsetHeight?: number;\n\n  private lastOffsetWidth?: number;\n\n  @obx private _height = 0;\n\n  @obx private _width = 0;\n\n  @obx private _left = 0;\n\n  @obx private _top = 0;\n\n  @obx private _right = 0;\n\n  @obx private _bottom = 0;\n\n  @computed get height() {\n    return this.isRoot ? this.viewport.height : this._height * this.scale;\n  }\n\n  @computed get width() {\n    return this.isRoot ? this.viewport.width : this._width * this.scale;\n  }\n\n  @computed get top() {\n    return this.isRoot ? 0 : this._top * this.scale;\n  }\n\n  @computed get left() {\n    return this.isRoot ? 0 : this._left * this.scale;\n  }\n\n  @computed get bottom() {\n    return this.isRoot ? this.viewport.height : this._bottom * this.scale;\n  }\n\n  @computed get right() {\n    return this.isRoot ? this.viewport.width : this._right * this.scale;\n  }\n\n  @obx hasOffset = false;\n\n  @computed get offsetLeft() {\n    if (this.isRoot) {\n      return this.viewport.scrollX * this.scale;\n    }\n    if (!this.viewport.scrolling || this.lastOffsetLeft == null) {\n      this.lastOffsetLeft = this.left + this.viewport.scrollX * this.scale;\n    }\n    return this.lastOffsetLeft;\n  }\n\n  @computed get offsetTop() {\n    if (this.isRoot) {\n      return this.viewport.scrollY * this.scale;\n    }\n    if (!this.viewport.scrolling || this.lastOffsetTop == null) {\n      this.lastOffsetTop = this.top + this.viewport.scrollY * this.scale;\n    }\n    return this.lastOffsetTop;\n  }\n\n  @computed get offsetHeight() {\n    if (!this.viewport.scrolling || this.lastOffsetHeight == null) {\n      this.lastOffsetHeight = this.isRoot ? this.viewport.height : this.height;\n    }\n    return this.lastOffsetHeight;\n  }\n\n  @computed get offsetWidth() {\n    if (!this.viewport.scrolling || this.lastOffsetWidth == null) {\n      this.lastOffsetWidth = this.isRoot ? this.viewport.width : this.width;\n    }\n    return this.lastOffsetWidth;\n  }\n\n  @computed get scale() {\n    return this.viewport.scale;\n  }\n\n  private pid: number | undefined;\n\n  readonly viewport: IViewport | undefined;\n\n  private isRoot: boolean;\n\n  readonly node: INode;\n\n  readonly compute: () => void;\n\n  constructor(readonly nodeInstance: INodeSelector) {\n    const { node, instance } = nodeInstance;\n    this.node = node;\n    const doc = node.document;\n    const host = doc?.simulator;\n    const focusNode = doc?.focusNode;\n    this.isRoot = node.contains(focusNode!);\n    this.viewport = host?.viewport;\n    makeObservable(this);\n    if (this.isRoot) {\n      this.hasOffset = true;\n      return;\n    }\n    if (!instance) {\n      return;\n    }\n\n    let pid: number | undefined;\n    const compute = () => {\n      if (pid !== this.pid) {\n        return;\n      }\n\n      const rect = host.computeComponentInstanceRect(instance!, node.componentMeta.rootSelector);\n\n      if (!rect) {\n        this.hasOffset = false;\n      } else if (!this.viewport.scrolling || !this.hasOffset) {\n        this._height = rect.height;\n        this._width = rect.width;\n        this._left = rect.left;\n        this._top = rect.top;\n        this._right = rect.right;\n        this._bottom = rect.bottom;\n        this.hasOffset = true;\n      }\n      this.pid = requestIdleCallback(compute);\n      pid = this.pid;\n    };\n\n    this.compute = compute;\n\n    // try first\n    compute();\n    // try second, ensure the dom mounted\n    this.pid = requestIdleCallback(compute);\n    pid = this.pid;\n  }\n\n  purge() {\n    if (this.pid) {\n      cancelIdleCallback(this.pid);\n    }\n    this.pid = undefined;\n  }\n\n  isPurged() {\n    return this.pid == null;\n  }\n}\n\nexport function createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null {\n  if (!nodeInstance.instance) {\n    return null;\n  }\n  return new OffsetObserver(nodeInstance);\n}\n"
  },
  {
    "path": "packages/designer/src/designer/scroller.ts",
    "content": "import { isElement } from '@alilc/lowcode-utils';\nimport { IPublicModelScrollTarget, IPublicTypeScrollable, IPublicModelScroller } from '@alilc/lowcode-types';\n\nexport interface IScrollTarget extends IPublicModelScrollTarget {\n}\n\nexport class ScrollTarget implements IScrollTarget {\n  get left() {\n    return 'scrollX' in this.target ? this.target.scrollX : this.target.scrollLeft;\n  }\n\n  get top() {\n    return 'scrollY' in this.target ? this.target.scrollY : this.target.scrollTop;\n  }\n\n  private doc?: HTMLElement;\n\n  constructor(private target: Window | Element) {\n    if (isWindow(target)) {\n      this.doc = target.document.documentElement;\n    }\n  }\n\n  scrollTo(options: { left?: number; top?: number }) {\n    this.target.scrollTo(options);\n  }\n\n  scrollToXY(x: number, y: number) {\n    this.target.scrollTo(x, y);\n  }\n\n  get scrollHeight(): number {\n    return ((this.doc || this.target) as any).scrollHeight;\n  }\n\n  get scrollWidth(): number {\n    return ((this.doc || this.target) as any).scrollWidth;\n  }\n}\n\nfunction isWindow(obj: any): obj is Window {\n  return obj && obj.document;\n}\n\nfunction easing(n: number) {\n  return Math.sin((n * Math.PI) / 2);\n}\n\nconst SCROLL_ACCURACY = 30;\n\nexport interface IScroller extends IPublicModelScroller {\n\n}\nexport class Scroller implements IScroller {\n  private pid: number | undefined;\n  scrollable: IPublicTypeScrollable;\n\n  constructor(scrollable: IPublicTypeScrollable) {\n    this.scrollable = scrollable;\n  }\n\n  get scrollTarget(): IScrollTarget | null {\n    let target = this.scrollable.scrollTarget;\n    if (!target) {\n      return null;\n    }\n    if (isElement(target)) {\n      target = new ScrollTarget(target);\n      this.scrollable.scrollTarget = target;\n    }\n    return target;\n  }\n\n  scrollTo(options: { left?: number; top?: number }) {\n    this.cancel();\n\n    const { scrollTarget } = this;\n    if (!scrollTarget) {\n      return;\n    }\n\n    let pid: number;\n    const { left } = scrollTarget;\n    const { top } = scrollTarget;\n    const end = () => {\n      this.cancel();\n    };\n\n    if ((left === options.left || options.left == null) && top === options.top) {\n      end();\n      return;\n    }\n\n    const duration = 200;\n    const start = +new Date();\n\n    const animate = () => {\n      if (pid !== this.pid) {\n        return;\n      }\n\n      const now = +new Date();\n      const time = Math.min(1, (now - start) / duration);\n      const eased = easing(time);\n      const opt: any = {};\n      if (options.left != null) {\n        opt.left = eased * (options.left - left) + left;\n      }\n      if (options.top != null) {\n        opt.top = eased * (options.top - top) + top;\n      }\n\n      scrollTarget.scrollTo(opt);\n\n      if (time < 1) {\n        this.pid = requestAnimationFrame(animate);\n        pid = this.pid;\n      } else {\n        end();\n      }\n    };\n\n    this.pid = requestAnimationFrame(animate);\n    pid = this.pid;\n  }\n\n  scrolling(point: { globalX: number; globalY: number }) {\n    this.cancel();\n\n    const { bounds, scale = 1 } = this.scrollable;\n    const { scrollTarget } = this;\n    if (!scrollTarget || !bounds) {\n      return;\n    }\n\n    const x = point.globalX;\n    const y = point.globalY;\n\n    const maxScrollHeight = scrollTarget.scrollHeight - bounds.height / scale;\n    const maxScrollWidth = scrollTarget.scrollWidth - bounds.width / scale;\n    let sx = scrollTarget.left;\n    let sy = scrollTarget.top;\n    let ax = 0;\n    let ay = 0;\n    if (y < bounds.top + SCROLL_ACCURACY) {\n      ay = -Math.min(Math.max(bounds.top + SCROLL_ACCURACY - y, 10), 50) / scale;\n    } else if (y > bounds.bottom - SCROLL_ACCURACY) {\n      ay = Math.min(Math.max(y + SCROLL_ACCURACY - bounds.bottom, 10), 50) / scale;\n    }\n    if (x < bounds.left + SCROLL_ACCURACY) {\n      ax = -Math.min(Math.max(bounds.top + SCROLL_ACCURACY - y, 10), 50) / scale;\n    } else if (x > bounds.right - SCROLL_ACCURACY) {\n      ax = Math.min(Math.max(x + SCROLL_ACCURACY - bounds.right, 10), 50) / scale;\n    }\n\n    if (!ax && !ay) {\n      return;\n    }\n\n    const animate = () => {\n      let scroll = false;\n      if ((ay > 0 && sy < maxScrollHeight) || (ay < 0 && sy > 0)) {\n        sy += ay;\n        sy = Math.min(Math.max(sy, 0), maxScrollHeight);\n        scroll = true;\n      }\n      if ((ax > 0 && sx < maxScrollWidth) || (ax < 0 && sx > 0)) {\n        sx += ax;\n        sx = Math.min(Math.max(sx, 0), maxScrollWidth);\n        scroll = true;\n      }\n      if (!scroll) {\n        return;\n      }\n\n      scrollTarget.scrollTo({ left: sx, top: sy });\n      this.pid = requestAnimationFrame(animate);\n    };\n\n    animate();\n  }\n\n  cancel() {\n    if (this.pid) {\n      cancelAnimationFrame(this.pid);\n    }\n    this.pid = undefined;\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/setting/index.ts",
    "content": "export * from './setting-field';\nexport * from './setting-top-entry';\nexport * from './setting-entry-type';\nexport * from './setting-prop-entry';\n"
  },
  {
    "path": "packages/designer/src/designer/setting/setting-entry-type.ts",
    "content": "import { IPublicApiSetters, IPublicModelEditor } from '@alilc/lowcode-types';\nimport { IDesigner } from '../designer';\nimport { INode } from '../../document';\nimport { ISettingField } from './setting-field';\n\nexport interface ISettingEntry {\n  readonly designer: IDesigner | undefined;\n\n  readonly id: string;\n\n  /**\n   * 同样类型的节点\n   */\n  readonly isSameComponent: boolean;\n\n  /**\n   * 一个\n   */\n  readonly isSingle: boolean;\n\n  /**\n   * 多个\n   */\n  readonly isMultiple: boolean;\n\n  /**\n   * 编辑器引用\n   */\n  readonly editor: IPublicModelEditor;\n\n  readonly setters: IPublicApiSetters;\n\n  /**\n   * 取得子项\n   */\n  get: (propName: string | number) => ISettingField | null;\n\n  readonly nodes: INode[];\n\n  // @todo 补充 node 定义\n  /**\n   * 获取 node 中的第一项\n   */\n  getNode: () => any;\n}\n"
  },
  {
    "path": "packages/designer/src/designer/setting/setting-field.ts",
    "content": "import { ReactNode } from 'react';\nimport {\n  IPublicTypeTitleContent,\n  IPublicTypeSetterType,\n  IPublicTypeDynamicSetter,\n  IPublicTypeFieldExtraProps,\n  IPublicTypeFieldConfig,\n  IPublicTypeCustomView,\n  IPublicTypeDisposable,\n  IPublicModelSettingField,\n  IBaseModelSettingField,\n} from '@alilc/lowcode-types';\nimport type {\n  IPublicTypeSetValueOptions,\n} from '@alilc/lowcode-types';\nimport { Transducer } from './utils';\nimport { ISettingPropEntry, SettingPropEntry } from './setting-prop-entry';\nimport { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core';\nimport { cloneDeep, isCustomView, isDynamicSetter, isJSExpression } from '@alilc/lowcode-utils';\nimport { ISettingTopEntry } from './setting-top-entry';\nimport { IComponentMeta, INode } from '@alilc/lowcode-designer';\n\nfunction getSettingFieldCollectorKey(parent: ISettingTopEntry | ISettingField, config: IPublicTypeFieldConfig) {\n  let cur = parent;\n  const path = [config.name];\n  while (cur !== parent.top) {\n    if (cur instanceof SettingField && cur.type !== 'group') {\n      path.unshift(cur.name);\n    }\n    cur = cur.parent;\n  }\n  return path.join('.');\n}\n\nexport interface ISettingField extends ISettingPropEntry, Omit<IBaseModelSettingField<\n  ISettingTopEntry,\n  ISettingField,\n  IComponentMeta,\n  INode\n>, 'setValue' | 'key' | 'node'> {\n  readonly isSettingField: true;\n\n  readonly isRequired: boolean;\n\n  readonly isGroup: boolean;\n\n  extraProps: IPublicTypeFieldExtraProps;\n\n  get items(): Array<ISettingField | IPublicTypeCustomView>;\n\n  get title(): string | ReactNode | undefined;\n\n  get setter(): IPublicTypeSetterType | null;\n\n  get expanded(): boolean;\n\n  get valueState(): number;\n\n  setExpanded(value: boolean): void;\n\n  purge(): void;\n\n  setValue(\n    val: any,\n    isHotValue?: boolean,\n    force?: boolean,\n    extraOptions?: IPublicTypeSetValueOptions,\n  ): void;\n\n  clearValue(): void;\n\n  valueChange(options: IPublicTypeSetValueOptions): void;\n\n  createField(config: IPublicTypeFieldConfig): ISettingField;\n\n  onEffect(action: () => void): IPublicTypeDisposable;\n\n  internalToShellField(): IPublicModelSettingField;\n}\n\nexport class SettingField extends SettingPropEntry implements ISettingField {\n  readonly isSettingField = true;\n\n  readonly isRequired: boolean;\n\n  readonly transducer: Transducer;\n\n  private _config: IPublicTypeFieldConfig;\n\n  private hotValue: any;\n\n  parent: ISettingTopEntry | ISettingField;\n\n  extraProps: IPublicTypeFieldExtraProps;\n\n  // ==== dynamic properties ====\n  private _title?: IPublicTypeTitleContent;\n\n  get title() {\n    return (\n      this._title || (typeof this.name === 'number' ? `${intl('Item')} ${this.name}` : this.name)\n    );\n  }\n\n  private _setter?: IPublicTypeSetterType | IPublicTypeDynamicSetter;\n\n  @obx.ref private _expanded = true;\n\n  private _items: Array<ISettingField | IPublicTypeCustomView> = [];\n\n  constructor(\n    parent: ISettingTopEntry | ISettingField,\n    config: IPublicTypeFieldConfig,\n    private settingFieldCollector?: (name: string | number, field: ISettingField) => void,\n  ) {\n    super(parent, config.name, config.type);\n    makeObservable(this);\n    const { title, items, setter, extraProps, ...rest } = config;\n    this.parent = parent;\n    this._config = config;\n    this._title = title;\n    this._setter = setter;\n    this.extraProps = {\n      ...rest,\n      ...extraProps,\n    };\n    this.isRequired = config.isRequired || (setter as any)?.isRequired;\n    this._expanded = !extraProps?.defaultCollapsed;\n\n    // initial items\n    if (items && items.length > 0) {\n      this.initItems(items, settingFieldCollector);\n    }\n    if (this.type !== 'group' && settingFieldCollector && config.name) {\n      settingFieldCollector(getSettingFieldCollectorKey(parent, config), this);\n    }\n\n    // compatiable old config\n    this.transducer = new Transducer(this, { setter });\n  }\n\n  @computed get setter(): IPublicTypeSetterType | null {\n    if (!this._setter) {\n      return null;\n    }\n    if (isDynamicSetter(this._setter)) {\n      return untracked(() => {\n        const shellThis = this.internalToShellField();\n        return (this._setter as IPublicTypeDynamicSetter)?.call(shellThis, shellThis!);\n      });\n    }\n    return this._setter;\n  }\n\n  get expanded(): boolean {\n    return this._expanded;\n  }\n\n  setExpanded(value: boolean) {\n    this._expanded = value;\n  }\n\n  get items(): Array<ISettingField | IPublicTypeCustomView> {\n    return this._items;\n  }\n\n  get config(): IPublicTypeFieldConfig {\n    return this._config;\n  }\n\n  private initItems(\n    items: Array<IPublicTypeFieldConfig | IPublicTypeCustomView>,\n    settingFieldCollector?: {\n      (name: string | number, field: ISettingField): void;\n      (name: string, field: ISettingField): void;\n    },\n  ) {\n    this._items = items.map((item) => {\n      if (isCustomView(item)) {\n        return item;\n      }\n      return new SettingField(this, item, settingFieldCollector);\n    });\n  }\n\n  private disposeItems() {\n    this._items.forEach((item) => isSettingField(item) && item.purge());\n    this._items = [];\n  }\n\n  // 创建子配置项，通常用于 object/array 类型数据\n  createField(config: IPublicTypeFieldConfig): ISettingField {\n    this.settingFieldCollector?.(getSettingFieldCollectorKey(this.parent, config), this);\n    return new SettingField(this, config, this.settingFieldCollector);\n  }\n\n  purge() {\n    this.disposeItems();\n  }\n\n  // ======= compatibles for vision ======\n\n  getConfig<K extends keyof IPublicTypeFieldConfig>(\n    configName?: K,\n  ): IPublicTypeFieldConfig[K] | IPublicTypeFieldConfig {\n    if (configName) {\n      return this.config[configName];\n    }\n    return this._config;\n  }\n\n  getItems(\n    filter?: (item: ISettingField | IPublicTypeCustomView) => boolean,\n  ): Array<ISettingField | IPublicTypeCustomView> {\n    return this._items.filter((item) => {\n      if (filter) {\n        return filter(item);\n      }\n      return true;\n    });\n  }\n\n  @action\n  setValue(\n    val: any,\n    isHotValue?: boolean,\n    force?: boolean,\n    extraOptions?: IPublicTypeSetValueOptions,\n  ) {\n    if (isHotValue) {\n      this.setHotValue(val, extraOptions);\n      return;\n    }\n    super.setValue(val, false, false, extraOptions);\n  }\n\n  getHotValue(): any {\n    if (this.hotValue) {\n      return this.hotValue;\n    }\n    // avoid View modify\n    let v = cloneDeep(this.getMockOrValue());\n    if (v == null) {\n      v = this.extraProps.defaultValue;\n    }\n    return this.transducer.toHot(v);\n  }\n\n  /* istanbul ignore next */\n  @action\n  setMiniAppDataSourceValue(data: any, options?: any) {\n    this.hotValue = data;\n    const v = this.transducer.toNative(data);\n    this.setValue(v, false, false, options);\n    // dirty fix list setter\n    if (Array.isArray(data) && data[0] && data[0].__sid__) {\n      return;\n    }\n\n    this.valueChange();\n  }\n\n  @action\n  setHotValue(data: any, options?: IPublicTypeSetValueOptions) {\n    this.hotValue = data;\n    const value = this.transducer.toNative(data);\n    if (options) {\n      options.fromSetHotValue = true;\n    } else {\n      options = { fromSetHotValue: true };\n    }\n    if (this.isUseVariable()) {\n      const oldValue = this.getValue();\n      if (isJSExpression(value)) {\n        this.setValue(\n          {\n            type: 'JSExpression',\n            value: value.value,\n            mock: oldValue.mock,\n          },\n          false,\n          false,\n          options,\n        );\n      } else {\n        this.setValue(\n          {\n            type: 'JSExpression',\n            value: oldValue.value,\n            mock: value,\n          },\n          false,\n          false,\n          options,\n        );\n      }\n    } else {\n      this.setValue(value, false, false, options);\n    }\n\n    // dirty fix list setter\n    if (Array.isArray(data) && data[0] && data[0].__sid__) {\n      return;\n    }\n\n    this.valueChange(options);\n  }\n\n  onEffect(action: () => void): IPublicTypeDisposable {\n    return this.designer!.autorun(action, true);\n  }\n\n  internalToShellField() {\n    return this.designer!.shellModelFactory.createSettingField(this);\n  }\n}\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isSettingField(obj: any): obj is ISettingField {\n  return obj && obj.isSettingField;\n}\n"
  },
  {
    "path": "packages/designer/src/designer/setting/setting-prop-entry.ts",
    "content": "import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { GlobalEvent, IPublicApiSetters, IPublicModelEditor, IPublicModelSettingField, IPublicTypeFieldExtraProps, IPublicTypeSetValueOptions } from '@alilc/lowcode-types';\nimport { uniqueId, isJSExpression } from '@alilc/lowcode-utils';\nimport { ISettingEntry } from './setting-entry-type';\nimport { INode } from '../../document';\nimport type { IComponentMeta } from '../../component-meta';\nimport { IDesigner } from '../designer';\nimport { ISettingTopEntry } from './setting-top-entry';\nimport { ISettingField, isSettingField } from './setting-field';\n\nexport interface ISettingPropEntry extends ISettingEntry {\n  readonly isGroup: boolean;\n\n  get props(): ISettingTopEntry;\n\n  get name(): string | number | undefined;\n\n  valueChange(options: IPublicTypeSetValueOptions): void;\n\n  getKey(): string | number | undefined;\n\n  setKey(key: string | number): void;\n\n  getDefaultValue(): any;\n\n  setUseVariable(flag: boolean): void;\n\n  getProps(): ISettingTopEntry;\n\n  isUseVariable(): boolean;\n\n  getMockOrValue(): any;\n\n  remove(): void;\n\n  setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions): void;\n\n  internalToShellField(): IPublicModelSettingField;\n}\n\nexport class SettingPropEntry implements ISettingPropEntry {\n  // === static properties ===\n  readonly editor: IPublicModelEditor;\n\n  readonly isSameComponent: boolean;\n\n  readonly isMultiple: boolean;\n\n  readonly isSingle: boolean;\n\n  readonly setters: IPublicApiSetters;\n\n  readonly nodes: INode[];\n\n  readonly componentMeta: IComponentMeta | null;\n\n  readonly designer: IDesigner | undefined;\n\n  readonly top: ISettingTopEntry;\n\n  readonly isGroup: boolean;\n\n  readonly type: 'field' | 'group';\n\n  readonly id = uniqueId('entry');\n\n  readonly emitter: IEventBus = createModuleEventBus('SettingPropEntry');\n\n  // ==== dynamic properties ====\n  @obx.ref private _name: string | number | undefined;\n\n  get name() {\n    return this._name;\n  }\n\n  @computed get path() {\n    const path = this.parent.path.slice();\n    if (this.type === 'field' && this.name?.toString()) {\n      path.push(this.name);\n    }\n    return path;\n  }\n\n  extraProps: IPublicTypeFieldExtraProps = {};\n\n  constructor(readonly parent: ISettingTopEntry | ISettingField, name: string | number | undefined, type?: 'field' | 'group') {\n    makeObservable(this);\n    if (type == null) {\n      const c = typeof name === 'string' ? name.slice(0, 1) : '';\n      if (c === '#') {\n        this.type = 'group';\n      } else {\n        this.type = 'field';\n      }\n    } else {\n      this.type = type;\n    }\n    // initial self properties\n    this._name = name;\n    this.isGroup = this.type === 'group';\n\n    // copy parent static properties\n    this.editor = parent.editor;\n    this.nodes = parent.nodes;\n    this.setters = parent.setters;\n    this.componentMeta = parent.componentMeta;\n    this.isSameComponent = parent.isSameComponent;\n    this.isMultiple = parent.isMultiple;\n    this.isSingle = parent.isSingle;\n    this.designer = parent.designer;\n    this.top = parent.top;\n  }\n\n  getId() {\n    return this.id;\n  }\n\n  setKey(key: string | number) {\n    if (this.type !== 'field') {\n      return;\n    }\n    const propName = this.path.join('.');\n    let l = this.nodes.length;\n    while (l-- > 0) {\n      this.nodes[l].getProp(propName, true)!.key = key;\n    }\n    this._name = key;\n  }\n\n  getKey() {\n    return this._name;\n  }\n\n  remove() {\n    if (this.type !== 'field') {\n      return;\n    }\n    const propName = this.path.join('.');\n    let l = this.nodes.length;\n    while (l-- > 0) {\n      this.nodes[l].getProp(propName)?.remove();\n    }\n  }\n\n  // ====== 当前属性读写 =====\n\n  /**\n   * 判断当前属性值是否一致\n   * -1 多种值\n   * 0 无值\n   * 1 类似值，比如数组长度一样\n   * 2 单一植\n   */\n  /* istanbul ignore next */\n  @computed get valueState(): number {\n    return runInAction(() => {\n      if (this.type !== 'field') {\n        const { getValue } = this.extraProps;\n        return getValue\n          ? getValue(this.internalToShellField()!, undefined) === undefined\n            ? 0\n            : 1\n          : 0;\n      }\n      if (this.nodes.length === 1) {\n        return 2;\n      }\n      const propName = this.path.join('.');\n      const first = this.nodes[0].getProp(propName)!;\n      let l = this.nodes.length;\n      let state = 2;\n      while (--l > 0) {\n        const next = this.nodes[l].getProp(propName, false);\n        const s = first.compare(next);\n        if (s > 1) {\n          return -1;\n        }\n        if (s === 1) {\n          state = 1;\n        }\n      }\n      if (state === 2 && first.isUnset()) {\n        return 0;\n      }\n      return state;\n    });\n  }\n\n  /**\n   * 获取当前属性值\n   */\n  getValue(): any {\n    let val: any;\n    if (this.type === 'field' && this.name?.toString()) {\n      val = this.parent.getPropValue(this.name);\n    }\n    const { getValue } = this.extraProps;\n    try {\n      return getValue ? getValue(this.internalToShellField()!, val) : val;\n    } catch (e) {\n      console.warn(e);\n      return val;\n    }\n  }\n\n  /**\n   * 设置当前属性值\n   */\n  setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) {\n    const oldValue = this.getValue();\n    if (this.type === 'field') {\n      this.name?.toString() && this.parent.setPropValue(this.name, val);\n    }\n\n    const { setValue } = this.extraProps;\n    if (setValue && !extraOptions?.disableMutator) {\n      try {\n        setValue(this.internalToShellField()!, val);\n      } catch (e) {\n        /* istanbul ignore next */\n        console.warn(e);\n      }\n    }\n    this.notifyValueChange(oldValue, val);\n    // 如果 fromSetHotValue，那么在 setHotValue 中已经调用过 valueChange 了\n    if (!extraOptions?.fromSetHotValue) {\n      this.valueChange(extraOptions);\n    }\n  }\n\n  /**\n   * 清除已设置的值\n   */\n  clearValue() {\n    if (this.type === 'field') {\n      this.name?.toString() && this.parent.clearPropValue(this.name);\n    }\n    const { setValue } = this.extraProps;\n    if (setValue) {\n      try {\n        setValue(this.internalToShellField()!, undefined);\n      } catch (e) {\n        /* istanbul ignore next */\n        console.warn(e);\n      }\n    }\n  }\n\n  /**\n   * 获取子项\n   */\n  get(propName: string | number) {\n    const path = this.path.concat(propName).join('.');\n    return this.top.get(path);\n  }\n\n  /**\n   * 设置子级属性值\n   */\n  setPropValue(propName: string | number, value: any) {\n    const path = this.path.concat(propName).join('.');\n    this.top.setPropValue(path, value);\n  }\n\n  /**\n   * 清除已设置值\n   */\n  clearPropValue(propName: string | number) {\n    const path = this.path.concat(propName).join('.');\n    this.top.clearPropValue(path);\n  }\n\n  /**\n   * 获取子级属性值\n   */\n  getPropValue(propName: string | number): any {\n    return this.top.getPropValue(this.path.concat(propName).join('.'));\n  }\n\n  /**\n   * 获取顶层附属属性值\n   */\n  getExtraPropValue(propName: string) {\n    return this.top.getExtraPropValue(propName);\n  }\n\n  /**\n   * 设置顶层附属属性值\n   */\n  setExtraPropValue(propName: string, value: any) {\n    this.top.setExtraPropValue(propName, value);\n  }\n\n  // ======= compatibles for vision ======\n  getNode() {\n    return this.nodes[0];\n  }\n\n  getName(): string {\n    return this.path.join('.');\n  }\n\n  getProps() {\n    return this.top;\n  }\n\n  // add settingfield props\n  get props() {\n    return this.top;\n  }\n\n  onValueChange(func: () => any) {\n    this.emitter.on('valuechange', func);\n\n    return () => {\n      this.emitter.removeListener('valuechange', func);\n    };\n  }\n\n  /**\n   * @deprecated\n   */\n  valueChange(options: IPublicTypeSetValueOptions = {}) {\n    this.emitter.emit('valuechange', options);\n\n    if (this.parent && isSettingField(this.parent)) {\n      this.parent.valueChange(options);\n    }\n  }\n\n  notifyValueChange(oldValue: any, newValue: any) {\n    this.editor.eventBus.emit(GlobalEvent.Node.Prop.Change, {\n      node: this.getNode(),\n      prop: this,\n      oldValue,\n      newValue,\n    });\n  }\n\n  getDefaultValue() {\n    return this.extraProps.defaultValue;\n  }\n\n  isIgnore() {\n    return false;\n  }\n\n  getVariableValue() {\n    const v = this.getValue();\n    if (isJSExpression(v)) {\n      return v.value;\n    }\n    return '';\n  }\n\n  setVariableValue(value: string) {\n    const v = this.getValue();\n    this.setValue({\n      type: 'JSExpression',\n      value,\n      mock: isJSExpression(v) ? v.mock : v,\n    });\n  }\n\n  setUseVariable(flag: boolean) {\n    if (this.isUseVariable() === flag) {\n      return;\n    }\n    const v = this.getValue();\n    if (this.isUseVariable()) {\n      this.setValue(v.mock);\n    } else {\n      this.setValue({\n        type: 'JSExpression',\n        value: '',\n        mock: v,\n      });\n    }\n  }\n\n  isUseVariable() {\n    return isJSExpression(this.getValue());\n  }\n\n  get useVariable() {\n    return this.isUseVariable();\n  }\n\n  getMockOrValue() {\n    const v = this.getValue();\n    if (isJSExpression(v)) {\n      return v.mock;\n    }\n    return v;\n  }\n\n  internalToShellField(): IPublicModelSettingField {\n    return this.designer!.shellModelFactory.createSettingField(this);\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/designer/setting/setting-top-entry.ts",
    "content": "import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry, IPublicApiSetters } from '@alilc/lowcode-types';\nimport { isCustomView } from '@alilc/lowcode-utils';\nimport { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { ISettingEntry } from './setting-entry-type';\nimport { ISettingField, SettingField } from './setting-field';\nimport { INode } from '../../document';\nimport type { IComponentMeta } from '../../component-meta';\nimport { IDesigner } from '../designer';\n\nfunction generateSessionId(nodes: INode[]) {\n  return nodes\n    .map((node) => node.id)\n    .sort()\n    .join(',');\n}\n\nexport interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopEntry<\n  INode,\n  ISettingField\n> {\n  readonly top: ISettingTopEntry;\n\n  readonly parent: ISettingTopEntry;\n\n  readonly path: never[];\n\n  items: Array<ISettingField | IPublicTypeCustomView>;\n\n  componentMeta: IComponentMeta | null;\n\n  purge(): void;\n\n  getExtraPropValue(propName: string): void;\n\n  setExtraPropValue(propName: string, value: any): void;\n}\n\nexport class SettingTopEntry implements ISettingTopEntry {\n  private emitter: IEventBus = createModuleEventBus('SettingTopEntry');\n\n  private _items: Array<SettingField | IPublicTypeCustomView> = [];\n\n  private _componentMeta: IComponentMeta | null = null;\n\n  private _isSame = true;\n\n  private _settingFieldMap: { [prop: string]: ISettingField } = {};\n\n  readonly path = [];\n\n  readonly top = this;\n\n  readonly parent = this;\n\n  get componentMeta() {\n    return this._componentMeta;\n  }\n\n  get items() {\n    return this._items;\n  }\n\n  /**\n   * 同样的\n   */\n  get isSameComponent(): boolean {\n    return this._isSame;\n  }\n\n  /**\n   * 一个\n   */\n  get isSingle(): boolean {\n    return this.nodes.length === 1;\n  }\n\n  get isLocked(): boolean {\n    return this.first.isLocked;\n  }\n\n  /**\n   * 多个\n   */\n  get isMultiple(): boolean {\n    return this.nodes.length > 1;\n  }\n\n  readonly id: string;\n\n  readonly first: INode;\n\n  readonly designer: IDesigner | undefined;\n\n  readonly setters: IPublicApiSetters;\n\n  disposeFunctions: any[] = [];\n\n  constructor(readonly editor: IPublicModelEditor, readonly nodes: INode[]) {\n    if (!Array.isArray(nodes) || nodes.length < 1) {\n      throw new ReferenceError('nodes should not be empty');\n    }\n    this.id = generateSessionId(nodes);\n    this.first = nodes[0];\n    this.designer = this.first.document?.designer;\n    this.setters = editor.get('setters') as IPublicApiSetters;\n\n    // setups\n    this.setupComponentMeta();\n\n    // clear fields\n    this.setupItems();\n\n    this.disposeFunctions.push(this.setupEvents());\n  }\n\n  private setupComponentMeta() {\n    // todo: enhance compile a temp configure.compiled\n    const { first } = this;\n    const meta = first.componentMeta;\n    const l = this.nodes.length;\n    let theSame = true;\n    for (let i = 1; i < l; i++) {\n      const other = this.nodes[i];\n      if (other.componentMeta !== meta) {\n        theSame = false;\n        break;\n      }\n    }\n    if (theSame) {\n      this._isSame = true;\n      this._componentMeta = meta;\n    } else {\n      this._isSame = false;\n      this._componentMeta = null;\n    }\n  }\n\n  private setupItems() {\n    if (this.componentMeta) {\n      const settingFieldMap: { [prop: string]: ISettingField } = {};\n      const settingFieldCollector = (name: string | number, field: ISettingField) => {\n        settingFieldMap[name] = field;\n      };\n      this._items = this.componentMeta.configure.map((item) => {\n        if (isCustomView(item)) {\n          return item;\n        }\n        return new SettingField(this, item as any, settingFieldCollector);\n      });\n      this._settingFieldMap = settingFieldMap;\n    }\n  }\n\n  private setupEvents() {\n    return this.componentMeta?.onMetadataChange(() => {\n      this.setupItems();\n    });\n  }\n\n  /**\n   * 获取当前属性值\n   */\n  @computed getValue(): any {\n    return this.first?.propsData;\n  }\n\n  /**\n   * 设置当前属性值\n   */\n  setValue(val: any) {\n    this.setProps(val);\n    // TODO: emit value change\n  }\n\n  /**\n   * 获取子项\n   */\n  get(propName: string | number): ISettingField | null {\n    if (!propName) return null;\n    return this._settingFieldMap[propName] || (new SettingField(this, { name: propName }));\n  }\n\n  /**\n   * 设置子级属性值\n   */\n  setPropValue(propName: string | number, value: any) {\n    this.nodes.forEach((node) => {\n      node.setPropValue(propName.toString(), value);\n    });\n  }\n\n  /**\n   * 清除已设置值\n   */\n  clearPropValue(propName: string | number) {\n    this.nodes.forEach((node) => {\n      node.clearPropValue(propName.toString());\n    });\n  }\n\n  /**\n   * 获取子级属性值\n   */\n  getPropValue(propName: string | number): any {\n    return this.first.getProp(propName.toString(), true)?.getValue();\n  }\n\n  /**\n   * 获取顶层附属属性值\n   */\n  getExtraPropValue(propName: string) {\n    return this.first.getExtraProp(propName, false)?.getValue();\n  }\n\n  /**\n   * 设置顶层附属属性值\n   */\n  setExtraPropValue(propName: string, value: any) {\n    this.nodes.forEach((node) => {\n      node.getExtraProp(propName, true)?.setValue(value);\n    });\n  }\n\n  // 设置多个属性值，替换原有值\n  setProps(data: object) {\n    this.nodes.forEach((node) => {\n      node.setProps(data as any);\n    });\n  }\n\n  // 设置多个属性值，和原有值合并\n  mergeProps(data: object) {\n    this.nodes.forEach((node) => {\n      node.mergeProps(data as any);\n    });\n  }\n\n  private disposeItems() {\n    this._items.forEach((item) => isPurgeable(item) && item.purge());\n    this._items = [];\n  }\n\n  purge() {\n    this.disposeItems();\n    this._settingFieldMap = {};\n    this.emitter.removeAllListeners();\n    this.disposeFunctions.forEach(f => f());\n    this.disposeFunctions = [];\n  }\n\n  getProp(propName: string | number) {\n    return this.get(propName);\n  }\n\n  // ==== copy some Node api =====\n  getStatus() {\n\n  }\n\n  setStatus() {\n\n  }\n\n  getChildren() {\n    // this.nodes.map()\n  }\n\n  getDOMNode() {\n\n  }\n\n  getId() {\n    return this.id;\n  }\n\n  getPage() {\n    return this.first.document;\n  }\n\n  /**\n   * @deprecated\n   */\n  get node() {\n    return this.getNode();\n  }\n\n  getNode() {\n    return this.nodes[0];\n  }\n}\n\ninterface Purgeable {\n  purge(): void;\n}\nfunction isPurgeable(obj: any): obj is Purgeable {\n  return obj && obj.purge;\n}\n"
  },
  {
    "path": "packages/designer/src/designer/setting/utils.ts",
    "content": "// all this file for polyfill vision logic\nimport { isValidElement } from 'react';\nimport { IPublicTypeFieldConfig, IPublicTypeSetterConfig } from '@alilc/lowcode-types';\nimport { isSetterConfig, isDynamicSetter } from '@alilc/lowcode-utils';\nimport { ISettingField } from './setting-field';\n\nfunction getHotterFromSetter(setter) {\n  return setter && (setter.Hotter || (setter.type && setter.type.Hotter)) || []; // eslint-disable-line\n}\n\nfunction getTransducerFromSetter(setter) {\n  return (\n    (setter &&\n      (setter.transducer ||\n        setter.Transducer ||\n        (setter.type && (setter.type.transducer || setter.type.Transducer)))) ||\n    null\n  ); // eslint-disable-line\n}\n\nfunction combineTransducer(transducer, arr, context) {\n  if (!transducer && Array.isArray(arr)) {\n    const [toHot, toNative] = arr;\n    transducer = { toHot, toNative };\n  }\n\n  return {\n    toHot: (transducer && transducer.toHot || (x => x)).bind(context), // eslint-disable-line\n    toNative: (transducer && transducer.toNative || (x => x)).bind(context), // eslint-disable-line\n  };\n}\n\nexport class Transducer {\n  setterTransducer: any;\n\n  context: any;\n\n  constructor(context: ISettingField, config: { setter: IPublicTypeFieldConfig['setter'] }) {\n    let { setter } = config;\n\n    // 1. validElement\n    // 2. IPublicTypeSetterConfig\n    // 3. IPublicTypeSetterConfig[]\n    if (Array.isArray(setter)) {\n      setter = setter[0];\n    } else if (isValidElement(setter) && setter.type.displayName === 'MixedSetter') {\n      setter = setter.props?.setters?.[0];\n    } else if (typeof setter === 'object' && setter.componentName === 'MixedSetter') {\n      setter = Array.isArray(setter?.props?.setters) && setter.props.setters[0];\n    }\n\n    /**\n     * 两种方式标识是 FC 而不是动态 setter\n     * 1. 物料描述里面 setter 的配置，显式设置为 false\n     * 2. registerSetter 注册 setter 时显式设置为 false\n     */\n\n    let isDynamic = true;\n\n    if (isSetterConfig(setter)) {\n      const { componentName, isDynamic: dynamicFlag } = setter as IPublicTypeSetterConfig;\n      setter = componentName;\n      isDynamic = dynamicFlag !== false;\n    }\n    if (typeof setter === 'string') {\n      const { component, isDynamic: dynamicFlag } = context.setters.getSetter(setter) || {};\n      setter = component;\n      // 如果在物料配置中声明了，在 registerSetter 没有声明，取物料配置中的声明\n      isDynamic = dynamicFlag === undefined ? isDynamic : dynamicFlag !== false;\n    }\n    if (isDynamicSetter(setter) && isDynamic) {\n      try {\n        setter = setter.call(context.internalToShellField(), context.internalToShellField());\n      } catch (e) { console.error(e); }\n    }\n\n    this.setterTransducer = combineTransducer(getTransducerFromSetter(setter), getHotterFromSetter(setter), context);\n    this.context = context;\n  }\n\n  toHot(data) {\n    return this.setterTransducer.toHot(data);\n  }\n\n  toNative(data) {\n    return this.setterTransducer.toNative(data);\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/document/document-model.ts",
    "content": "import {\n  makeObservable,\n  obx,\n  engineConfig,\n  action,\n  runWithGlobalEventOff,\n  wrapWithEventSwitch,\n  createModuleEventBus,\n  IEventBus,\n} from '@alilc/lowcode-editor-core';\nimport {\n  IPublicTypeNodeData,\n  IPublicTypeNodeSchema,\n  IPublicTypePageSchema,\n  IPublicTypeComponentsMap,\n  IPublicTypeDragNodeObject,\n  IPublicTypeDragNodeDataObject,\n  IPublicModelDocumentModel,\n  IPublicEnumTransformStage,\n  IPublicTypeOnChangeOptions,\n  IPublicTypeDisposable,\n} from '@alilc/lowcode-types';\nimport type {\n  IPublicTypeRootSchema,\n} from '@alilc/lowcode-types';\nimport type {\n  IDropLocation,\n} from '@alilc/lowcode-designer';\nimport {\n  uniqueId,\n  isPlainObject,\n  compatStage,\n  isJSExpression,\n  isDOMText,\n  isNodeSchema,\n  isDragNodeObject,\n  isDragNodeDataObject,\n  isNode,\n} from '@alilc/lowcode-utils';\nimport { IProject } from '../project';\nimport { ISimulatorHost } from '../simulator';\nimport type { IComponentMeta } from '../component-meta';\nimport { IDesigner, IHistory } from '../designer';\nimport { insertChildren, insertChild, IRootNode } from './node/node';\nimport type { INode } from './node/node';\nimport { Selection, ISelection } from './selection';\nimport { History } from './history';\nimport { IModalNodesManager, ModalNodesManager, Node } from './node';\nimport { EDITOR_EVENT } from '../types';\n\nexport type GetDataType<T, NodeType> = T extends undefined\n  ? NodeType extends {\n    schema: infer R;\n  }\n  ? R\n  : any\n  : T;\n\nexport interface IDocumentModel extends Omit<IPublicModelDocumentModel<\n  ISelection,\n  IHistory,\n  INode,\n  IDropLocation,\n  IModalNodesManager,\n  IProject\n>,\n  'detecting' |\n  'checkNesting' |\n  'getNodeById' |\n  // 以下属性在内部的 document 中不存在\n  'exportSchema' |\n  'importSchema' |\n  'onAddNode' |\n  'onRemoveNode' |\n  'onChangeDetecting' |\n  'onChangeSelection' |\n  'onChangeNodeProp' |\n  'onImportSchema' |\n  'isDetectingNode' |\n  'onFocusNodeChanged' |\n  'onDropLocationChanged'\n> {\n\n  readonly designer: IDesigner;\n\n  selection: ISelection;\n\n  get rootNode(): INode | null;\n\n  get simulator(): ISimulatorHost | null;\n\n  get active(): boolean;\n\n  get nodesMap(): Map<string, INode>;\n\n  /**\n   * 是否为非激活状态\n   */\n  get suspensed(): boolean;\n\n  get fileName(): string;\n\n  get currentRoot(): INode | null;\n\n  isBlank(): boolean;\n\n  /**\n   * 根据 id 获取节点\n   */\n  getNode(id: string): INode | null;\n\n  getRoot(): INode | null;\n\n  getHistory(): IHistory;\n\n  checkNesting(\n    dropTarget: INode,\n    dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject,\n  ): boolean;\n\n  getNodeCount(): number;\n\n  nextId(possibleId: string | undefined): string;\n\n  import(schema: IPublicTypeRootSchema, checkId?: boolean): void;\n\n  export(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined;\n\n  onNodeCreate(func: (node: INode) => void): IPublicTypeDisposable;\n\n  onNodeDestroy(func: (node: INode) => void): IPublicTypeDisposable;\n\n  onChangeNodeVisible(fn: (node: INode, visible: boolean) => void): IPublicTypeDisposable;\n\n  addWillPurge(node: INode): void;\n\n  removeWillPurge(node: INode): void;\n\n  getComponentMeta(componentName: string): IComponentMeta;\n\n  insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean): INode[];\n\n  open(): IDocumentModel;\n\n  remove(): void;\n\n  suspense(): void;\n\n  close(): void;\n\n  unlinkNode(node: INode): void;\n\n  destroyNode(node: INode): void;\n}\n\nexport class DocumentModel implements IDocumentModel {\n  /**\n   * 根节点 类型有：Page/Component/Block\n   */\n  rootNode: IRootNode | null;\n\n  /**\n   * 文档编号\n   */\n  id: string = uniqueId('doc');\n\n  /**\n   * 选区控制\n   */\n  readonly selection: ISelection = new Selection(this);\n\n  /**\n   * 操作记录控制\n   */\n  readonly history: IHistory;\n\n  /**\n   * 模态节点管理\n   */\n  modalNodesManager: IModalNodesManager;\n\n  private _nodesMap = new Map<string, INode>();\n\n  readonly project: IProject;\n\n  readonly designer: IDesigner;\n\n  @obx.shallow private nodes = new Set<INode>();\n\n  private seqId = 0;\n\n  private emitter: IEventBus;\n\n  private rootNodeVisitorMap: { [visitorName: string]: any } = {};\n\n  /**\n   * @deprecated\n   */\n  private _addons: Array<{ name: string; exportData: any }> = [];\n\n  /**\n   * 模拟器\n   */\n  get simulator(): ISimulatorHost | null {\n    return this.project.simulator;\n  }\n\n  get nodesMap(): Map<string, INode> {\n    return this._nodesMap;\n  }\n\n  get fileName(): string {\n    return this.rootNode?.getExtraProp('fileName', false)?.getAsString() || this.id;\n  }\n\n  set fileName(fileName: string) {\n    this.rootNode?.getExtraProp('fileName', true)?.setValue(fileName);\n  }\n\n  get focusNode(): INode | null {\n    if (this._drillDownNode) {\n      return this._drillDownNode;\n    }\n    const selector = engineConfig.get('focusNodeSelector');\n    if (selector && typeof selector === 'function') {\n      return selector(this.rootNode!);\n    }\n    return this.rootNode;\n  }\n\n  @obx.ref private _drillDownNode: INode | null = null;\n\n  private _modalNode?: INode;\n\n  private _blank?: boolean;\n\n  private inited = false;\n\n  @obx.shallow private willPurgeSpace: INode[] = [];\n\n  get modalNode() {\n    return this._modalNode;\n  }\n\n  get currentRoot() {\n    return this.modalNode || this.focusNode;\n  }\n\n  @obx.shallow private activeNodes?: INode[];\n\n  @obx.ref private _dropLocation: IDropLocation | null = null;\n\n  set dropLocation(loc: IDropLocation | null) {\n    this._dropLocation = loc;\n    // pub event\n    this.designer.editor.eventBus.emit(\n      'document.dropLocation.changed',\n      { document: this, location: loc },\n    );\n  }\n\n  /**\n   * 投放插入位置标记\n   */\n  get dropLocation() {\n    return this._dropLocation;\n  }\n\n  /**\n   * 导出 schema 数据\n   */\n  get schema(): IPublicTypeRootSchema {\n    return this.rootNode?.schema as any;\n  }\n\n  @obx.ref private _opened = false;\n\n  @obx.ref private _suspensed = false;\n\n  /**\n   * 是否为非激活状态\n   */\n  get suspensed(): boolean {\n    return this._suspensed || !this._opened;\n  }\n\n  /**\n   * 与 suspensed 相反，是否为激活状态，这个函数可能用的更多一点\n   */\n  get active(): boolean {\n    return !this._suspensed;\n  }\n\n  /**\n   * @deprecated 兼容\n   */\n  get actived(): boolean {\n    return this.active;\n  }\n\n  /**\n   * 是否打开\n   */\n  get opened() {\n    return this._opened;\n  }\n\n  get root() {\n    return this.rootNode;\n  }\n\n  constructor(project: IProject, schema?: IPublicTypeRootSchema) {\n    makeObservable(this);\n    this.project = project;\n    this.designer = this.project?.designer;\n    this.emitter = createModuleEventBus('DocumentModel');\n\n    if (!schema) {\n      this._blank = true;\n    }\n\n    // 兼容 vision\n    this.id = project.getSchema()?.id || this.id;\n\n    this.rootNode = this.createNode(\n      schema || {\n        componentName: 'Page',\n        id: 'root',\n        fileName: '',\n      },\n    );\n\n    this.history = new History(\n      () => this.export(IPublicEnumTransformStage.Serilize),\n      (schema) => {\n        this.import(schema as IPublicTypeRootSchema, true);\n        this.simulator?.rerender();\n      },\n      this,\n    );\n\n    this.setupListenActiveNodes();\n    this.modalNodesManager = new ModalNodesManager(this);\n    this.inited = true;\n  }\n\n  drillDown(node: INode | null) {\n    this._drillDownNode = node;\n  }\n\n  onChangeNodeVisible(fn: (node: INode, visible: boolean) => void): IPublicTypeDisposable {\n    this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn);\n\n    return () => {\n      this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn);\n    };\n  }\n\n  onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<INode>) => void): IPublicTypeDisposable {\n    this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn);\n\n    return () => {\n      this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn);\n    };\n  }\n\n  addWillPurge(node: INode) {\n    this.willPurgeSpace.push(node);\n  }\n\n  removeWillPurge(node: INode) {\n    const i = this.willPurgeSpace.indexOf(node);\n    if (i > -1) {\n      this.willPurgeSpace.splice(i, 1);\n    }\n  }\n\n  isBlank() {\n    return !!(this._blank && !this.isModified());\n  }\n\n  /**\n   * 生成唯一 id\n   */\n  nextId(possibleId: string | undefined): string {\n    let id = possibleId;\n    while (!id || this.nodesMap.get(id)) {\n      id = `node_${(String(this.id).slice(-10) + (++this.seqId).toString(36)).toLocaleLowerCase()}`;\n    }\n\n    return id;\n  }\n\n  /**\n   * 根据 id 获取节点\n   */\n  getNode(id: string): INode | null {\n    return this._nodesMap.get(id) || null;\n  }\n\n  /**\n   * 根据 id 获取节点\n   */\n  getNodeCount(): number {\n    return this._nodesMap?.size;\n  }\n\n  /**\n   * 是否存在节点\n   */\n  hasNode(id: string): boolean {\n    const node = this.getNode(id);\n    return node ? !node.isPurged : false;\n  }\n\n  onMountNode(fn: (payload: { node: INode }) => void) {\n    this.designer.editor.eventBus.on('node.add', fn as any);\n\n    return () => {\n      this.designer.editor.eventBus.off('node.add', fn as any);\n    };\n  }\n\n  /**\n   * 根据 schema 创建一个节点\n   */\n  @action\n  createNode<T extends INode = INode, C = undefined>(data: GetDataType<C, T>): T {\n    let schema: any;\n    if (isDOMText(data) || isJSExpression(data)) {\n      schema = {\n        componentName: 'Leaf',\n        children: data,\n      };\n    } else {\n      schema = data;\n    }\n\n    let node: INode | null = null;\n    if (this.hasNode(schema?.id)) {\n      schema.id = null;\n    }\n    /* istanbul ignore next */\n    if (schema.id) {\n      node = this.getNode(schema.id);\n      // TODO: 底下这几段代码似乎永远都进不去\n      if (node && node.componentName === schema.componentName) {\n        if (node.parent) {\n          node.internalSetParent(null, false);\n          // will move to another position\n          // todo: this.activeNodes?.push(node);\n        }\n        node.import(schema, true);\n      } else if (node) {\n        node = null;\n      }\n    }\n    if (!node) {\n      node = new Node(this, schema);\n      // will add\n      // todo: this.activeNodes?.push(node);\n    }\n\n    this._nodesMap.set(node.id, node);\n    this.nodes.add(node);\n\n    this.emitter.emit('nodecreate', node);\n    return node as any;\n  }\n\n  public destroyNode(node: INode) {\n    this.emitter.emit('nodedestroy', node);\n  }\n\n  /**\n   * 插入一个节点\n   */\n  insertNode(parent: INode, thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean): INode | null {\n    return insertChild(parent, thing, at, copy);\n  }\n\n  /**\n   * 插入多个节点\n   */\n  insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean) {\n    return insertChildren(parent, thing, at, copy);\n  }\n\n  /**\n   * 移除一个节点\n   */\n  removeNode(idOrNode: string | INode) {\n    let id: string;\n    let node: INode | null = null;\n    if (typeof idOrNode === 'string') {\n      id = idOrNode;\n      node = this.getNode(id);\n    } else if (idOrNode.id) {\n      id = idOrNode.id;\n      node = this.getNode(id);\n    }\n    if (!node) {\n      return;\n    }\n    this.internalRemoveAndPurgeNode(node, true);\n  }\n\n  /**\n   * 内部方法，请勿调用\n   */\n  internalRemoveAndPurgeNode(node: INode, useMutator = false) {\n    if (!this.nodes.has(node)) {\n      return;\n    }\n    node.remove(useMutator);\n  }\n\n  unlinkNode(node: INode) {\n    this.nodes.delete(node);\n    this._nodesMap.delete(node.id);\n  }\n\n  /**\n   * 包裹当前选区中的节点\n   */\n  wrapWith(schema: IPublicTypeNodeSchema): INode | null {\n    const nodes = this.selection.getTopNodes();\n    if (nodes.length < 1) {\n      return null;\n    }\n    const wrapper = this.createNode(schema);\n    if (wrapper.isParental()) {\n      const first = nodes[0];\n      // TODO: check nesting rules x 2\n      insertChild(first.parent!, wrapper, first.index);\n      insertChildren(wrapper, nodes);\n      this.selection.select(wrapper.id);\n      return wrapper;\n    }\n\n    this.removeNode(wrapper);\n    return null;\n  }\n\n  @action\n  import(schema: IPublicTypeRootSchema, checkId = false) {\n    const drillDownNodeId = this._drillDownNode?.id;\n    runWithGlobalEventOff(() => {\n      // TODO: 暂时用饱和式删除，原因是 Slot 节点并不是树节点，无法正常递归删除\n      this.nodes.forEach(node => {\n        if (node.isRoot()) return;\n        this.internalRemoveAndPurgeNode(node, true);\n      });\n      this.rootNode?.import(schema as any, checkId);\n      this.modalNodesManager = new ModalNodesManager(this);\n      // todo: select added and active track added\n      if (drillDownNodeId) {\n        this.drillDown(this.getNode(drillDownNodeId));\n      }\n    });\n  }\n\n  export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize): IPublicTypeRootSchema | undefined {\n    stage = compatStage(stage);\n    // 置顶只作用于 Page 的第一级子节点，目前还用不到里层的置顶；如果后面有需要可以考虑将这段写到 node-children 中的 export\n    const currentSchema = this.rootNode?.export<IPublicTypeRootSchema>(stage);\n    if (Array.isArray(currentSchema?.children) && currentSchema?.children?.length && currentSchema?.children?.length > 0) {\n      const FixedTopNodeIndex = currentSchema?.children\n        .filter(i => isPlainObject(i))\n        .findIndex((i => (i as IPublicTypeNodeSchema).props?.__isTopFixed__));\n      if (FixedTopNodeIndex > 0) {\n        const FixedTopNode = currentSchema?.children.splice(FixedTopNodeIndex, 1);\n        currentSchema?.children.unshift(FixedTopNode[0]);\n      }\n    }\n    return currentSchema;\n  }\n\n  /**\n   * 导出节点数据\n   */\n  getNodeSchema(id: string): IPublicTypeNodeData | null {\n    const node = this.getNode(id);\n    if (node) {\n      return node.schema;\n    }\n    return null;\n  }\n\n  /**\n   * 是否已修改\n   */\n  isModified(): boolean {\n    return this.history.isSavePoint();\n  }\n\n  // FIXME: does needed?\n  getComponent(componentName: string): any {\n    return this.simulator!.getComponent(componentName);\n  }\n\n  getComponentMeta(componentName: string): IComponentMeta {\n    return this.designer.getComponentMeta(\n      componentName,\n      () => this.simulator?.generateComponentMetadata(componentName) || null,\n    );\n  }\n\n  /**\n   * 切换激活，只有打开的才能激活\n   * 不激活，打开之后切换到另外一个时发生，比如 tab 视图，切换到另外一个标签页\n   */\n  private setSuspense(flag: boolean) {\n    if (!this._opened && !flag) {\n      return;\n    }\n    this._suspensed = flag;\n    this.simulator?.setSuspense(flag);\n    if (!flag) {\n      this.project.checkExclusive(this);\n    }\n  }\n\n  suspense() {\n    this.setSuspense(true);\n  }\n\n  activate() {\n    this.setSuspense(false);\n  }\n\n  /**\n   * 打开，已载入，默认建立时就打开状态，除非手动关闭\n   */\n  open(): DocumentModel {\n    const originState = this._opened;\n    this._opened = true;\n    if (originState === false) {\n      this.designer.postEvent('document-open', this);\n    }\n    if (this._suspensed) {\n      this.setSuspense(false);\n    } else {\n      this.project.checkExclusive(this);\n    }\n    return this;\n  }\n\n  /**\n   * 关闭，相当于 sleep，仍然缓存，停止一切响应，如果有发生的变更没被保存，仍然需要去取数据保存\n   */\n  close(): void {\n    this.setSuspense(true);\n    this._opened = false;\n  }\n\n  /**\n   * 从项目中移除\n   */\n  remove() {\n    this.designer.postEvent('document.remove', { id: this.id });\n    this.purge();\n    this.project.removeDocument(this);\n  }\n\n  purge() {\n    this.rootNode?.purge();\n    this.nodes.clear();\n    this._nodesMap.clear();\n    this.rootNode = null;\n  }\n\n  checkNesting(\n    dropTarget: INode,\n    dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject,\n  ): boolean {\n    let items: Array<INode | IPublicTypeNodeSchema>;\n    if (isDragNodeDataObject(dragObject)) {\n      items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];\n    } else if (isDragNodeObject<INode>(dragObject)) {\n      items = dragObject.nodes;\n    } else if (isNode<INode>(dragObject) || isNodeSchema(dragObject)) {\n      items = [dragObject];\n    } else {\n      console.warn('the dragObject is not in the correct type, dragObject:', dragObject);\n      return true;\n    }\n    return items.every((item) => this.checkNestingDown(dropTarget, item) && this.checkNestingUp(dropTarget, item));\n  }\n\n  /**\n   * @deprecated since version 1.0.16.\n   * Will be deleted in version 2.0.0.\n   * Use checkNesting method instead.\n   */\n  checkDropTarget(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject): boolean {\n    let items: Array<INode | IPublicTypeNodeSchema>;\n    if (isDragNodeDataObject(dragObject)) {\n      items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];\n    } else if (isDragNodeObject<INode>(dragObject)) {\n      items = dragObject.nodes;\n    } else {\n      return false;\n    }\n    return items.every((item) => this.checkNestingUp(dropTarget, item));\n  }\n\n  /**\n   * 检查对象对父级的要求，涉及配置 parentWhitelist\n   */\n  checkNestingUp(parent: INode, obj: IPublicTypeNodeSchema | INode): boolean {\n    if (isNode(obj) || isNodeSchema(obj)) {\n      const config = isNode(obj) ? obj.componentMeta : this.getComponentMeta(obj.componentName);\n      if (config) {\n        return config.checkNestingUp(obj, parent);\n      }\n    }\n\n    return true;\n  }\n\n  /**\n   * 检查投放位置对子级的要求，涉及配置 childWhitelist\n   */\n  checkNestingDown(parent: INode, obj: IPublicTypeNodeSchema | INode): boolean {\n    const config = parent.componentMeta;\n    return config.checkNestingDown(parent, obj);\n  }\n\n  // ======= compatibles for vision\n  getRoot() {\n    return this.rootNode;\n  }\n\n  // add toData\n  toData(extraComps?: string[]) {\n    const node = this.export(IPublicEnumTransformStage.Save);\n    const data = {\n      componentsMap: this.getComponentsMap(extraComps),\n      utils: this.getUtilsMap(),\n      componentsTree: [node],\n    };\n    return data;\n  }\n\n  getHistory(): IHistory {\n    return this.history;\n  }\n\n  /**\n   * @deprecated\n   */\n  /* istanbul ignore next */\n  getAddonData(name: string) {\n    const addon = this._addons.find((item) => item.name === name);\n    if (addon) {\n      return addon.exportData();\n    }\n  }\n\n  /**\n   * @deprecated\n  */\n  /* istanbul ignore next */\n  exportAddonData() {\n    const addons: {\n      [key: string]: any;\n    } = {};\n    this._addons.forEach((addon) => {\n      const data = addon.exportData();\n      if (data === null) {\n        delete addons[addon.name];\n      } else {\n        addons[addon.name] = data;\n      }\n    });\n    return addons;\n  }\n\n  /**\n   * @deprecated\n   */\n  /* istanbul ignore next */\n  registerAddon(name: string, exportData: any) {\n    if (['id', 'params', 'layout'].indexOf(name) > -1) {\n      throw new Error('addon name cannot be id, params, layout');\n    }\n    const i = this._addons.findIndex((item) => item.name === name);\n    if (i > -1) {\n      this._addons.splice(i, 1);\n    }\n    this._addons.push({\n      exportData,\n      name,\n    });\n  }\n\n  /* istanbul ignore next */\n  acceptRootNodeVisitor(\n    visitorName = 'default',\n    visitorFn: (node: IRootNode) => any,\n  ) {\n    let visitorResult = {};\n    if (!visitorName) {\n      /* eslint-disable-next-line no-console */\n      console.warn('Invalid or empty RootNodeVisitor name.');\n    }\n    try {\n      if (this.rootNode) {\n        visitorResult = visitorFn.call(this, this.rootNode);\n        this.rootNodeVisitorMap[visitorName] = visitorResult;\n      }\n    } catch (e) {\n      console.error('RootNodeVisitor is not valid.');\n      console.error(e);\n    }\n    return visitorResult;\n  }\n\n  /* istanbul ignore next */\n  getRootNodeVisitor(name: string) {\n    return this.rootNodeVisitorMap[name];\n  }\n\n  getComponentsMap(extraComps?: string[]) {\n    const componentsMap: IPublicTypeComponentsMap = [];\n    // 组件去重\n    const exsitingMap: { [componentName: string]: boolean } = {};\n    for (const node of this._nodesMap.values()) {\n      const { componentName } = node || {};\n      if (componentName === 'Slot') continue;\n      if (!exsitingMap[componentName]) {\n        exsitingMap[componentName] = true;\n        if (node.componentMeta?.npm?.package) {\n          componentsMap.push({\n            ...node.componentMeta.npm,\n            componentName,\n          });\n        } else {\n          componentsMap.push({\n            devMode: 'lowCode',\n            componentName,\n          });\n        }\n      }\n    }\n    // 合并外界传入的自定义渲染的组件\n    if (Array.isArray(extraComps)) {\n      extraComps.forEach((componentName) => {\n        if (componentName && !exsitingMap[componentName]) {\n          const meta = this.getComponentMeta(componentName);\n          if (meta?.npm?.package) {\n            componentsMap.push({\n              ...meta?.npm,\n              componentName,\n            });\n          } else {\n            componentsMap.push({\n              devMode: 'lowCode',\n              componentName,\n            });\n          }\n        }\n      });\n    }\n    return componentsMap;\n  }\n\n  /**\n   * 获取 schema 中的 utils 节点，当前版本不判断页面中使用了哪些 utils，直接返回资产包中所有的 utils\n   * @returns\n   */\n  getUtilsMap() {\n    return this.designer?.editor?.get('assets')?.utils?.map((item: any) => ({\n      name: item.name,\n      type: item.type || 'npm',\n      // TODO 当前只有 npm 类型，content 直接设置为 item.npm，有 function 类型之后需要处理\n      content: item.npm,\n    }));\n  }\n\n  onNodeCreate(func: (node: INode) => void) {\n    const wrappedFunc = wrapWithEventSwitch(func);\n    this.emitter.on('nodecreate', wrappedFunc);\n    return () => {\n      this.emitter.removeListener('nodecreate', wrappedFunc);\n    };\n  }\n\n  onNodeDestroy(func: (node: INode) => void) {\n    const wrappedFunc = wrapWithEventSwitch(func);\n    this.emitter.on('nodedestroy', wrappedFunc);\n    return () => {\n      this.emitter.removeListener('nodedestroy', wrappedFunc);\n    };\n  }\n\n  /**\n   * @deprecated\n   */\n  refresh() {\n    console.warn('refresh method is deprecated');\n  }\n\n  /**\n   * @deprecated\n   */\n  onRefresh(/* func: () => void */) {\n    console.warn('onRefresh method is deprecated');\n  }\n\n  onReady(fn: (...args: any[]) => void) {\n    this.designer.editor.eventBus.on('document-open', fn);\n    return () => {\n      this.designer.editor.eventBus.off('document-open', fn);\n    };\n  }\n\n  private setupListenActiveNodes() {\n    // todo:\n  }\n}\n\nexport function isDocumentModel(obj: any): obj is IDocumentModel {\n  return obj && obj.rootNode;\n}\n\nexport function isPageSchema(obj: any): obj is IPublicTypePageSchema {\n  return obj?.componentName === 'Page';\n}\n"
  },
  {
    "path": "packages/designer/src/document/document-view.tsx",
    "content": "import { Component } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { DocumentModel, IDocumentModel } from './document-model';\nimport { BuiltinSimulatorHostView } from '../builtin-simulator';\n\n@observer\nexport class DocumentView extends Component<{ document: IDocumentModel }> {\n  render() {\n    const { document } = this.props;\n    const { simulatorProps } = document;\n    const Simulator = document.designer.simulatorComponent || BuiltinSimulatorHostView;\n    return (\n      <div\n        className={classNames('lc-document', {\n          'lc-document-hidden': document.suspensed,\n        })}\n      >\n        {/* 这一层将来做缩放用途 */}\n        <div className=\"lc-simulator-shell\">\n          <Simulator {...simulatorProps} />\n        </div>\n        <DocumentInfoView document={document} />\n      </div>\n    );\n  }\n}\n\nclass DocumentInfoView extends Component<{ document: IDocumentModel }> {\n  render() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/document/history.ts",
    "content": "import { reaction, untracked, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { IPublicTypeNodeSchema, IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types';\nimport { Logger } from '@alilc/lowcode-utils';\nimport { IDocumentModel } from '../designer';\n\nconst logger = new Logger({ level: 'warn', bizName: 'history' });\n\nexport interface Serialization<K = IPublicTypeNodeSchema, T = string> {\n  serialize(data: K): T;\n  unserialize(data: T): K;\n}\n\nexport interface IHistory extends IPublicModelHistory {\n  onStateChange(func: () => any): IPublicTypeDisposable;\n}\n\nexport class History<T = IPublicTypeNodeSchema> implements IHistory {\n  private session: Session;\n\n  private records: Session[];\n\n  private point = 0;\n\n  private emitter: IEventBus = createModuleEventBus('History');\n\n  private asleep = false;\n\n  private currentSerialization: Serialization<T, string> = {\n    serialize(data: T): string {\n      return JSON.stringify(data);\n    },\n    unserialize(data: string) {\n      return JSON.parse(data);\n    },\n  };\n\n  get hotData() {\n    return this.session.data;\n  }\n\n  private timeGap: number = 1000;\n\n  constructor(\n      dataFn: () => T | null,\n      private redoer: (data: T) => void,\n      private document?: IDocumentModel,\n    ) {\n    this.session = new Session(0, null, this.timeGap);\n    this.records = [this.session];\n\n    reaction((): any => {\n      return dataFn();\n    }, (data: T) => {\n      if (this.asleep) return;\n      untracked(() => {\n        const log = this.currentSerialization.serialize(data);\n\n        // do not record unchanged data\n        if (this.session.data === log) {\n          return;\n        }\n\n        if (this.session.isActive()) {\n          this.session.log(log);\n        } else {\n          this.session.end();\n          const lastState = this.getState();\n          const cursor = this.session.cursor + 1;\n          const session = new Session(cursor, log, this.timeGap);\n          this.session = session;\n          this.records.splice(cursor, this.records.length - cursor, session);\n          const currentState = this.getState();\n          if (currentState !== lastState) {\n            this.emitter.emit('statechange', currentState);\n          }\n        }\n      });\n    }, { fireImmediately: true });\n  }\n\n  setSerialization(serialization: Serialization<T, string>) {\n    this.currentSerialization = serialization;\n  }\n\n  isSavePoint(): boolean {\n    return this.point !== this.session.cursor;\n  }\n\n  private sleep() {\n    this.asleep = true;\n  }\n\n  private wakeup() {\n    this.asleep = false;\n  }\n\n  go(originalCursor: number) {\n    this.session.end();\n\n    let cursor = originalCursor;\n    cursor = +cursor;\n    if (cursor < 0) {\n      cursor = 0;\n    } else if (cursor >= this.records.length) {\n      cursor = this.records.length - 1;\n    }\n\n    const currentCursor = this.session.cursor;\n    if (cursor === currentCursor) {\n      return;\n    }\n\n    const session = this.records[cursor];\n    const hotData = session.data;\n\n    this.sleep();\n    try {\n      this.redoer(this.currentSerialization.unserialize(hotData));\n      this.emitter.emit('cursor', hotData);\n    } catch (e) /* istanbul ignore next */ {\n      logger.error(e);\n    }\n\n    this.wakeup();\n    this.session = session;\n\n    this.emitter.emit('statechange', this.getState());\n  }\n\n  back() {\n    if (!this.session) {\n      return;\n    }\n    const cursor = this.session.cursor - 1;\n    this.go(cursor);\n    const editor = this.document?.designer.editor;\n    if (!editor) {\n      return;\n    }\n    editor.eventBus.emit('history.back', cursor);\n  }\n\n  forward() {\n    if (!this.session) {\n      return;\n    }\n    const cursor = this.session.cursor + 1;\n    this.go(cursor);\n    const editor = this.document?.designer.editor;\n    if (!editor) {\n      return;\n    }\n    editor.eventBus.emit('history.forward', cursor);\n  }\n\n  savePoint() {\n    if (!this.session) {\n      return;\n    }\n    this.session.end();\n    this.point = this.session.cursor;\n    this.emitter.emit('statechange', this.getState());\n  }\n\n  /**\n   *  |    1     |     1    |    1     |\n   *  | -------- | -------- | -------- |\n   *  | modified | redoable | undoable |\n   */\n  getState(): number {\n    const { cursor } = this.session;\n    let state = 7;\n    // undoable ?\n    if (cursor <= 0) {\n      state -= 1;\n    }\n    // redoable ?\n    if (cursor >= this.records.length - 1) {\n      state -= 2;\n    }\n    // modified ?\n    if (this.point === cursor) {\n      state -= 4;\n    }\n    return state;\n  }\n\n  /**\n   * 监听 state 变更事件\n   * @param func\n   * @returns\n   */\n  onChangeState(func: () => any): IPublicTypeDisposable {\n    return this.onStateChange(func);\n  }\n\n  onStateChange(func: () => any): IPublicTypeDisposable {\n    this.emitter.on('statechange', func);\n    return () => {\n      this.emitter.removeListener('statechange', func);\n    };\n  }\n\n  /**\n   * 监听历史记录游标位置变更事件\n   * @param func\n   * @returns\n   */\n  onChangeCursor(func: () => any): IPublicTypeDisposable {\n    return this.onCursor(func);\n  }\n\n  onCursor(func: () => any): () => void {\n    this.emitter.on('cursor', func);\n    return () => {\n      this.emitter.removeListener('cursor', func);\n    };\n  }\n\n  destroy() {\n    this.emitter.removeAllListeners();\n    this.records = [];\n  }\n\n  /**\n   *\n   * @deprecated\n   * @returns\n   * @memberof History\n   */\n  isModified() {\n    return this.isSavePoint();\n  }\n}\n\nexport class Session {\n  private _data: any;\n\n  private activeTimer: any;\n\n  get data() {\n    return this._data;\n  }\n\n  constructor(readonly cursor: number, data: any, private timeGap: number = 1000) {\n    this.setTimer();\n    this.log(data);\n  }\n\n  log(data: any) {\n    if (!this.isActive()) {\n      return;\n    }\n    this._data = data;\n    this.setTimer();\n  }\n\n  isActive() {\n    return this.activeTimer != null;\n  }\n\n  end() {\n    if (this.isActive()) {\n      this.clearTimer();\n    }\n  }\n\n  private setTimer() {\n    this.clearTimer();\n    this.activeTimer = setTimeout(() => this.end(), this.timeGap);\n  }\n\n  private clearTimer() {\n    if (this.activeTimer) {\n      clearTimeout(this.activeTimer);\n    }\n    this.activeTimer = null;\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/document/index.ts",
    "content": "export * from './document-model';\nexport * from './node';\nexport * from './selection';\nexport * from './history';\n"
  },
  {
    "path": "packages/designer/src/document/node/exclusive-group.ts",
    "content": "import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';\nimport { uniqueId } from '@alilc/lowcode-utils';\nimport { IPublicTypeTitleContent, IPublicModelExclusiveGroup } from '@alilc/lowcode-types';\nimport type { INode } from './node';\nimport { intl } from '../../locale';\n\nexport interface IExclusiveGroup extends IPublicModelExclusiveGroup<INode> {\n  readonly name: string;\n\n  get index(): number | undefined;\n\n  remove(node: INode): void;\n\n  add(node: INode): void;\n\n  isVisible(node: INode): boolean;\n\n  get length(): number;\n\n  get visibleNode(): INode;\n}\n\n// modals assoc x-hide value, initial: check is Modal, yes will put it in modals, cross levels\n// if-else-if assoc conditionGroup value, should be the same level,\n// and siblings, need renderEngine support\nexport class ExclusiveGroup implements IExclusiveGroup {\n  readonly isExclusiveGroup = true;\n\n  readonly id = uniqueId('exclusive');\n\n  readonly title: IPublicTypeTitleContent;\n\n  @obx.shallow readonly children: INode[] = [];\n\n  @obx private visibleIndex = 0;\n\n  @computed get document() {\n    return this.visibleNode.document;\n  }\n\n  @computed get zLevel() {\n    return this.visibleNode.zLevel;\n  }\n\n  @computed get length() {\n    return this.children.length;\n  }\n\n  @computed get visibleNode(): INode {\n    return this.children[this.visibleIndex];\n  }\n\n  @computed get firstNode(): INode {\n    return this.children[0]!;\n  }\n\n  get index() {\n    return this.firstNode.index;\n  }\n\n  constructor(readonly name: string, title?: IPublicTypeTitleContent) {\n    makeObservable(this);\n    this.title = title || {\n      type: 'i18n',\n      intl: intl('Condition Group'),\n    };\n  }\n\n  add(node: INode) {\n    if (node.nextSibling && node.nextSibling.conditionGroup?.id === this.id) {\n      const i = this.children.indexOf(node.nextSibling);\n      this.children.splice(i, 0, node);\n    } else {\n      this.children.push(node);\n    }\n  }\n\n  remove(node: INode) {\n    const i = this.children.indexOf(node);\n    if (i > -1) {\n      this.children.splice(i, 1);\n      if (this.visibleIndex > i) {\n        this.visibleIndex -= 1;\n      } else if (this.visibleIndex >= this.children.length) {\n        this.visibleIndex = this.children.length - 1;\n      }\n    }\n  }\n\n  setVisible(node: INode) {\n    const i = this.children.indexOf(node);\n    if (i > -1) {\n      this.visibleIndex = i;\n    }\n  }\n\n  isVisible(node: INode) {\n    const i = this.children.indexOf(node);\n    return i === this.visibleIndex;\n  }\n}\n\nexport function isExclusiveGroup(obj: any): obj is ExclusiveGroup {\n  return obj && obj.isExclusiveGroup;\n}\n"
  },
  {
    "path": "packages/designer/src/document/node/index.ts",
    "content": "export * from './exclusive-group';\nexport * from './node';\nexport * from './node-children';\nexport * from './props/prop';\nexport * from './props/props';\nexport * from './transform-stage';\nexport * from './modal-nodes-manager';\n"
  },
  {
    "path": "packages/designer/src/document/node/modal-nodes-manager.ts",
    "content": "import { INode } from './node';\nimport { DocumentModel } from '../document-model';\nimport { IPublicModelModalNodesManager } from '@alilc/lowcode-types';\nimport { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';\n\nexport function getModalNodes(node: INode) {\n  if (!node) return [];\n  let nodes: any = [];\n  if (node.componentMeta.isModal) {\n    nodes.push(node);\n  }\n  const { children } = node;\n  if (children) {\n    children.forEach((child) => {\n      nodes = nodes.concat(getModalNodes(child));\n    });\n  }\n  return nodes;\n}\n\nexport interface IModalNodesManager extends IPublicModelModalNodesManager<INode> {\n}\n\nexport class ModalNodesManager implements IModalNodesManager {\n  willDestroy: any;\n\n  private page: DocumentModel;\n\n  private modalNodes: INode[];\n\n  private nodeRemoveEvents: any;\n\n  private emitter: IEventBus;\n\n  constructor(page: DocumentModel) {\n    this.page = page;\n    this.emitter = createModuleEventBus('ModalNodesManager');\n    this.nodeRemoveEvents = {};\n    this.setNodes();\n    this.hideModalNodes();\n    this.willDestroy = [\n      page.onNodeCreate((node) => this.addNode(node)),\n      page.onNodeDestroy((node) => this.removeNode(node)),\n    ];\n  }\n\n  getModalNodes(): INode[] {\n    return this.modalNodes;\n  }\n\n  getVisibleModalNode(): INode | null {\n    const visibleNode = this.getModalNodes().find((node: INode) => node.getVisible());\n    return visibleNode || null;\n  }\n\n  hideModalNodes() {\n    this.modalNodes.forEach((node: INode) => {\n      node.setVisible(false);\n    });\n  }\n\n  setVisible(node: INode) {\n    this.hideModalNodes();\n    node.setVisible(true);\n  }\n\n  setInvisible(node: INode) {\n    node.setVisible(false);\n  }\n\n  onVisibleChange(func: () => any) {\n    this.emitter.on('visibleChange', func);\n    return () => {\n      this.emitter.removeListener('visibleChange', func);\n    };\n  }\n\n  onModalNodesChange(func: () => any) {\n    this.emitter.on('modalNodesChange', func);\n    return () => {\n      this.emitter.removeListener('modalNodesChange', func);\n    };\n  }\n\n  private addNode(node: INode) {\n    if (node?.componentMeta.isModal) {\n      this.hideModalNodes();\n      this.modalNodes.push(node);\n      this.addNodeEvent(node);\n      this.emitter.emit('modalNodesChange');\n      this.emitter.emit('visibleChange');\n    }\n  }\n\n  private removeNode(node: INode) {\n    if (node.componentMeta.isModal) {\n      const index = this.modalNodes.indexOf(node);\n      if (index >= 0) {\n        this.modalNodes.splice(index, 1);\n      }\n      this.removeNodeEvent(node);\n      this.emitter.emit('modalNodesChange');\n      if (node.getVisible()) {\n        this.emitter.emit('visibleChange');\n      }\n    }\n  }\n\n  private addNodeEvent(node: INode) {\n    this.nodeRemoveEvents[node.id] =\n      node.onVisibleChange(() => {\n        this.emitter.emit('visibleChange');\n      });\n  }\n\n  private removeNodeEvent(node: INode) {\n    if (this.nodeRemoveEvents[node.id]) {\n      this.nodeRemoveEvents[node.id]();\n      delete this.nodeRemoveEvents[node.id];\n    }\n  }\n\n  setNodes() {\n    const nodes = getModalNodes(this.page.rootNode!);\n    this.modalNodes = nodes;\n    this.modalNodes.forEach((node: INode) => {\n      this.addNodeEvent(node);\n    });\n\n    this.emitter.emit('modalNodesChange');\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/document/node/node-children.ts",
    "content": "import { obx, computed, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { Node, INode } from './node';\nimport { IPublicTypeNodeData, IPublicModelNodeChildren, IPublicEnumTransformStage, IPublicTypeDisposable } from '@alilc/lowcode-types';\nimport { shallowEqual, compatStage, isNodeSchema } from '@alilc/lowcode-utils';\nimport { foreachReverse } from '../../utils/tree';\nimport { NodeRemoveOptions } from '../../types';\n\nexport interface IOnChangeOptions {\n  type: string;\n  node: Node;\n}\n\nexport interface INodeChildren extends Omit<IPublicModelNodeChildren<INode>,\n  'importSchema' |\n  'exportSchema' |\n  'isEmpty' |\n  'notEmpty'\n> {\n  children: INode[];\n\n  get owner(): INode;\n\n  get length(): number;\n\n  unlinkChild(node: INode): void;\n\n  /**\n   * 删除一个节点\n   */\n  internalDelete(\n      node: INode,\n      purge: boolean,\n      useMutator: boolean,\n      options: NodeRemoveOptions\n    ): boolean;\n\n  /**\n   * 插入一个节点，返回新长度\n   */\n  internalInsert(node: INode, at?: number | null, useMutator?: boolean): void;\n\n  import(data?: IPublicTypeNodeData | IPublicTypeNodeData[], checkId?: boolean): void;\n\n  /**\n   * 导出 schema\n   */\n  export(stage: IPublicEnumTransformStage): IPublicTypeNodeData[];\n\n  /** following methods are overriding super interface, using different param types */\n  /** overriding methods start */\n\n  forEach(fn: (item: INode, index: number) => void): void;\n\n  /**\n   * 根据索引获得节点\n   */\n  get(index: number): INode | null;\n\n  isEmpty(): boolean;\n\n  notEmpty(): boolean;\n\n  internalInitParent(): void;\n\n  onChange(fn: (info?: IOnChangeOptions) => void): IPublicTypeDisposable;\n\n  /** overriding methods end */\n}\nexport class NodeChildren implements INodeChildren {\n  @obx.shallow children: INode[];\n\n  private emitter: IEventBus = createModuleEventBus('NodeChildren');\n\n  /**\n   * 元素个数\n   */\n  @computed get size(): number {\n    return this.children.length;\n  }\n\n  get isEmptyNode(): boolean {\n    return this.size < 1;\n  }\n  get notEmptyNode(): boolean {\n    return this.size > 0;\n  }\n\n  @computed get length(): number {\n    return this.children.length;\n  }\n\n  private purged = false;\n\n  get [Symbol.toStringTag]() {\n    // 保证向前兼容性\n    return 'Array';\n  }\n\n  constructor(\n      readonly owner: INode,\n      data: IPublicTypeNodeData | IPublicTypeNodeData[],\n      options: any = {},\n    ) {\n    makeObservable(this);\n    this.children = (Array.isArray(data) ? data : [data]).filter(child => !!child).map((child) => {\n      return this.owner.document?.createNode(child, options.checkId);\n    });\n  }\n\n  internalInitParent() {\n    this.children.forEach((child) => child.internalSetParent(this.owner));\n  }\n\n  /**\n   * 导出 schema\n   */\n  export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): IPublicTypeNodeData[] {\n    stage = compatStage(stage);\n    return this.children.map((node) => {\n      const data = node.export(stage);\n      if (node.isLeafNode && IPublicEnumTransformStage.Save === stage) {\n        // FIXME: filter empty\n        return data.children as IPublicTypeNodeData;\n      }\n      return data;\n    });\n  }\n\n  import(data?: IPublicTypeNodeData | IPublicTypeNodeData[], checkId = false) {\n    data = (data ? (Array.isArray(data) ? data : [data]) : []).filter(d => !!d);\n\n    const originChildren = this.children.slice();\n    this.children.forEach((child) => child.internalSetParent(null));\n\n    const children = new Array<Node>(data.length);\n    for (let i = 0, l = data.length; i < l; i++) {\n      const child = originChildren[i];\n      const item = data[i];\n\n      let node: INode | undefined | null;\n      if (isNodeSchema(item) && !checkId && child && child.componentName === item.componentName) {\n        node = child;\n        node.import(item);\n      } else {\n        node = this.owner.document?.createNode(item, checkId);\n      }\n      children[i] = node;\n    }\n\n    this.children = children;\n    this.internalInitParent();\n    if (!shallowEqual(children, originChildren)) {\n      this.emitter.emit('change');\n    }\n  }\n\n  /**\n   * @deprecated\n   * @param nodes\n   */\n  concat(nodes: INode[]) {\n    return this.children.concat(nodes);\n  }\n\n  /**\n   *\n   */\n  isEmpty() {\n    return this.isEmptyNode;\n  }\n\n  notEmpty() {\n    return this.notEmptyNode;\n  }\n\n  /**\n   * 回收销毁\n   */\n  purge(useMutator = true) {\n    if (this.purged) {\n      return;\n    }\n    this.purged = true;\n    this.children.forEach((child) => {\n      child.purge(useMutator);\n    });\n  }\n\n  unlinkChild(node: INode) {\n    const i = this.children.map(d => d.id).indexOf(node.id);\n    if (i < 0) {\n      return false;\n    }\n    this.children.splice(i, 1);\n    this.emitter.emit('change', {\n      type: 'unlink',\n      node,\n    });\n  }\n\n  /**\n   * 删除一个节点\n   */\n  delete(node: INode): boolean {\n    return this.internalDelete(node);\n  }\n\n  /**\n   * 删除一个节点\n   */\n  internalDelete(node: INode, purge = false, useMutator = true, options: NodeRemoveOptions = {}): boolean {\n    node.internalPurgeStart();\n    if (node.isParentalNode) {\n      foreachReverse(\n        node.children,\n        (subNode: Node) => {\n          subNode.remove(useMutator, purge, options);\n        },\n        (iterable, idx) => (iterable as NodeChildren).get(idx),\n      );\n      foreachReverse(\n        node.slots,\n        (slotNode: Node) => {\n          slotNode.remove(useMutator, purge);\n        },\n        (iterable, idx) => (iterable as [])[idx],\n      );\n    }\n    // 需要在从 children 中删除 node 前记录下 index，internalSetParent 中会执行删除 (unlink) 操作\n    const i = this.children.map(d => d.id).indexOf(node.id);\n    if (purge) {\n      // should set parent null\n      node.internalSetParent(null, useMutator);\n      try {\n        node.purge();\n      } catch (err) {\n        console.error(err);\n      }\n    }\n    const { document } = node;\n    /* istanbul ignore next */\n    const editor = node.document?.designer.editor;\n    editor?.eventBus.emit('node.remove', { node, index: i });\n    document?.unlinkNode(node);\n    document?.selection.remove(node.id);\n    document?.destroyNode(node);\n    this.emitter.emit('change', {\n      type: 'delete',\n      node,\n    });\n    if (useMutator) {\n      this.reportModified(node, this.owner, {\n        type: 'remove',\n        propagated: false,\n        isSubDeleting: this.owner.isPurging,\n        removeIndex: i,\n        removeNode: node,\n      });\n    }\n    // purge 为 true 时，已在 internalSetParent 中删除了子节点\n    if (i > -1 && !purge) {\n      this.children.splice(i, 1);\n    }\n    return false;\n  }\n\n  insert(node: INode, at?: number | null): void {\n    this.internalInsert(node, at, true);\n  }\n\n  /**\n   * 插入一个节点，返回新长度\n   */\n  internalInsert(node: INode, at?: number | null, useMutator = true): void {\n    const { children } = this;\n    let index = at == null || at === -1 ? children.length : at;\n\n    const i = children.map(d => d.id).indexOf(node.id);\n\n    if (node.parent) {\n      const editor = node.document?.designer.editor;\n      editor?.eventBus.emit('node.remove.topLevel', {\n        node,\n        index: node.index,\n      });\n    }\n\n    if (i < 0) {\n      if (index < children.length) {\n        children.splice(index, 0, node);\n      } else {\n        children.push(node);\n      }\n      node.internalSetParent(this.owner, useMutator);\n    } else {\n      if (index > i) {\n        index -= 1;\n      }\n\n      if (index === i) {\n        return;\n      }\n\n      children.splice(i, 1);\n      children.splice(index, 0, node);\n    }\n\n    this.emitter.emit('change', {\n      type: 'insert',\n      node,\n    });\n    this.emitter.emit('insert', node);\n    /* istanbul ignore next */\n    const editor = node.document?.designer.editor;\n    editor?.eventBus.emit('node.add', { node });\n    if (useMutator) {\n      this.reportModified(node, this.owner, { type: 'insert' });\n    }\n\n    // check condition group\n    if (node.conditionGroup) {\n      if (\n        !(\n          // just sort at condition group\n          (\n            (node.prevSibling && node.prevSibling.conditionGroup === node.conditionGroup) ||\n            (node.nextSibling && node.nextSibling.conditionGroup === node.conditionGroup)\n          )\n        )\n      ) {\n        node.setConditionGroup(null);\n      }\n    }\n    if (node.prevSibling && node.nextSibling) {\n      const { conditionGroup } = node.prevSibling;\n      // insert at condition group\n      if (conditionGroup && conditionGroup === node.nextSibling.conditionGroup) {\n        node.setConditionGroup(conditionGroup);\n      }\n    }\n  }\n\n  /**\n   * 取得节点索引编号\n   */\n  indexOf(node: INode): number {\n    return this.children.map(d => d.id).indexOf(node.id);\n  }\n\n  /**\n   *\n   */\n  splice(start: number, deleteCount: number, node?: INode): INode[] {\n    if (node) {\n      return this.children.splice(start, deleteCount, node);\n    }\n    return this.children.splice(start, deleteCount);\n  }\n\n  /**\n   * 根据索引获得节点\n   */\n  get(index: number): INode | null {\n    return this.children.length > index ? this.children[index] : null;\n  }\n\n  /**\n   * 是否存在节点\n   */\n  has(node: INode) {\n    return this.indexOf(node) > -1;\n  }\n\n  /**\n   * 迭代器\n   */\n  [Symbol.iterator](): { next(): { value: INode } } {\n    let index = 0;\n    const { children } = this;\n    const length = children.length || 0;\n    return {\n      next() {\n        if (index < length) {\n          return {\n            value: children[index++],\n            done: false,\n          };\n        }\n        return {\n          value: undefined as any,\n          done: true,\n        };\n      },\n    };\n  }\n\n  /**\n   * 遍历\n   */\n  forEach(fn: (item: INode, index: number) => void): void {\n    this.children.forEach((child, index) => {\n      return fn(child, index);\n    });\n  }\n\n  /**\n   * 遍历\n   */\n  map<T>(fn: (item: INode, index: number) => T): T[] | null {\n    return this.children.map((child, index) => {\n      return fn(child, index);\n    });\n  }\n\n  every(fn: (item: INode, index: number) => any): boolean {\n    return this.children.every((child, index) => fn(child, index));\n  }\n\n  some(fn: (item: INode, index: number) => any): boolean {\n    return this.children.some((child, index) => fn(child, index));\n  }\n\n  filter(fn: (item: INode, index: number) => any): any {\n    return this.children.filter(fn);\n  }\n\n  find(fn: (item: INode, index: number) => boolean): INode | undefined {\n    return this.children.find(fn);\n  }\n\n  reduce(fn: (acc: any, cur: INode) => any, initialValue: any): void {\n    return this.children.reduce(fn, initialValue);\n  }\n\n  reverse() {\n    return this.children.reverse();\n  }\n\n  mergeChildren(\n    remover: (node: INode, idx: number) => boolean,\n    adder: (children: INode[]) => IPublicTypeNodeData[] | null,\n    sorter: (firstNode: INode, secondNode: INode) => number,\n  ): any {\n    let changed = false;\n    if (remover) {\n      const willRemove = this.children.filter(remover);\n      if (willRemove.length > 0) {\n        willRemove.forEach((node) => {\n          const i = this.children.map(d => d.id).indexOf(node.id);\n          if (i > -1) {\n            this.children.splice(i, 1);\n            node.remove(false);\n          }\n        });\n        changed = true;\n      }\n    }\n    if (adder) {\n      const items = adder(this.children);\n      if (items && items.length > 0) {\n        items.forEach((child: IPublicTypeNodeData) => {\n          const node: INode = this.owner.document?.createNode(child);\n          this.children.push(node);\n          node.internalSetParent(this.owner);\n          /* istanbul ignore next */\n          const editor = node.document?.designer.editor;\n          editor?.eventBus.emit('node.add', { node });\n        });\n        changed = true;\n      }\n    }\n    if (sorter) {\n      this.children = this.children.sort(sorter);\n      changed = true;\n    }\n    if (changed) {\n      this.emitter.emit('change');\n    }\n  }\n\n  onChange(fn: (info?: IOnChangeOptions) => void): IPublicTypeDisposable {\n    this.emitter.on('change', fn);\n    return () => {\n      this.emitter.removeListener('change', fn);\n    };\n  }\n\n  onInsert(fn: (node: INode) => void) {\n    this.emitter.on('insert', fn);\n    return () => {\n      this.emitter.removeListener('insert', fn);\n    };\n  }\n\n  private reportModified(node: INode, owner: INode, options = {}) {\n    if (!node) {\n      return;\n    }\n    if (node.isRootNode) {\n      return;\n    }\n    const callbacks = owner.componentMeta?.advanced.callbacks;\n    if (callbacks?.onSubtreeModified) {\n      try {\n        callbacks?.onSubtreeModified.call(\n          node.internalToShellNode(),\n          owner.internalToShellNode(),\n          options,\n        );\n      } catch (e) {\n        console.error('error when execute advanced.callbacks.onSubtreeModified', e);\n      }\n    }\n\n    if (owner.parent && !owner.parent.isRootNode) {\n      this.reportModified(node, owner.parent, { ...options, propagated: true });\n    }\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/document/node/node.ts",
    "content": "import { ReactElement } from 'react';\nimport { obx, computed, autorun, makeObservable, runInAction, wrapWithEventSwitch, action, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicTypeNodeSchema,\n  IPublicTypePropsMap,\n  IPublicTypePropsList,\n  IPublicTypeNodeData,\n  IPublicTypeI18nData,\n  IPublicTypeSlotSchema,\n  IPublicTypePageSchema,\n  IPublicTypeComponentSchema,\n  IPublicTypeCompositeValue,\n  GlobalEvent,\n  IPublicTypeComponentAction,\n  IPublicModelNode,\n  IPublicModelExclusiveGroup,\n  IPublicEnumTransformStage,\n  IPublicTypeDisposable,\n  IBaseModelNode,\n} from '@alilc/lowcode-types';\nimport { compatStage, isDOMText, isJSExpression, isNode, isNodeSchema } from '@alilc/lowcode-utils';\nimport { ISettingTopEntry } from '@alilc/lowcode-designer';\nimport { Props, getConvertedExtraKey, IProps } from './props/props';\nimport type { IDocumentModel } from '../document-model';\nimport { NodeChildren, INodeChildren } from './node-children';\nimport { IProp, Prop } from './props/prop';\nimport type { IComponentMeta } from '../../component-meta';\nimport { ExclusiveGroup, isExclusiveGroup } from './exclusive-group';\nimport type { IExclusiveGroup } from './exclusive-group';\nimport { includeSlot, removeSlot } from '../../utils/slot';\nimport { foreachReverse } from '../../utils/tree';\nimport { NodeRemoveOptions, EDITOR_EVENT } from '../../types';\n\nexport interface NodeStatus {\n  locking: boolean;\n  pseudo: boolean;\n  inPlaceEditing: boolean;\n}\n\nexport interface IBaseNode<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> extends Omit<IBaseModelNode<\n  IDocumentModel,\n  IBaseNode,\n  INodeChildren,\n  IComponentMeta,\n  ISettingTopEntry,\n  IProps,\n  IProp,\n  IExclusiveGroup\n>,\n  'isRoot' |\n  'isPage' |\n  'isComponent' |\n  'isModal' |\n  'isSlot' |\n  'isParental' |\n  'isLeaf' |\n  'settingEntry' |\n  // 在内部的 node 模型中不存在\n  'getExtraPropValue' |\n  'setExtraPropValue' |\n  'exportSchema' |\n  'visible' |\n  'importSchema' |\n  // 内外实现有差异\n  'isContainer' |\n  'isEmpty'\n> {\n  isNode: boolean;\n\n  get componentMeta(): IComponentMeta;\n\n  get settingEntry(): ISettingTopEntry;\n\n  get isPurged(): boolean;\n\n  get index(): number | undefined;\n\n  get isPurging(): boolean;\n\n  getId(): string;\n\n  getParent(): INode | null;\n\n  /**\n   * 内部方法，请勿使用\n   * @param useMutator 是否触发联动逻辑\n   */\n  internalSetParent(parent: INode | null, useMutator?: boolean): void;\n\n  setConditionGroup(grp: IPublicModelExclusiveGroup | string | null): void;\n\n  internalToShellNode(): IPublicModelNode | null;\n\n  internalPurgeStart(): void;\n\n  unlinkSlot(slotNode: INode): void;\n\n  /**\n   * 导出 schema\n   */\n  export<T = Schema>(stage: IPublicEnumTransformStage, options?: any): T;\n\n  emitPropChange(val: IPublicTypePropChangeOptions): void;\n\n  import(data: Schema, checkId?: boolean): void;\n\n  internalSetSlotFor(slotFor: Prop | null | undefined): void;\n\n  addSlot(slotNode: INode): void;\n\n  onVisibleChange(func: (flag: boolean) => any): () => void;\n\n  getSuitablePlace(node: INode, ref: any): any;\n\n  onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable | undefined;\n\n  onPropChange(func: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable;\n\n  isModal(): boolean;\n\n  isRoot(): boolean;\n\n  isPage(): boolean;\n\n  isComponent(): boolean;\n\n  isSlot(): boolean;\n\n  isParental(): boolean;\n\n  isLeaf(): boolean;\n\n  isContainer(): boolean;\n\n  isEmpty(): boolean;\n\n  remove(\n    useMutator?: boolean,\n    purge?: boolean,\n    options?: NodeRemoveOptions,\n  ): void;\n\n  didDropIn(dragment: INode): void;\n\n  didDropOut(dragment: INode): void;\n\n  purge(): void;\n\n  removeSlot(slotNode: INode): boolean;\n\n  setVisible(flag: boolean): void;\n\n  getVisible(): boolean;\n\n  getChildren(): INodeChildren | null;\n\n  clearPropValue(path: string | number): void;\n\n  setProps(props?: IPublicTypePropsMap | IPublicTypePropsList | Props | null): void;\n\n  mergeProps(props: IPublicTypePropsMap): void;\n\n  /** 是否可以选中 */\n  canSelect(): boolean;\n}\n\n/**\n * 基础节点\n *\n * [Node Properties]\n *  componentName: Page/Block/Component\n *  props\n *  children\n *\n * [Directives]\n *  loop\n *  loopArgs\n *  condition\n *  ------- addition support -----\n *  conditionGroup use for condition, for exclusive\n *  title          display on outline\n *  ignored        ignore this node will not publish to render, but will store\n *  isLocked       can not select/hover/ item on canvas and outline\n *  hidden         not visible on canvas\n *  slotArgs       like loopArgs, for slot node\n *\n * 根容器节点\n *\n * [Node Properties]\n *  componentName: Page/Block/Component\n *  props\n *  children\n *\n * [Root Container Extra Properties]\n *  fileName\n *  meta\n *  state\n *  defaultProps\n *  dataSource\n *  lifeCycles\n *  methods\n *  css\n *\n * [Directives **not used**]\n *  loop\n *  loopArgs\n *  condition\n *  ------- future support -----\n *  conditionGroup\n *  title\n *  ignored\n *  isLocked\n *  hidden\n */\nexport class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> implements IBaseNode {\n  private emitter: IEventBus;\n\n  /**\n   * 是节点实例\n   */\n  readonly isNode = true;\n\n  /**\n   * 节点 id\n   */\n  readonly id: string;\n\n  /**\n   * 节点组件类型\n   * 特殊节点：\n   *  * Page 页面\n   *  * Block 区块\n   *  * Component 组件/元件\n   *  * Fragment 碎片节点，无 props，有指令\n   *  * Leaf 文字节点 | 表达式节点，无 props，无指令？\n   *  * Slot 插槽节点，无 props，正常 children，有 slotArgs，有指令\n   */\n  readonly componentName: string;\n\n  /**\n   * 属性抽象\n   */\n  props: IProps;\n\n  protected _children?: INodeChildren;\n\n  /**\n   * @deprecated\n   */\n  private _addons: { [key: string]: { exportData: () => any; isProp: boolean } } = {};\n\n  @obx.ref private _parent: INode | null = null;\n\n  /**\n   * 父级节点\n   */\n  get parent(): INode | null {\n    return this._parent;\n  }\n\n  /**\n   * 当前节点子集\n   */\n  get children(): INodeChildren | null {\n    return this._children || null;\n  }\n\n  /**\n   * 当前节点深度\n   */\n  @computed get zLevel(): number {\n    if (this._parent) {\n      return this._parent.zLevel + 1;\n    }\n    return 0;\n  }\n\n  @computed get title(): string | IPublicTypeI18nData | ReactElement {\n    let t = this.getExtraProp('title');\n    // TODO: 暂时走不到这个分支\n    // if (!t && this.componentMeta.descriptor) {\n    //   t = this.getProp(this.componentMeta.descriptor, false);\n    // }\n    if (t) {\n      const v = t.getAsString();\n      if (v) {\n        return v;\n      }\n    }\n    return this.componentMeta.title;\n  }\n\n  get icon() {\n    return this.componentMeta.icon;\n  }\n\n  isInited = false;\n\n  _settingEntry: ISettingTopEntry;\n\n  get settingEntry(): ISettingTopEntry {\n    if (this._settingEntry) return this._settingEntry;\n    this._settingEntry = this.document.designer.createSettingEntry([this]);\n    return this._settingEntry;\n  }\n\n  private autoruns?: Array<() => void>;\n\n  private _isRGLContainer = false;\n\n  set isRGLContainer(status: boolean) {\n    this._isRGLContainer = status;\n  }\n\n  get isRGLContainer(): boolean {\n    return !!this._isRGLContainer;\n  }\n\n  set isRGLContainerNode(status: boolean) {\n    this._isRGLContainer = status;\n  }\n\n  get isRGLContainerNode(): boolean {\n    return !!this._isRGLContainer;\n  }\n\n  get isEmptyNode() {\n    return this.isEmpty();\n  }\n\n  private _slotFor?: IProp | null | undefined = null;\n\n  @obx.shallow _slots: INode[] = [];\n\n  get slots(): INode[] {\n    return this._slots;\n  }\n\n  /* istanbul ignore next */\n  @obx.ref private _conditionGroup: IExclusiveGroup | null = null;\n\n  /* istanbul ignore next */\n  get conditionGroup(): IExclusiveGroup | null {\n    return this._conditionGroup;\n  }\n\n  private purged = false;\n\n  /**\n   * 是否已销毁\n   */\n  get isPurged() {\n    return this.purged;\n  }\n\n  private purging: boolean = false;\n\n  /**\n   * 是否正在销毁\n   */\n  get isPurging() {\n    return this.purging;\n  }\n\n  @obx.shallow status: NodeStatus = {\n    inPlaceEditing: false,\n    locking: false,\n    pseudo: false,\n  };\n\n  constructor(readonly document: IDocumentModel, nodeSchema: Schema) {\n    makeObservable(this);\n    const { componentName, id, children, props, ...extras } = nodeSchema;\n    this.id = document.nextId(id);\n    this.componentName = componentName;\n    if (this.componentName === 'Leaf') {\n      this.props = new Props(this, {\n        children: isDOMText(children) || isJSExpression(children) ? children : '',\n      });\n    } else {\n      this.props = new Props(this, props, extras);\n      this._children = new NodeChildren(this as INode, this.initialChildren(children));\n      this._children.internalInitParent();\n      this.props.merge(\n        this.upgradeProps(this.initProps(props || {})),\n        this.upgradeProps(extras),\n      );\n      this.setupAutoruns();\n    }\n\n    this.initBuiltinProps();\n\n    this.isInited = true;\n    this.emitter = createModuleEventBus('Node');\n    const { editor } = this.document.designer;\n    this.onVisibleChange((visible: boolean) => {\n      editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible);\n    });\n    this.onChildrenChange((info?: { type: string; node: INode }) => {\n      editor?.eventBus.emit(EDITOR_EVENT.NODE_CHILDREN_CHANGE, {\n        type: info?.type,\n        node: this,\n      });\n    });\n  }\n\n  /**\n   * 节点初始化期间就把内置的一些 prop 初始化好，避免后续不断构造实例导致 reaction 执行多次\n   */\n  @action\n  private initBuiltinProps() {\n    this.props.has(getConvertedExtraKey('hidden')) || this.props.add(false, getConvertedExtraKey('hidden'));\n    this.props.has(getConvertedExtraKey('title')) || this.props.add('', getConvertedExtraKey('title'));\n    this.props.has(getConvertedExtraKey('isLocked')) || this.props.add(false, getConvertedExtraKey('isLocked'));\n    this.props.has(getConvertedExtraKey('condition')) || this.props.add(true, getConvertedExtraKey('condition'));\n    this.props.has(getConvertedExtraKey('conditionGroup')) || this.props.add('', getConvertedExtraKey('conditionGroup'));\n    this.props.has(getConvertedExtraKey('loop')) || this.props.add(undefined, getConvertedExtraKey('loop'));\n  }\n\n  @action\n  private initProps(props: any): any {\n    return this.document.designer.transformProps(props, this, IPublicEnumTransformStage.Init);\n  }\n\n  @action\n  private upgradeProps(props: any): any {\n    return this.document.designer.transformProps(props, this, IPublicEnumTransformStage.Upgrade);\n  }\n\n  private setupAutoruns() {\n    const { autoruns } = this.componentMeta.advanced;\n    if (!autoruns || autoruns.length < 1) {\n      return;\n    }\n    this.autoruns = autoruns.map((item) => {\n      return autorun(() => {\n        item.autorun(this.props.getNode().settingEntry.get(item.name)?.internalToShellField());\n      });\n    });\n  }\n\n  private initialChildren(children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined): IPublicTypeNodeData[] {\n    const { initialChildren } = this.componentMeta.advanced;\n\n    if (children == null) {\n      if (initialChildren) {\n        if (typeof initialChildren === 'function') {\n          return initialChildren(this.internalToShellNode()!) || [];\n        }\n        return initialChildren;\n      }\n      return [];\n    }\n\n    if (Array.isArray(children)) {\n      return children;\n    }\n\n    return [children];\n  }\n\n  isContainer(): boolean {\n    return this.isContainerNode;\n  }\n\n  get isContainerNode(): boolean {\n    return this.isParentalNode && this.componentMeta.isContainer;\n  }\n\n  isModal(): boolean {\n    return this.isModalNode;\n  }\n\n  get isModalNode(): boolean {\n    return this.componentMeta.isModal;\n  }\n\n  isRoot(): boolean {\n    return this.isRootNode;\n  }\n\n  get isRootNode(): boolean {\n    return this.document.rootNode === (this as any);\n  }\n\n  isPage(): boolean {\n    return this.isPageNode;\n  }\n\n  get isPageNode(): boolean {\n    return this.isRootNode && this.componentName === 'Page';\n  }\n\n  isComponent(): boolean {\n    return this.isComponentNode;\n  }\n\n  get isComponentNode(): boolean {\n    return this.isRootNode && this.componentName === 'Component';\n  }\n\n  isSlot(): boolean {\n    return this.isSlotNode;\n  }\n\n  get isSlotNode(): boolean {\n    return this._slotFor != null && this.componentName === 'Slot';\n  }\n\n  /**\n   * 是否一个父亲类节点\n   */\n  isParental(): boolean {\n    return this.isParentalNode;\n  }\n\n  get isParentalNode(): boolean {\n    return !this.isLeafNode;\n  }\n\n  /**\n   * 终端节点，内容一般为 文字 或者 表达式\n   */\n  isLeaf(): boolean {\n    return this.isLeafNode;\n  }\n  get isLeafNode(): boolean {\n    return this.componentName === 'Leaf';\n  }\n\n  internalSetWillPurge() {\n    this.internalSetParent(null);\n    this.document.addWillPurge(this);\n  }\n\n  didDropIn(dragment: INode) {\n    const { callbacks } = this.componentMeta.advanced;\n    if (callbacks?.onNodeAdd) {\n      const cbThis = this.internalToShellNode();\n      callbacks?.onNodeAdd.call(cbThis, dragment.internalToShellNode(), cbThis);\n    }\n    if (this._parent) {\n      this._parent.didDropIn(dragment);\n    }\n  }\n\n  didDropOut(dragment: INode) {\n    const { callbacks } = this.componentMeta.advanced;\n    if (callbacks?.onNodeRemove) {\n      const cbThis = this.internalToShellNode();\n      callbacks?.onNodeRemove.call(cbThis, dragment.internalToShellNode(), cbThis);\n    }\n    if (this._parent) {\n      this._parent.didDropOut(dragment);\n    }\n  }\n\n  /**\n   * 内部方法，请勿使用\n   * @param useMutator 是否触发联动逻辑\n   */\n  internalSetParent(parent: INode | null, useMutator = false) {\n    if (this._parent === parent) {\n      return;\n    }\n\n    // 解除老的父子关系，但不需要真的删除节点\n    if (this._parent) {\n      if (this.isSlot()) {\n        this._parent.unlinkSlot(this);\n      } else {\n        this._parent.children?.unlinkChild(this);\n      }\n    }\n    if (useMutator) {\n      this._parent?.didDropOut(this);\n    }\n    if (parent) {\n      // 建立新的父子关系，尤其注意：对于 parent 为 null 的场景，不会赋值，因为 subtreeModified 等事件可能需要知道该 node 被删除前的父子关系\n      this._parent = parent;\n      this.document.removeWillPurge(this);\n      /* istanbul ignore next */\n      if (!this.conditionGroup) {\n        // initial conditionGroup\n        const grp = this.getExtraProp('conditionGroup', false)?.getAsString();\n        if (grp) {\n          this.setConditionGroup(grp);\n        }\n      }\n\n      if (useMutator) {\n        parent.didDropIn(this);\n      }\n    }\n  }\n\n  internalSetSlotFor(slotFor: Prop | null | undefined) {\n    this._slotFor = slotFor;\n  }\n\n  internalToShellNode(): IPublicModelNode | null {\n    return this.document.designer.shellModelFactory.createNode(this);\n  }\n\n  /**\n   * 关联属性\n   */\n  get slotFor(): IProp | null | undefined {\n    return this._slotFor;\n  }\n\n  /**\n   * 移除当前节点\n   */\n  remove(\n    useMutator = true,\n    purge = true,\n    options: NodeRemoveOptions = { suppressRemoveEvent: false },\n  ) {\n    if (this.parent) {\n      if (!options.suppressRemoveEvent) {\n        this.document.designer.editor?.eventBus.emit('node.remove.topLevel', {\n          node: this,\n          index: this.parent?.children?.indexOf(this),\n        });\n      }\n      if (this.isSlot()) {\n        this.parent.removeSlot(this);\n        this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true });\n      } else {\n        this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true });\n      }\n    }\n  }\n\n  /**\n   * 锁住当前节点\n   */\n  lock(flag = true) {\n    this.setExtraProp('isLocked', flag);\n  }\n\n  /**\n   * 获取当前节点的锁定状态\n   */\n  get isLocked(): boolean {\n    return !!this.getExtraProp('isLocked')?.getValue();\n  }\n\n  canSelect(): boolean {\n    const onSelectHook = this.componentMeta?.advanced?.callbacks?.onSelectHook;\n    const canSelect = typeof onSelectHook === 'function' ? onSelectHook(this.internalToShellNode()!) : true;\n    return canSelect;\n  }\n\n  /**\n   * 选择当前节点\n   */\n  select() {\n    this.document.selection.select(this.id);\n  }\n\n  /**\n   * 悬停高亮\n   */\n  hover(flag = true) {\n    if (flag) {\n      this.document.designer.detecting.capture(this);\n    } else {\n      this.document.designer.detecting.release(this);\n    }\n  }\n\n  /**\n   * 节点组件描述\n   */\n  @computed get componentMeta(): IComponentMeta {\n    return this.document.getComponentMeta(this.componentName);\n  }\n\n  @computed get propsData(): IPublicTypePropsMap | IPublicTypePropsList | null {\n    if (!this.isParental() || this.componentName === 'Fragment') {\n      return null;\n    }\n    return this.props.export(IPublicEnumTransformStage.Serilize).props || null;\n  }\n\n  hasSlots() {\n    return this._slots.length > 0;\n  }\n\n  /* istanbul ignore next */\n  setConditionGroup(grp: IPublicModelExclusiveGroup | string | null) {\n    let _grp: IExclusiveGroup | null = null;\n    if (!grp) {\n      this.getExtraProp('conditionGroup', false)?.remove();\n      if (this._conditionGroup) {\n        this._conditionGroup.remove(this);\n        this._conditionGroup = null;\n      }\n      return;\n    }\n    if (!isExclusiveGroup(grp)) {\n      if (this.prevSibling?.conditionGroup?.name === grp) {\n        _grp = this.prevSibling.conditionGroup;\n      } else if (this.nextSibling?.conditionGroup?.name === grp) {\n        _grp = this.nextSibling.conditionGroup;\n      } else if (typeof grp === 'string') {\n        _grp = new ExclusiveGroup(grp);\n      }\n    }\n    if (_grp && this._conditionGroup !== _grp) {\n      this.getExtraProp('conditionGroup', true)?.setValue(_grp.name);\n      if (this._conditionGroup) {\n        this._conditionGroup.remove(this);\n      }\n      this._conditionGroup = _grp;\n      _grp?.add(this);\n    }\n  }\n\n  /* istanbul ignore next */\n  isConditionalVisible(): boolean | undefined {\n    return this._conditionGroup?.isVisible(this);\n  }\n\n  /* istanbul ignore next */\n  setConditionalVisible() {\n    this._conditionGroup?.setVisible(this);\n  }\n\n  hasCondition() {\n    const v = this.getExtraProp('condition', false)?.getValue();\n    return v != null && v !== '' && v !== true;\n  }\n\n  /**\n   * has loop when 1. loop is validArray with length > 1 ; OR  2. loop is variable object\n   * @return boolean, has loop config or not\n   */\n  hasLoop() {\n    const value = this.getExtraProp('loop', false)?.getValue();\n    if (value === undefined || value === null) {\n      return false;\n    }\n\n    if (Array.isArray(value)) {\n      return true;\n    }\n    if (isJSExpression(value)) {\n      return true;\n    }\n    return false;\n  }\n\n  /* istanbul ignore next */\n  wrapWith(schema: Schema) {\n    const wrappedNode = this.replaceWith({ ...schema, children: [this.export()] });\n    return wrappedNode.children!.get(0);\n  }\n\n  replaceWith(schema: Schema, migrate = false): any {\n    // reuse the same id? or replaceSelection\n    schema = Object.assign({}, migrate ? this.export() : {}, schema);\n    return this.parent?.replaceChild(this, schema);\n  }\n\n  /**\n   * 替换子节点\n   *\n   * @param {INode} node\n   * @param {object} data\n   */\n  replaceChild(node: INode, data: any): INode | null {\n    if (this.children?.has(node)) {\n      const selected = this.document.selection.has(node.id);\n\n      delete data.id;\n      const newNode = this.document.createNode(data);\n\n      if (!isNode(newNode)) {\n        return null;\n      }\n\n      this.insertBefore(newNode, node, false);\n      node.remove(false);\n\n      if (selected) {\n        this.document.selection.select(newNode.id);\n      }\n      return newNode;\n    }\n    return node;\n  }\n\n  setVisible(flag: boolean): void {\n    this.getExtraProp('hidden')?.setValue(!flag);\n    this.emitter.emit('visibleChange', flag);\n  }\n\n  getVisible(): boolean {\n    return !this.getExtraProp('hidden')?.getValue();\n  }\n\n  onVisibleChange(func: (flag: boolean) => any): () => void {\n    const wrappedFunc = wrapWithEventSwitch(func);\n    this.emitter.on('visibleChange', wrappedFunc);\n    return () => {\n      this.emitter.removeListener('visibleChange', wrappedFunc);\n    };\n  }\n\n  getProp(path: string, createIfNone = true): IProp | null {\n    return this.props.query(path, createIfNone) || null;\n  }\n\n  getExtraProp(key: string, createIfNone = true): IProp | null {\n    return this.props.get(getConvertedExtraKey(key), createIfNone) || null;\n  }\n\n  setExtraProp(key: string, value: IPublicTypeCompositeValue) {\n    this.getProp(getConvertedExtraKey(key), true)?.setValue(value);\n  }\n\n  /**\n   * 获取单个属性值\n   */\n  getPropValue(path: string): any {\n    return this.getProp(path, false)?.value;\n  }\n\n  /**\n   * 设置单个属性值\n   */\n  setPropValue(path: string, value: any) {\n    this.getProp(path, true)!.setValue(value);\n  }\n\n  /**\n   * 清除已设置的值\n   */\n  clearPropValue(path: string): void {\n    this.getProp(path, false)?.unset();\n  }\n\n  /**\n   * 设置多个属性值，和原有值合并\n   */\n  mergeProps(props: IPublicTypePropsMap) {\n    this.props.merge(props);\n  }\n\n  /**\n   * 设置多个属性值，替换原有值\n   */\n  setProps(props?: IPublicTypePropsMap | IPublicTypePropsList | Props | null) {\n    if (props instanceof Props) {\n      this.props = props;\n      return;\n    }\n    this.props.import(props);\n  }\n\n  /**\n   * 获取节点在父容器中的索引\n   */\n  @computed get index(): number | undefined {\n    if (!this.parent) {\n      return -1;\n    }\n    return this.parent.children?.indexOf(this);\n  }\n\n  /**\n   * 获取下一个兄弟节点\n   */\n  get nextSibling(): INode | null | undefined {\n    if (!this.parent) {\n      return null;\n    }\n    const { index } = this;\n    if (typeof index !== 'number') {\n      return null;\n    }\n    if (index < 0) {\n      return null;\n    }\n    return this.parent.children?.get(index + 1);\n  }\n\n  /**\n   * 获取上一个兄弟节点\n   */\n  get prevSibling(): INode | null | undefined {\n    if (!this.parent) {\n      return null;\n    }\n    const { index } = this;\n    if (typeof index !== 'number') {\n      return null;\n    }\n    if (index < 1) {\n      return null;\n    }\n    return this.parent.children?.get(index - 1);\n  }\n\n  /**\n   * 获取符合搭建协议-节点 schema 结构\n   */\n  get schema(): Schema {\n    return this.export(IPublicEnumTransformStage.Save);\n  }\n\n  set schema(data: Schema) {\n    runInAction(() => this.import(data));\n  }\n\n  import(data: Schema, checkId = false) {\n    const { componentName, id, children, props, ...extras } = data;\n    if (this.isSlot()) {\n      foreachReverse(\n        this.children!,\n        (subNode: INode) => {\n          subNode.remove(true, true);\n        },\n        (iterable, idx) => (iterable as INodeChildren).get(idx),\n      );\n    }\n    if (this.isParental()) {\n      this.props.import(props, extras);\n      this._children?.import(children, checkId);\n    } else {\n      this.props\n        .get('children', true)!\n        .setValue(isDOMText(children) || isJSExpression(children) ? children : '');\n    }\n  }\n\n  toData() {\n    return this.export();\n  }\n\n  /**\n   * 导出 schema\n   */\n  export<T = IPublicTypeNodeSchema>(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, options: any = {}): T {\n    stage = compatStage(stage);\n    const baseSchema: any = {\n      componentName: this.componentName,\n    };\n\n    if (stage !== IPublicEnumTransformStage.Clone) {\n      baseSchema.id = this.id;\n    }\n    if (stage === IPublicEnumTransformStage.Render) {\n      baseSchema.docId = this.document.id;\n    }\n\n    if (this.isLeaf()) {\n      if (!options.bypassChildren) {\n        baseSchema.children = this.props.get('children')?.export(stage);\n      }\n      return baseSchema;\n    }\n\n    const { props = {}, extras } = this.props.export(stage) || {};\n    const _extras_: { [key: string]: any } = {\n      ...extras,\n    };\n    /* istanbul ignore next */\n    Object.keys(this._addons).forEach((key) => {\n      const addon = this._addons[key];\n      if (addon) {\n        if (addon.isProp) {\n          (props as any)[getConvertedExtraKey(key)] = addon.exportData();\n        } else {\n          _extras_[key] = addon.exportData();\n        }\n      }\n    });\n\n    const schema: any = {\n      ...baseSchema,\n      props: this.document.designer.transformProps(props, this, stage),\n      ...this.document.designer.transformProps(_extras_, this, stage),\n    };\n\n    if (this.isParental() && this.children && this.children.size > 0 && !options.bypassChildren) {\n      schema.children = this.children.export(stage);\n    }\n\n    return schema;\n  }\n\n  /**\n   * 判断是否包含特定节点\n   */\n  contains(node: INode): boolean {\n    return contains(this, node);\n  }\n\n  /**\n   * 获取特定深度的父亲节点\n   */\n  getZLevelTop(zLevel: number): INode | null {\n    return getZLevelTop(this, zLevel);\n  }\n\n  /**\n   * 判断与其它节点的位置关系\n   *\n   *  16 thisNode contains otherNode\n   *  8  thisNode contained_by otherNode\n   *  2  thisNode before or after otherNode\n   *  0  thisNode same as otherNode\n   */\n  comparePosition(otherNode: INode): PositionNO {\n    return comparePosition(this, otherNode);\n  }\n\n  unlinkSlot(slotNode: INode) {\n    const i = this._slots.indexOf(slotNode);\n    if (i < 0) {\n      return false;\n    }\n    this._slots.splice(i, 1);\n  }\n\n  /**\n   * 删除一个Slot节点\n   */\n  removeSlot(slotNode: INode): boolean {\n    // if (purge) {\n    //   // should set parent null\n    //   slotNode?.internalSetParent(null, false);\n    //   slotNode?.purge();\n    // }\n    // this.document.unlinkNode(slotNode);\n    // this.document.selection.remove(slotNode.id);\n    const i = this._slots.indexOf(slotNode);\n    if (i < 0) {\n      return false;\n    }\n    this._slots.splice(i, 1);\n    return false;\n  }\n\n  addSlot(slotNode: INode) {\n    const slotName = slotNode?.getExtraProp('name')?.getAsString();\n    // 一个组件下的所有 slot，相同 slotName 的 slot 应该是唯一的\n    if (includeSlot(this, slotName)) {\n      removeSlot(this, slotName);\n    }\n    slotNode.internalSetParent(this as INode, true);\n    this._slots.push(slotNode);\n  }\n\n  /**\n   * 当前node对应组件是否已注册可用\n   */\n  isValidComponent() {\n    const allComponents = this.document?.designer?.componentsMap;\n    if (allComponents && allComponents[this.componentName]) {\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * 删除一个节点\n   * @param node\n   */\n  removeChild(node: INode) {\n    this.children?.delete(node);\n  }\n\n  /**\n   * 销毁\n   */\n  purge() {\n    if (this.purged) {\n      return;\n    }\n    this.purged = true;\n    this.autoruns?.forEach((dispose) => dispose());\n    this.props.purge();\n    this.settingEntry?.purge();\n    // this.document.destroyNode(this);\n  }\n\n  internalPurgeStart() {\n    this.purging = true;\n  }\n\n  /**\n   * 是否可执行某 action\n   */\n  canPerformAction(actionName: string): boolean {\n    const availableActions =\n      this.componentMeta?.availableActions?.filter((action: IPublicTypeComponentAction) => {\n        const { condition } = action;\n        return typeof condition === 'function' ?\n          condition(this) !== false :\n          condition !== false;\n      })\n        .map((action: IPublicTypeComponentAction) => action.name) || [];\n\n    return availableActions.indexOf(actionName) >= 0;\n  }\n\n  // ======= compatible apis ====\n  isEmpty(): boolean {\n    return this.children ? this.children.isEmpty() : true;\n  }\n\n  getChildren() {\n    return this.children;\n  }\n\n  getComponentName() {\n    return this.componentName;\n  }\n\n  insert(node: INode, ref?: INode, useMutator = true) {\n    this.insertAfter(node, ref, useMutator);\n  }\n\n  insertBefore(node: INode, ref?: INode, useMutator = true) {\n    const nodeInstance = ensureNode(node, this.document);\n    this.children?.internalInsert(nodeInstance, ref ? ref.index : null, useMutator);\n  }\n\n  insertAfter(node: any, ref?: INode, useMutator = true) {\n    const nodeInstance = ensureNode(node, this.document);\n    this.children?.internalInsert(nodeInstance, ref ? (ref.index || 0) + 1 : null, useMutator);\n  }\n\n  getParent() {\n    return this.parent;\n  }\n\n  getId() {\n    return this.id;\n  }\n\n  getIndex() {\n    return this.index;\n  }\n\n  getNode() {\n    return this;\n  }\n\n  getRoot() {\n    return this.document.rootNode;\n  }\n\n  getProps() {\n    return this.props;\n  }\n\n  onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable | undefined {\n    const wrappedFunc = wrapWithEventSwitch(fn);\n    return this.children?.onChange(wrappedFunc);\n  }\n\n  mergeChildren(\n    remover: (node: INode, idx: number) => any,\n    adder: (children: INode[]) => IPublicTypeNodeData[] | null,\n    sorter: (firstNode: INode, secondNode: INode) => any,\n  ) {\n    this.children?.mergeChildren(remover, adder, sorter);\n  }\n\n  /**\n   * @deprecated\n   */\n  getStatus(field?: keyof NodeStatus) {\n    if (field && this.status[field] != null) {\n      return this.status[field];\n    }\n\n    return this.status;\n  }\n\n  /**\n   * @deprecated\n   */\n  setStatus(field: keyof NodeStatus, flag: boolean) {\n    if (!this.status.hasOwnProperty(field)) {\n      return;\n    }\n\n    if (flag !== this.status[field]) {\n      this.status[field] = flag;\n    }\n  }\n\n  /**\n   * @deprecated\n   */\n  getDOMNode(): any {\n    const instance = this.document.simulator?.getComponentInstances(this)?.[0];\n    if (!instance) {\n      return;\n    }\n    return this.document.simulator?.findDOMNodes(instance)?.[0];\n  }\n\n  /**\n   * @deprecated\n   */\n  getPage() {\n    console.warn('getPage is deprecated, use document instead');\n    return this.document;\n  }\n\n  /**\n   * 获取磁贴相关信息\n   */\n  getRGL(): {\n    isContainerNode: boolean;\n    isEmptyNode: boolean;\n    isRGLContainerNode: boolean;\n    isRGLNode: boolean;\n    isRGL: boolean;\n    rglNode: Node | null;\n  } {\n    const isContainerNode = this.isContainer();\n    const isEmptyNode = this.isEmpty();\n    const isRGLContainerNode = this.isRGLContainer;\n    const isRGLNode = (this.getParent()?.isRGLContainer) as boolean;\n    const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode));\n    let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : null;\n    return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode };\n  }\n\n  /**\n   * @deprecated no one is using this, will be removed in a future release\n   */\n  getSuitablePlace(node: INode, ref: any): any {\n    const focusNode = this.document?.focusNode;\n    // 如果节点是模态框，插入到根节点下\n    if (node?.componentMeta?.isModal) {\n      return { container: focusNode, ref };\n    }\n\n    if (!ref && focusNode && this.contains(focusNode)) {\n      const rootCanDropIn = focusNode.componentMeta?.prototype?.options?.canDropIn;\n      if (\n        rootCanDropIn === undefined ||\n        rootCanDropIn === true ||\n        (typeof rootCanDropIn === 'function' && rootCanDropIn(node))\n      ) {\n        return { container: focusNode };\n      }\n\n      return null;\n    }\n\n    if (this.isRoot() && this.children) {\n      const dropElement = this.children.filter((c) => {\n        if (!c.isContainerNode) {\n          return false;\n        }\n        const canDropIn = c.componentMeta?.prototype?.options?.canDropIn;\n        if (\n          canDropIn === undefined ||\n          canDropIn === true ||\n          (typeof canDropIn === 'function' && canDropIn(node))\n        ) {\n          return true;\n        }\n        return false;\n      })[0];\n\n      if (dropElement) {\n        return { container: dropElement, ref };\n      }\n\n      const rootCanDropIn = this.componentMeta?.prototype?.options?.canDropIn;\n      if (\n        rootCanDropIn === undefined ||\n        rootCanDropIn === true ||\n        (typeof rootCanDropIn === 'function' && rootCanDropIn(node))\n      ) {\n        return { container: this, ref };\n      }\n\n      return null;\n    }\n\n    const canDropIn = this.componentMeta?.prototype?.options?.canDropIn;\n    if (this.isContainer()) {\n      if (\n        canDropIn === undefined ||\n        (typeof canDropIn === 'boolean' && canDropIn) ||\n        (typeof canDropIn === 'function' && canDropIn(node))\n      ) {\n        return { container: this, ref };\n      }\n    }\n\n    if (this.parent) {\n      return this.parent.getSuitablePlace(node, { index: this.index });\n    }\n\n    return null;\n  }\n\n  /**\n   * @deprecated\n   */\n  getAddonData(key: string) {\n    const addon = this._addons[key];\n    if (addon) {\n      return addon.exportData();\n    }\n    return this.getExtraProp(key)?.getValue();\n  }\n\n  /**\n   * @deprecated\n   */\n  registerAddon(key: string, exportData: () => any, isProp = false) {\n    this._addons[key] = { exportData, isProp };\n  }\n\n  getRect(): DOMRect | null {\n    if (this.isRoot()) {\n      return this.document.simulator?.viewport.contentBounds || null;\n    }\n    return this.document.simulator?.computeRect(this) || null;\n  }\n\n  /**\n   * @deprecated\n   */\n  getPrototype() {\n    return this.componentMeta.prototype;\n  }\n\n  /**\n   * @deprecated\n   */\n  setPrototype(proto: any) {\n    this.componentMeta.prototype = proto;\n  }\n\n  getIcon() {\n    return this.icon;\n  }\n\n  toString() {\n    return this.id;\n  }\n\n  emitPropChange(val: IPublicTypePropChangeOptions) {\n    this.emitter?.emit('propChange', val);\n  }\n\n  onPropChange(func: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable {\n    const wrappedFunc = wrapWithEventSwitch(func);\n    this.emitter.on('propChange', wrappedFunc);\n    return () => {\n      this.emitter.removeListener('propChange', wrappedFunc);\n    };\n  }\n}\n\nfunction ensureNode(node: any, document: IDocumentModel): INode {\n  let nodeInstance = node;\n  if (!isNode(node)) {\n    if (node.getComponentName) {\n      nodeInstance = document.createNode({\n        componentName: node.getComponentName(),\n      });\n    } else {\n      nodeInstance = document.createNode(node);\n    }\n  }\n  return nodeInstance;\n}\n\nexport interface LeafNode extends Node {\n  readonly children: null;\n}\n\nexport type IPublicTypePropChangeOptions = Omit<GlobalEvent.Node.Prop.ChangeOptions, 'node'>;\n\nexport type ISlotNode = IBaseNode<IPublicTypeSlotSchema>;\nexport type IPageNode = IBaseNode<IPublicTypePageSchema>;\nexport type IComponentNode = IBaseNode<IPublicTypeComponentSchema>;\nexport type IRootNode = IPageNode | IComponentNode;\nexport type INode = IPageNode | ISlotNode | IComponentNode | IRootNode;\n\nexport function isRootNode(node: INode): node is IRootNode {\n  return node && node.isRootNode;\n}\n\nexport function isLowCodeComponent(node: INode): node is IComponentNode {\n  return node.componentMeta?.getMetadata().devMode === 'lowCode';\n}\n\nexport function getZLevelTop(child: INode, zLevel: number): INode | null {\n  let l = child.zLevel;\n  if (l < zLevel || zLevel < 0) {\n    return null;\n  }\n  if (l === zLevel) {\n    return child;\n  }\n  let r: any = child;\n  while (r && l-- > zLevel) {\n    r = r.parent;\n  }\n  return r;\n}\n\n/**\n * 测试两个节点是否为包含关系\n * @param node1 测试的父节点\n * @param node2 测试的被包含节点\n * @returns 是否包含\n */\nexport function contains(node1: INode, node2: INode): boolean {\n  if (node1 === node2) {\n    return true;\n  }\n\n  if (!node1.isParentalNode || !node2.parent) {\n    return false;\n  }\n\n  const p = getZLevelTop(node2, node1.zLevel);\n  if (!p) {\n    return false;\n  }\n\n  return node1 === p;\n}\n\n// 16 node1 contains node2\n// 8  node1 contained_by node2\n// 2  node1 before or after node2\n// 0  node1 same as node2\nexport enum PositionNO {\n  Contains = 16,\n  ContainedBy = 8,\n  BeforeOrAfter = 2,\n  TheSame = 0,\n}\nexport function comparePosition(node1: INode, node2: INode): PositionNO {\n  if (node1 === node2) {\n    return PositionNO.TheSame;\n  }\n  const l1 = node1.zLevel;\n  const l2 = node2.zLevel;\n  if (l1 === l2) {\n    return PositionNO.BeforeOrAfter;\n  }\n\n  let p: any;\n  if (l1 < l2) {\n    p = getZLevelTop(node2, l1);\n    if (p && p === node1) {\n      return PositionNO.Contains;\n    }\n    return PositionNO.BeforeOrAfter;\n  }\n\n  p = getZLevelTop(node1, l2);\n  if (p && p === node2) {\n    return PositionNO.ContainedBy;\n  }\n\n  return PositionNO.BeforeOrAfter;\n}\n\nexport function insertChild(\n  container: INode,\n  thing: INode | IPublicTypeNodeData,\n  at?: number | null,\n  copy?: boolean,\n): INode | null {\n  let node: INode | null | IRootNode | undefined;\n  let nodeSchema: IPublicTypeNodeSchema;\n  if (isNode<INode>(thing) && (copy || thing.isSlot())) {\n    nodeSchema = thing.export(IPublicEnumTransformStage.Clone);\n    node = container.document?.createNode(nodeSchema);\n  } else if (isNode<INode>(thing)) {\n    node = thing;\n  } else if (isNodeSchema(thing)) {\n    node = container.document?.createNode(thing);\n  }\n\n  if (isNode<INode>(node)) {\n    container.children?.insert(node, at);\n    return node;\n  }\n\n  return null;\n}\n\nexport function insertChildren(\n  container: INode,\n  nodes: INode[] | IPublicTypeNodeData[],\n  at?: number | null,\n  copy?: boolean,\n): INode[] {\n  let index = at;\n  let node: any;\n  const results: INode[] = [];\n  // eslint-disable-next-line no-cond-assign\n  while ((node = nodes.pop())) {\n    node = insertChild(container, node, index, copy);\n    results.push(node);\n    index = node.index;\n  }\n  return results;\n}\n"
  },
  {
    "path": "packages/designer/src/document/node/props/prop.ts",
    "content": "import { untracked, computed, obx, engineConfig, action, makeObservable, mobx, runInAction } from '@alilc/lowcode-editor-core';\nimport { GlobalEvent, IPublicEnumTransformStage } from '@alilc/lowcode-types';\nimport type { IPublicTypeCompositeValue, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicModelProp } from '@alilc/lowcode-types';\nimport { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot, isNodeSchema } from '@alilc/lowcode-utils';\nimport { valueToSource } from './value-to-source';\nimport { IPropParent } from './props';\nimport type { IProps } from './props';\nimport { ISlotNode, INode } from '../node';\n// import { TransformStage } from '../transform-stage';\n\nconst { set: mobxSet, isObservableArray } = mobx;\nexport const UNSET = Symbol.for('unset');\n// eslint-disable-next-line no-redeclare\nexport type UNSET = typeof UNSET;\n\nexport interface IProp extends Omit<IPublicModelProp<\n  INode\n>, 'exportSchema' | 'node'>, IPropParent {\n  spread: boolean;\n\n  key: string | number | undefined;\n\n  readonly props: IProps;\n\n  readonly owner: INode;\n\n  delete(prop: IProp): void;\n\n  export(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue;\n\n  getNode(): INode;\n\n  getAsString(): string;\n\n  unset(): void;\n\n  get value(): IPublicTypeCompositeValue | UNSET;\n\n  compare(other: IProp | null): number;\n\n  isUnset(): boolean;\n\n  purge(): void;\n\n  setupItems(): IProp[] | null;\n\n  isVirtual(): boolean;\n\n  get type(): ValueTypes;\n\n  get size(): number;\n\n  get code(): string;\n}\n\nexport type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot';\n\nexport class Prop implements IProp, IPropParent {\n  readonly isProp = true;\n\n  readonly owner: INode;\n\n  /**\n   * 键值\n   */\n  @obx key: string | number | undefined;\n\n  /**\n   * 扩展值\n   */\n  @obx spread: boolean;\n\n  readonly props: IProps;\n\n  readonly options: any;\n\n  readonly id = uniqueId('prop$');\n\n  @obx.ref private _type: ValueTypes = 'unset';\n\n  /**\n   * 属性类型\n   */\n  get type(): ValueTypes {\n    return this._type;\n  }\n\n  @obx private _value: any = UNSET;\n\n  /**\n   * 属性值\n   */\n  @computed get value(): IPublicTypeCompositeValue | UNSET {\n    return this.export(IPublicEnumTransformStage.Serilize);\n  }\n\n  private _code: string | null = null;\n\n  /**\n   * 获得表达式值\n   */\n  @computed get code() {\n    if (isJSExpression(this.value)) {\n      return this.value.value;\n    }\n    // todo: JSFunction ...\n    if (this.type === 'slot') {\n      return JSON.stringify(this._slotNode!.export(IPublicEnumTransformStage.Save));\n    }\n    return this._code != null ? this._code : JSON.stringify(this.value);\n  }\n\n  /**\n   * 设置表达式值\n   */\n  set code(code: string) {\n    if (isJSExpression(this._value)) {\n      this.setValue({\n        ...this._value,\n        value: code,\n      });\n      this._code = code;\n      return;\n    }\n\n    try {\n      const v = JSON.parse(code);\n      this.setValue(v);\n      this._code = code;\n      return;\n    } catch (e) {\n      // ignore\n    }\n\n    this.setValue({\n      type: 'JSExpression',\n      value: code,\n      mock: this._value,\n    });\n    this._code = code;\n  }\n\n  private _slotNode?: INode | null;\n\n  get slotNode(): INode | null {\n    return this._slotNode || null;\n  }\n\n  @obx.shallow private _items: IProp[] | null = null;\n\n  /**\n   * 作为一层缓存机制，主要是复用部分已存在的 Prop，保持响应式关系，比如：\n   * 当前 Prop#_value 值为 { a: 1 }，当调用 setValue({ a: 2 }) 时，所有原来的子 Prop 均被销毁，\n   * 导致假如外部有 mobx reaction（常见于 observer），此时响应式链路会被打断，\n   * 因为 reaction 监听的是原 Prop(a) 的 _value，而不是新 Prop(a) 的 _value。\n   */\n  @obx.shallow private _maps: Map<string | number, IProp> | null = null;\n\n  /**\n   * 构造 items 属性，同时构造 maps 属性\n   */\n  private get items(): IProp[] | null {\n    if (this._items) return this._items;\n    return runInAction(() => {\n      let items: IProp[] | null = null;\n      if (this._type === 'list') {\n        const maps = new Map<string, IProp>();\n        const data = this._value;\n        data.forEach((item: any, idx: number) => {\n          items = items || [];\n          let prop;\n          if (this._maps?.has(idx.toString())) {\n            prop = this._maps.get(idx.toString())!;\n            prop.setValue(item);\n          } else {\n            prop = new Prop(this, item, idx);\n          }\n          maps.set(idx.toString(), prop);\n          items.push(prop);\n        });\n        this._maps = maps;\n      } else if (this._type === 'map') {\n        const data = this._value;\n        const maps = new Map<string, IProp>();\n        const keys = Object.keys(data);\n        for (const key of keys) {\n          let prop: IProp;\n          if (this._maps?.has(key)) {\n            prop = this._maps.get(key)!;\n            prop.setValue(data[key]);\n          } else {\n            prop = new Prop(this, data[key], key);\n          }\n          items = items || [];\n          items.push(prop);\n          maps.set(key, prop);\n        }\n        this._maps = maps;\n      } else {\n        items = null;\n        this._maps = null;\n      }\n      this._items = items;\n      return this._items;\n    });\n  }\n\n  @computed private get maps(): Map<string | number, IProp> | null {\n    if (!this.items) {\n      return null;\n    }\n    return this._maps;\n  }\n\n  get path(): string[] {\n    return (this.parent.path || []).concat(this.key as string);\n  }\n\n  /**\n   * 元素个数\n   */\n  get size(): number {\n    return this.items?.length || 0;\n  }\n\n  private purged = false;\n\n  constructor(\n    public parent: IPropParent,\n    value: IPublicTypeCompositeValue | UNSET = UNSET,\n    key?: string | number,\n    spread = false,\n    options = {},\n  ) {\n    makeObservable(this);\n    this.owner = parent.owner;\n    this.props = parent.props;\n    this.key = key;\n    this.spread = spread;\n    this.options = options;\n    if (value !== UNSET) {\n      this.setValue(value);\n    }\n    this.setupItems();\n  }\n\n  // TODO: 先用调用方式触发子 prop 的初始化，后续须重构\n  @action\n  setupItems() {\n    return this.items;\n  }\n\n  /**\n   * @see SettingTarget\n   */\n  @action\n  getPropValue(propName: string | number): any {\n    return this.get(propName)!.getValue();\n  }\n\n  /**\n   * @see SettingTarget\n   */\n  @action\n  setPropValue(propName: string | number, value: any): void {\n    this.set(propName, value);\n  }\n\n  /**\n   * @see SettingTarget\n   */\n  @action\n  clearPropValue(propName: string | number): void {\n    this.get(propName, false)?.unset();\n  }\n\n  export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): IPublicTypeCompositeValue {\n    stage = compatStage(stage);\n    const type = this._type;\n    if (stage === IPublicEnumTransformStage.Render && this.key === '___condition___') {\n      // 在设计器里，所有组件默认需要展示，除非开启了 enableCondition 配置\n      if (engineConfig?.get('enableCondition') !== true) {\n        return true;\n      }\n      return this._value;\n    }\n\n    if (type === 'unset') {\n      return undefined;\n    }\n\n    if (type === 'literal' || type === 'expression') {\n      return this._value;\n    }\n\n    if (type === 'slot') {\n      const schema = this._slotNode?.export(stage) || {} as any;\n      if (stage === IPublicEnumTransformStage.Render) {\n        return {\n          type: 'JSSlot',\n          params: schema.params,\n          value: schema,\n          id: schema.id,\n        };\n      }\n      return {\n        type: 'JSSlot',\n        params: schema.params,\n        value: schema.children,\n        title: schema.title,\n        name: schema.name,\n        id: schema.id,\n      };\n    }\n\n    if (type === 'map') {\n      if (!this._items) {\n        return this._value;\n      }\n      let maps: any;\n      this.items!.forEach((prop, key) => {\n        if (!prop.isUnset()) {\n          const v = prop.export(stage);\n          if (v != null) {\n            maps = maps || {};\n            maps[prop.key || key] = v;\n          }\n        }\n      });\n      return maps;\n    }\n\n    if (type === 'list') {\n      if (!this._items) {\n        return this._value;\n      }\n      return this.items!.map((prop) => {\n        return prop?.export(stage);\n      });\n    }\n  }\n\n  getAsString(): string {\n    if (this.type === 'literal') {\n      return this._value ? String(this._value) : '';\n    }\n    return '';\n  }\n\n  /**\n   * set value, val should be JSON Object\n   */\n  @action\n  setValue(val: IPublicTypeCompositeValue) {\n    if (val === this._value) return;\n    const oldValue = this._value;\n    this._value = val;\n    this._code = null;\n    const t = typeof val;\n    if (val == null) {\n      // this._value = undefined;\n      this._type = 'literal';\n    } else if (t === 'string' || t === 'number' || t === 'boolean') {\n      this._type = 'literal';\n    } else if (Array.isArray(val)) {\n      this._type = 'list';\n    } else if (isPlainObject(val)) {\n      if (isJSSlot(val)) {\n        this.setAsSlot(val);\n      } else if (isJSExpression(val)) {\n        this._type = 'expression';\n      } else {\n        this._type = 'map';\n      }\n    } else /* istanbul ignore next */ {\n      this._type = 'expression';\n      this._value = {\n        type: 'JSExpression',\n        value: valueToSource(val),\n      };\n    }\n\n    this.dispose();\n    // setValue 的时候，如果不重新建立 items，items 的 setValue 没有触发，会导致子项的响应式逻辑不能被触发\n    this.setupItems();\n\n    if (oldValue !== this._value) {\n      this.emitChange({ oldValue });\n    }\n  }\n\n  emitChange = ({\n    oldValue,\n  }: {\n    oldValue: IPublicTypeCompositeValue | UNSET;\n  }) => {\n    const editor = this.owner.document?.designer.editor;\n    const propsInfo = {\n      key: this.key,\n      prop: this,\n      oldValue,\n      newValue: this.type === 'unset' ? undefined : this._value,\n    };\n\n    editor?.eventBus.emit(GlobalEvent.Node.Prop.InnerChange, {\n      node: this.owner as any,\n      ...propsInfo,\n    });\n\n    this.owner?.emitPropChange?.(propsInfo);\n  };\n\n  getValue(): IPublicTypeCompositeValue {\n    return this.export(IPublicEnumTransformStage.Serilize);\n  }\n\n  @action\n  private dispose() {\n    const items = untracked(() => this._items);\n    if (items) {\n      items.forEach((prop) => prop.purge());\n    }\n    this._items = null;\n    if (this._type !== 'slot' && this._slotNode) {\n      this._slotNode.remove();\n      this._slotNode = undefined;\n    }\n  }\n\n  @action\n  setAsSlot(data: IPublicTypeJSSlot) {\n    this._type = 'slot';\n    let slotSchema: IPublicTypeSlotSchema;\n    // 当 data.value 的结构为 { componentName: 'Slot' } 时，复用部分 slotSchema 数据\n    if ((isPlainObject(data.value) && isNodeSchema(data.value) && data.value?.componentName === 'Slot')) {\n      const value = data.value as IPublicTypeSlotSchema;\n      slotSchema = {\n        componentName: 'Slot',\n        title: value.title || value.props?.slotTitle,\n        id: value.id,\n        name: value.name || value.props?.slotName,\n        params: value.params || value.props?.slotParams,\n        children: value.children,\n      } as IPublicTypeSlotSchema;\n    } else {\n      slotSchema = {\n        componentName: 'Slot',\n        title: data.title,\n        id: data.id,\n        name: data.name,\n        params: data.params,\n        children: data.value,\n      };\n    }\n\n    if (this._slotNode) {\n      this._slotNode.import(slotSchema);\n    } else {\n      const { owner } = this.props;\n      this._slotNode = owner.document?.createNode<ISlotNode>(slotSchema);\n      if (this._slotNode) {\n        owner.addSlot(this._slotNode);\n        this._slotNode.internalSetSlotFor(this);\n      }\n    }\n  }\n\n  /**\n   * 取消设置值\n   */\n  @action\n  unset() {\n    if (this._type !== 'unset') {\n      this._type = 'unset';\n      this.emitChange({\n        oldValue: this._value,\n      });\n    }\n  }\n\n  /**\n   * 是否未设置值\n   */\n  @action\n  isUnset() {\n    return this._type === 'unset';\n  }\n\n  isVirtual() {\n    return typeof this.key === 'string' && this.key.charAt(0) === '!';\n  }\n\n  /**\n   * @returns  0: the same 1: maybe & like 2: not the same\n   */\n  compare(other: IProp | null): number {\n    if (!other || other.isUnset()) {\n      return this.isUnset() ? 0 : 2;\n    }\n    if (other.type !== this.type) {\n      return 2;\n    }\n    // list\n    if (this.type === 'list') {\n      return this.size === other.size ? 1 : 2;\n    }\n    if (this.type === 'map') {\n      return 1;\n    }\n\n    // 'literal' | 'map' | 'expression' | 'slot'\n    return this.code === other.code ? 0 : 2;\n  }\n\n  /**\n   * 获取某个属性\n   * @param createIfNone 当没有的时候，是否创建一个\n   */\n  @action\n  get(path: string | number, createIfNone = true): IProp | null {\n    const type = this._type;\n    if (type !== 'map' && type !== 'list' && type !== 'unset' && !createIfNone) {\n      return null;\n    }\n\n    const maps = type === 'map' ? this.maps : null;\n    const items = type === 'list' ? this.items : null;\n\n    let entry = path;\n    let nest = '';\n    if (typeof path !== 'number') {\n      const i = path.indexOf('.');\n      if (i > 0) {\n        nest = path.slice(i + 1);\n        if (nest) {\n          entry = path.slice(0, i);\n        }\n      }\n    }\n\n    let prop: any;\n    if (type === 'list') {\n      if (isValidArrayIndex(entry, this.size)) {\n        prop = items![entry];\n      }\n    } else if (type === 'map') {\n      prop = maps?.get(entry);\n    }\n\n    if (prop) {\n      return nest ? prop.get(nest, createIfNone) : prop;\n    }\n\n    if (createIfNone) {\n      prop = new Prop(this, UNSET, entry);\n      this.set(entry, prop, true);\n      if (nest) {\n        return prop.get(nest, true);\n      }\n\n      return prop;\n    }\n\n    return null;\n  }\n\n  /**\n   * 从父级移除本身\n   */\n  @action\n  remove() {\n    this.parent.delete(this);\n    this.unset();\n  }\n\n  /**\n   * 删除项\n   */\n  @action\n  delete(prop: IProp): void {\n    /* istanbul ignore else */\n    if (this._items) {\n      const i = this._items.indexOf(prop);\n      if (i > -1) {\n        this._items.splice(i, 1);\n        prop.purge();\n      }\n      if (this._maps && prop.key) {\n        this._maps.delete(String(prop.key));\n      }\n    }\n  }\n\n  /**\n   * 删除 key\n   */\n  @action\n  deleteKey(key: string): void {\n    /* istanbul ignore else */\n    if (this.maps) {\n      const prop = this.maps.get(key);\n      if (prop) {\n        this.delete(prop);\n      }\n    }\n  }\n\n  /**\n   * 添加值到列表\n   *\n   * @param force 强制\n   */\n  @action\n  add(value: IPublicTypeCompositeValue, force = false): IProp | null {\n    const type = this._type;\n    if (type !== 'list' && type !== 'unset' && !force) {\n      return null;\n    }\n    if (type === 'unset' || (force && type !== 'list')) {\n      this.setValue([]);\n    }\n    const prop = new Prop(this, value);\n    this._items = this._items || [];\n    this._items.push(prop);\n    return prop;\n  }\n\n  /**\n   * 设置值到字典\n   *\n   * @param force 强制\n   */\n  @action\n  set(key: string | number, value: IPublicTypeCompositeValue | Prop, force = false) {\n    const type = this._type;\n    if (type !== 'map' && type !== 'list' && type !== 'unset' && !force) {\n      return null;\n    }\n    if (type === 'unset' || (force && type !== 'map')) {\n      if (isValidArrayIndex(key)) {\n        if (type !== 'list') {\n          this.setValue([]);\n        }\n      } else {\n        this.setValue({});\n      }\n    }\n    const prop = isProp(value) ? value : new Prop(this, value, key);\n    let items = this._items! || [];\n    if (this.type === 'list') {\n      if (!isValidArrayIndex(key)) {\n        return null;\n      }\n      if (isObservableArray(items)) {\n        mobxSet(items, key, prop);\n      } else {\n        items[key] = prop;\n      }\n      this._items = items;\n    } else if (this.type === 'map') {\n      const maps = this._maps || new Map<string, Prop>();\n      const orig = maps?.get(key);\n      if (orig) {\n        // replace\n        const i = items.indexOf(orig);\n        if (i > -1) {\n          items.splice(i, 1, prop)[0].purge();\n        }\n        maps?.set(key, prop);\n      } else {\n        // push\n        items.push(prop);\n        this._items = items;\n        maps?.set(key, prop);\n      }\n      this._maps = maps;\n    } /* istanbul ignore next */ else {\n      return null;\n    }\n\n    return prop;\n  }\n\n  /**\n   * 是否存在 key\n   */\n  has(key: string): boolean {\n    if (this._type !== 'map') {\n      return false;\n    }\n    if (this._maps) {\n      return this._maps.has(key);\n    }\n    return hasOwnProperty(this._value, key);\n  }\n\n  /**\n   * 回收销毁\n   */\n  @action\n  purge() {\n    if (this.purged) {\n      return;\n    }\n    this.purged = true;\n    if (this._items) {\n      this._items.forEach((item) => item.purge());\n    }\n    this._items = null;\n    this._maps = null;\n    if (this._slotNode && this._slotNode.slotFor === this) {\n      this._slotNode.remove();\n      this._slotNode = undefined;\n    }\n  }\n\n  /**\n   * 迭代器\n   */\n  [Symbol.iterator](): { next(): { value: IProp } } {\n    let index = 0;\n    const { items } = this;\n    const length = items?.length || 0;\n    return {\n      next() {\n        if (index < length) {\n          return {\n            value: items![index++],\n            done: false,\n          };\n        }\n        return {\n          value: undefined as any,\n          done: true,\n        };\n      },\n    };\n  }\n\n  /**\n   * 遍历\n   */\n  @action\n  forEach(fn: (item: IProp, key: number | string | undefined) => void): void {\n    const { items } = this;\n    if (!items) {\n      return;\n    }\n    const isMap = this._type === 'map';\n    items.forEach((item, index) => {\n      return isMap ? fn(item, item.key) : fn(item, index);\n    });\n  }\n\n  /**\n   * 遍历\n   */\n  @action\n  map<T>(fn: (item: IProp, key: number | string | undefined) => T): T[] | null {\n    const { items } = this;\n    if (!items) {\n      return null;\n    }\n    const isMap = this._type === 'map';\n    return items.map((item, index) => {\n      return isMap ? fn(item, item.key) : fn(item, index);\n    });\n  }\n\n  getProps() {\n    return this.props;\n  }\n\n  getNode() {\n    return this.owner;\n  }\n}\n\nexport function isProp(obj: any): obj is Prop {\n  return obj && obj.isProp;\n}\n\nexport function isValidArrayIndex(key: any, limit = -1): key is number {\n  const n = parseFloat(String(key));\n  return n >= 0 && Math.floor(n) === n && isFinite(n) && (limit < 0 || n < limit);\n}\n"
  },
  {
    "path": "packages/designer/src/document/node/props/props.ts",
    "content": "import { computed, makeObservable, obx, action } from '@alilc/lowcode-editor-core';\nimport { IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage, IBaseModelProps } from '@alilc/lowcode-types';\nimport type { IPublicTypePropsMap } from '@alilc/lowcode-types';\nimport { uniqueId, compatStage } from '@alilc/lowcode-utils';\nimport { Prop, UNSET } from './prop';\nimport type { IProp } from './prop';\nimport { INode } from '../node';\n// import { TransformStage } from '../transform-stage';\n\ninterface ExtrasObject {\n  [key: string]: any;\n}\n\nexport const EXTRA_KEY_PREFIX = '___';\nexport function getConvertedExtraKey(key: string): string {\n  if (!key) {\n    return '';\n  }\n  let _key = key;\n  if (key.indexOf('.') > 0) {\n    _key = key.split('.')[0];\n  }\n  return EXTRA_KEY_PREFIX + _key + EXTRA_KEY_PREFIX + key.slice(_key.length);\n}\nexport function getOriginalExtraKey(key: string): string {\n  return key.replace(new RegExp(`${EXTRA_KEY_PREFIX}`, 'g'), '');\n}\n\nexport interface IPropParent {\n\n  readonly props: IProps;\n\n  readonly owner: INode;\n\n  get path(): string[];\n\n  delete(prop: IProp): void;\n}\n\nexport interface IProps extends Omit<IBaseModelProps<IProp>, | 'getExtraProp' | 'getExtraPropValue' | 'setExtraPropValue' | 'node'>, IPropParent {\n\n  /**\n   * 获取 props 对应的 node\n   */\n  getNode(): INode;\n\n  get(path: string, createIfNone?: boolean): IProp | null;\n\n  export(stage?: IPublicEnumTransformStage): {\n    props?: IPublicTypePropsMap | IPublicTypePropsList;\n    extras?: ExtrasObject;\n  };\n\n  merge(value: IPublicTypePropsMap, extras?: IPublicTypePropsMap): void;\n\n  purge(): void;\n\n  query(path: string, createIfNone: boolean): IProp | null;\n\n  import(value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject): void;\n}\n\nexport class Props implements IProps, IPropParent {\n  readonly id = uniqueId('props');\n\n  @obx.shallow private items: IProp[] = [];\n\n  @computed private get maps(): Map<string, Prop> {\n    const maps = new Map();\n    if (this.items.length > 0) {\n      this.items.forEach((prop) => {\n        if (prop.key) {\n          maps.set(prop.key, prop);\n        }\n      });\n    }\n    return maps;\n  }\n\n  readonly path = [];\n\n  get props(): IProps {\n    return this;\n  }\n\n  readonly owner: INode;\n\n  /**\n   * 元素个数\n   */\n  @computed get size() {\n    return this.items.length;\n  }\n\n  @obx type: 'map' | 'list' = 'map';\n\n  private purged = false;\n\n  constructor(owner: INode, value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject) {\n    makeObservable(this);\n    this.owner = owner;\n    if (Array.isArray(value)) {\n      this.type = 'list';\n      this.items = value.map(\n        (item, idx) => new Prop(this, item.value, item.name || idx, item.spread),\n      );\n    } else if (value != null) {\n      this.items = Object.keys(value).map((key) => new Prop(this, value[key], key, false));\n    }\n    if (extras) {\n      Object.keys(extras).forEach((key) => {\n        this.items.push(new Prop(this, (extras as any)[key], getConvertedExtraKey(key)));\n      });\n    }\n  }\n\n  @action\n  import(value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject) {\n    const originItems = this.items;\n    if (Array.isArray(value)) {\n      this.type = 'list';\n      this.items = value.map(\n        (item, idx) => new Prop(this, item.value, item.name || idx, item.spread),\n      );\n    } else if (value != null) {\n      this.type = 'map';\n      this.items = Object.keys(value).map((key) => new Prop(this, value[key], key));\n    } else {\n      this.type = 'map';\n      this.items = [];\n    }\n    if (extras) {\n      Object.keys(extras).forEach((key) => {\n        this.items.push(new Prop(this, (extras as any)[key], getConvertedExtraKey(key)));\n      });\n    }\n    originItems.forEach((item) => item.purge());\n  }\n\n  @action\n  merge(value: IPublicTypePropsMap, extras?: IPublicTypePropsMap) {\n    Object.keys(value).forEach((key) => {\n      this.query(key, true)!.setValue(value[key]);\n      this.query(key, true)!.setupItems();\n    });\n    if (extras) {\n      Object.keys(extras).forEach((key) => {\n        this.query(getConvertedExtraKey(key), true)!.setValue(extras[key]);\n        this.query(getConvertedExtraKey(key), true)!.setupItems();\n      });\n    }\n  }\n\n  export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): {\n    props?: IPublicTypePropsMap | IPublicTypePropsList;\n    extras?: ExtrasObject;\n  } {\n    stage = compatStage(stage);\n    if (this.items.length < 1) {\n      return {};\n    }\n    let allProps = {} as any;\n    let props: any = {};\n    const extras: any = {};\n    if (this.type === 'list') {\n      props = [];\n      this.items.forEach((item) => {\n        let value = item.export(stage);\n        let name = item.key as string;\n        if (name && typeof name === 'string' && name.startsWith(EXTRA_KEY_PREFIX)) {\n          name = getOriginalExtraKey(name);\n          extras[name] = value;\n        } else {\n          props.push({\n            spread: item.spread,\n            name,\n            value,\n          });\n        }\n      });\n    } else {\n      this.items.forEach((item) => {\n        let name = item.key as string;\n        if (name == null || item.isUnset() || item.isVirtual()) return;\n        let value = item.export(stage);\n        if (value != null) {\n          allProps[name] = value;\n        }\n      });\n      // compatible vision\n      const transformedProps = this.transformToStatic(allProps);\n      Object.keys(transformedProps).forEach((name) => {\n        const value = transformedProps[name];\n        if (typeof name === 'string' && name.startsWith(EXTRA_KEY_PREFIX)) {\n          name = getOriginalExtraKey(name);\n          extras[name] = value;\n        } else {\n          props[name] = value;\n        }\n      });\n    }\n\n    return { props, extras };\n  }\n\n  /**\n   * @deprecated\n   */\n  /* istanbul ignore next */\n  private transformToStatic(props: any) {\n    let transducers = this.owner.componentMeta?.prototype?.options?.transducers;\n    if (!transducers) {\n      return props;\n    }\n    if (!Array.isArray(transducers)) {\n      transducers = [transducers];\n    }\n    props = transducers.reduce((xprops: any, transducer: any) => {\n      if (transducer && typeof transducer.toStatic === 'function') {\n        return transducer.toStatic(xprops);\n      }\n      return xprops;\n    }, props);\n    return props;\n  }\n\n  /**\n   * 根据 path 路径查询属性\n   *\n   * @param createIfNone 当没有的时候，是否创建一个\n   */\n  @action\n  query(path: string, createIfNone = true): IProp | null {\n    return this.get(path, createIfNone);\n  }\n\n  /**\n   * 获取某个属性，如果不存在，临时获取一个待写入\n   * @param createIfNone 当没有的时候，是否创建一个\n   */\n  @action\n  get(path: string, createIfNone = false): IProp | null {\n    let entry = path;\n    let nest = '';\n    const i = path.indexOf('.');\n    if (i > 0) {\n      nest = path.slice(i + 1);\n      if (nest) {\n        entry = path.slice(0, i);\n      }\n    }\n\n    let prop = this.maps.get(entry);\n    if (!prop && createIfNone) {\n      prop = new Prop(this, UNSET, entry);\n      this.items.push(prop);\n    }\n\n    if (prop) {\n      return nest ? prop.get(nest, createIfNone) : prop;\n    }\n\n    return null;\n  }\n\n  /**\n   * 删除项\n   */\n  @action\n  delete(prop: IProp): void {\n    const i = this.items.indexOf(prop);\n    if (i > -1) {\n      this.items.splice(i, 1);\n      prop.purge();\n    }\n  }\n\n  /**\n   * 删除 key\n   */\n  @action\n  deleteKey(key: string): void {\n    this.items = this.items.filter((item, i) => {\n      if (item.key === key) {\n        item.purge();\n        this.items.splice(i, 1);\n        return false;\n      }\n      return true;\n    });\n  }\n\n  /**\n   * 添加值\n   */\n  @action\n  add(\n    value: IPublicTypeCompositeValue | null,\n    key?: string | number,\n    spread = false,\n    options: any = {},\n  ): IProp {\n    const prop = new Prop(this, value, key, spread, options);\n    this.items.push(prop);\n    return prop;\n  }\n\n  /**\n   * 是否存在 key\n   */\n  has(key: string): boolean {\n    return this.maps.has(key);\n  }\n\n  /**\n   * 迭代器\n   */\n  [Symbol.iterator](): { next(): { value: IProp } } {\n    let index = 0;\n    const { items } = this;\n    const length = items.length || 0;\n    return {\n      next() {\n        if (index < length) {\n          return {\n            value: items[index++],\n            done: false,\n          };\n        }\n        return {\n          value: undefined as any,\n          done: true,\n        };\n      },\n    };\n  }\n\n  /**\n   * 遍历\n   */\n  @action\n  forEach(fn: (item: IProp, key: number | string | undefined) => void): void {\n    this.items.forEach((item) => {\n      return fn(item, item.key);\n    });\n  }\n\n  /**\n   * 遍历\n   */\n  @action\n  map<T>(fn: (item: IProp, key: number | string | undefined) => T): T[] | null {\n    return this.items.map((item) => {\n      return fn(item, item.key);\n    });\n  }\n\n  @action\n  filter(fn: (item: IProp, key: number | string | undefined) => boolean) {\n    return this.items.filter((item) => {\n      return fn(item, item.key);\n    });\n  }\n\n  /**\n   * 回收销毁\n   */\n  @action\n  purge() {\n    if (this.purged) {\n      return;\n    }\n    this.purged = true;\n    this.items.forEach((item) => item.purge());\n  }\n\n  /**\n   * 获取某个属性, 如果不存在，临时获取一个待写入\n   * @param createIfNone 当没有的时候，是否创建一个\n   */\n  @action\n  getProp(path: string, createIfNone = true): IProp | null {\n    return this.query(path, createIfNone) || null;\n  }\n\n  /**\n   * 获取单个属性值\n   */\n  @action\n  getPropValue(path: string): any {\n    return this.getProp(path, false)?.value;\n  }\n\n  /**\n   * 设置单个属性值\n   */\n  @action\n  setPropValue(path: string, value: any) {\n    this.getProp(path, true)!.setValue(value);\n  }\n\n  /**\n   * 获取 props 对应的 node\n   */\n  getNode() {\n    return this.owner;\n  }\n\n  /**\n   * @deprecated\n   * 获取 props 对应的 node\n   */\n  @action\n  toData() {\n    return this.export()?.props;\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/document/node/props/value-to-source.ts",
    "content": "function propertyNameRequiresQuotes(propertyName: string) {\n  try {\n    const context = {\n      worksWithoutQuotes: false,\n    };\n\n    // eslint-disable-next-line no-new-func\n    new Function('ctx', `ctx.worksWithoutQuotes = {${propertyName}: true}['${propertyName}']`)();\n\n    return !context.worksWithoutQuotes;\n  } catch (ex) {\n    return true;\n  }\n}\n\nfunction quoteString(str: string, { doubleQuote }: any) {\n  return doubleQuote ? `\"${str.replace(/\"/gu, '\\\\\"')}\"` : `'${str.replace(/'/gu, \"\\\\'\")}'`;\n}\n\nexport function valueToSource(\n  value: any,\n  {\n    circularReferenceToken = 'CIRCULAR_REFERENCE',\n    doubleQuote = true,\n    includeFunctions = true,\n    includeUndefinedProperties = false,\n    indentLevel = 0,\n    indentString = '  ',\n    lineEnding = '\\n',\n    visitedObjects = new Set(),\n  }: any = {},\n): any {\n  switch (typeof value) {\n    case 'boolean':\n      return value ? `${indentString.repeat(indentLevel)}true` : `${indentString.repeat(indentLevel)}false`;\n    case 'function':\n      if (includeFunctions) {\n        return `${indentString.repeat(indentLevel)}${value}`;\n      }\n      return null;\n    case 'number':\n      return `${indentString.repeat(indentLevel)}${value}`;\n    case 'object':\n      if (!value) {\n        return `${indentString.repeat(indentLevel)}null`;\n      }\n\n      if (visitedObjects.has(value)) {\n        return `${indentString.repeat(indentLevel)}${circularReferenceToken}`;\n      }\n\n      if (value instanceof Date) {\n        return `${indentString.repeat(indentLevel)}new Date(${quoteString(value.toISOString(), {\n          doubleQuote,\n        })})`;\n      }\n\n      if (value instanceof Map) {\n        return value.size\n          ? `${indentString.repeat(indentLevel)}new Map(${valueToSource([...value], {\n            circularReferenceToken,\n            doubleQuote,\n            includeFunctions,\n            includeUndefinedProperties,\n            indentLevel,\n            indentString,\n            lineEnding,\n            visitedObjects: new Set([value, ...visitedObjects]),\n          }).slice(indentLevel * indentString.length)})`\n          : `${indentString.repeat(indentLevel)}new Map()`;\n      }\n\n      if (value instanceof RegExp) {\n        return `${indentString.repeat(indentLevel)}/${value.source}/${value.flags}`;\n      }\n\n      if (value instanceof Set) {\n        return value.size\n          ? `${indentString.repeat(indentLevel)}new Set(${valueToSource([...value], {\n            circularReferenceToken,\n            doubleQuote,\n            includeFunctions,\n            includeUndefinedProperties,\n            indentLevel,\n            indentString,\n            lineEnding,\n            visitedObjects: new Set([value, ...visitedObjects]),\n          }).slice(indentLevel * indentString.length)})`\n          : `${indentString.repeat(indentLevel)}new Set()`;\n      }\n\n      if (Array.isArray(value)) {\n        if (!value.length) {\n          return `${indentString.repeat(indentLevel)}[]`;\n        }\n\n        const itemsStayOnTheSameLine = value.every(\n          item => typeof item === 'object' &&\n            item &&\n            !(item instanceof Date) &&\n            !(item instanceof Map) &&\n            !(item instanceof RegExp) &&\n            !(item instanceof Set) &&\n            (Object.keys(item).length || value.length === 1),\n        );\n\n        let previousIndex: number | null = null;\n\n        value = value.reduce((items, item, index) => {\n          if (previousIndex !== null) {\n            for (let i = index - previousIndex - 1; i > 0; i -= 1) {\n              items.push(indentString.repeat(indentLevel + 1));\n            }\n          }\n\n          previousIndex = index;\n\n          item = valueToSource(item, {\n            circularReferenceToken,\n            doubleQuote,\n            includeFunctions,\n            includeUndefinedProperties,\n            indentLevel: itemsStayOnTheSameLine ? indentLevel : indentLevel + 1,\n            indentString,\n            lineEnding,\n            visitedObjects: new Set([value, ...visitedObjects]),\n          });\n\n          if (item === null) {\n            items.push(indentString.repeat(indentLevel + 1));\n          } else if (itemsStayOnTheSameLine) {\n            items.push(item.slice(indentLevel * indentString.length));\n          } else {\n            items.push(item);\n          }\n\n          return items;\n        }, []);\n\n        return itemsStayOnTheSameLine\n          ? `${indentString.repeat(indentLevel)}[${value.join(', ')}]`\n          : `${indentString.repeat(indentLevel)}[${lineEnding}${value.join(\n            `,${lineEnding}`,\n          )}${lineEnding}${indentString.repeat(indentLevel)}]`;\n      }\n\n      value = Object.keys(value).reduce<string[]>((entries, propertyName) => {\n        const propertyValue = value[propertyName];\n        const propertyValueString =\n            typeof propertyValue !== 'undefined' || includeUndefinedProperties\n              ? valueToSource(value[propertyName], {\n                circularReferenceToken,\n                doubleQuote,\n                includeFunctions,\n                includeUndefinedProperties,\n                indentLevel: indentLevel + 1,\n                indentString,\n                lineEnding,\n                visitedObjects: new Set([value, ...visitedObjects]),\n              })\n              : null;\n\n        if (propertyValueString) {\n          const quotedPropertyName = propertyNameRequiresQuotes(propertyName)\n            ? quoteString(propertyName, {\n              doubleQuote,\n            })\n            : propertyName;\n          const trimmedPropertyValueString = propertyValueString.slice((indentLevel + 1) * indentString.length);\n\n          if (typeof propertyValue === 'function' && trimmedPropertyValueString.startsWith(`${propertyName}()`)) {\n            entries.push(\n              `${indentString.repeat(indentLevel + 1)}${quotedPropertyName} ${trimmedPropertyValueString.slice(\n                propertyName.length,\n              )}`,\n            );\n          } else {\n            entries.push(`${indentString.repeat(indentLevel + 1)}${quotedPropertyName}: ${trimmedPropertyValueString}`);\n          }\n        }\n\n        return entries;\n      }, []);\n\n      return value.length\n        ? `${indentString.repeat(indentLevel)}{${lineEnding}${value.join(\n          `,${lineEnding}`,\n        )}${lineEnding}${indentString.repeat(indentLevel)}}`\n        : `${indentString.repeat(indentLevel)}{}`;\n    case 'string':\n      return `${indentString.repeat(indentLevel)}${quoteString(value, {\n        doubleQuote,\n      })}`;\n    case 'symbol': {\n      let key = Symbol.keyFor(value);\n\n      if (typeof key === 'string') {\n        return `${indentString.repeat(indentLevel)}Symbol.for(${quoteString(key, {\n          doubleQuote,\n        })})`;\n      }\n\n      key = value.toString().slice(7, -1);\n\n      if (key) {\n        return `${indentString.repeat(indentLevel)}Symbol(${quoteString(key, {\n          doubleQuote,\n        })})`;\n      }\n\n      return `${indentString.repeat(indentLevel)}Symbol()`;\n    }\n    case 'undefined':\n      return `${indentString.repeat(indentLevel)}undefined`;\n    default:\n      return `${indentString.repeat(indentLevel)}undefined`;\n  }\n}\n\nexport function getSource(value: any): string {\n  if (value && value.__source) {\n    return value.__source;\n  }\n  let source = valueToSource(value);\n  if (source === 'undefined') {\n    source = '';\n  }\n  if (value) {\n    try {\n      value.__source = source;\n    } catch (ex) {\n      console.error(ex);\n    }\n  }\n  return source;\n}\n"
  },
  {
    "path": "packages/designer/src/document/node/transform-stage.ts",
    "content": "export { TransformStage } from '@alilc/lowcode-types';\n"
  },
  {
    "path": "packages/designer/src/document/selection.ts",
    "content": "import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { INode, comparePosition, PositionNO } from './node/node';\nimport { DocumentModel } from './document-model';\nimport { IPublicModelSelection } from '@alilc/lowcode-types';\n\nexport interface ISelection extends Omit<IPublicModelSelection<INode>, 'node'> {\n  containsNode(node: INode, excludeRoot: boolean): boolean;\n}\n\nexport class Selection implements ISelection {\n  private emitter: IEventBus = createModuleEventBus('Selection');\n\n  @obx.shallow private _selected: string[] = [];\n\n  constructor(readonly doc: DocumentModel) {\n    makeObservable(this);\n  }\n\n  /**\n   * 选中的节点 id\n   */\n  get selected(): string[] {\n    return this._selected;\n  }\n\n  /**\n   * 选中\n   */\n  select(id: string) {\n    if (this._selected.length === 1 && this._selected.indexOf(id) > -1) {\n      // avoid cause reaction\n      return;\n    }\n\n    const node = this.doc.getNode(id);\n\n    if (!node?.canSelect()) {\n      return;\n    }\n\n    this._selected = [id];\n    this.emitter.emit('selectionchange', this._selected);\n  }\n\n  /**\n   * 批量选中\n   */\n  selectAll(ids: string[]) {\n    const selectIds: string[] = [];\n\n    ids.forEach(d => {\n      const node = this.doc.getNode(d);\n\n      if (node?.canSelect()) {\n        selectIds.push(d);\n      }\n    });\n\n    this._selected = selectIds;\n\n    this.emitter.emit('selectionchange', this._selected);\n  }\n\n  /**\n   * 清除选中\n   */\n  clear() {\n    if (this._selected.length < 1) {\n      return;\n    }\n    this._selected = [];\n    this.emitter.emit('selectionchange', this._selected);\n  }\n\n  /**\n   * 整理选中\n   */\n  dispose() {\n    const l = this._selected.length;\n    let i = l;\n    while (i-- > 0) {\n      const id = this._selected[i];\n      if (!this.doc.hasNode(id)) {\n        this._selected.splice(i, 1);\n      }\n    }\n    if (this._selected.length !== l) {\n      this.emitter.emit('selectionchange', this._selected);\n    }\n  }\n\n  /**\n   * 添加选中\n   */\n  add(id: string) {\n    if (this._selected.indexOf(id) > -1) {\n      return;\n    }\n\n    this._selected.push(id);\n    this.emitter.emit('selectionchange', this._selected);\n  }\n\n  /**\n   * 是否选中\n   */\n  has(id: string) {\n    return this._selected.indexOf(id) > -1;\n  }\n\n  /**\n   * 移除选中\n   */\n  remove(id: string) {\n    const i = this._selected.indexOf(id);\n    if (i > -1) {\n      this._selected.splice(i, 1);\n      this.emitter.emit('selectionchange', this._selected);\n    }\n  }\n\n  /**\n   * 选区是否包含节点\n   */\n  containsNode(node: INode, excludeRoot = false) {\n    for (const id of this._selected) {\n      const parent = this.doc.getNode(id);\n      if (excludeRoot && parent?.contains(this.doc.focusNode)) {\n        continue;\n      }\n      if (parent?.contains(node)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * 获取选中的节点\n   */\n  getNodes(): INode[] {\n    const nodes: INode[] = [];\n    for (const id of this._selected) {\n      const node = this.doc.getNode(id);\n      if (node) {\n        nodes.push(node);\n      }\n    }\n    return nodes;\n  }\n\n  /**\n   * 获取顶层选区节点，场景：拖拽时，建立蒙层，只蒙在最上层\n   */\n  getTopNodes(includeRoot = false) {\n    const nodes = [];\n    for (const id of this._selected) {\n      const node = this.doc.getNode(id);\n      // 排除根节点\n      if (!node || (!includeRoot && node.contains(this.doc.focusNode))) {\n        continue;\n      }\n      let i = nodes.length;\n      let isTop = true;\n      while (i-- > 0) {\n        const n = comparePosition(nodes[i], node);\n        // nodes[i] contains node\n        if (n === PositionNO.Contains || n === PositionNO.TheSame) {\n          isTop = false;\n          break;\n        } else if (n === PositionNO.ContainedBy) {\n          // node contains nodes[i], delete nodes[i]\n          nodes.splice(i, 1);\n        }\n      }\n      // node is top item, push to nodes\n      if (isTop) {\n        nodes.push(node);\n      }\n    }\n    return nodes;\n  }\n\n  onSelectionChange(fn: (ids: string[]) => void): () => void {\n    this.emitter.on('selectionchange', fn);\n    return () => {\n      this.emitter.removeListener('selectionchange', fn);\n    };\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/icons/clone.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconClone(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M192 256.16C192 220.736 220.704 192 256.16 192h639.68C931.264 192 960 220.704 960 256.16v639.68A64.16 64.16 0 0 1 895.84 960H256.16A64.16 64.16 0 0 1 192 895.84V256.16z m64 31.584v576.512a32 32 0 0 0 31.744 31.744h576.512a32 32 0 0 0 31.744-31.744V287.744A32 32 0 0 0 864.256 256H287.744A32 32 0 0 0 256 287.744zM288 192v64h64V192H288z m128 0v64h64V192h-64z m128 0v64h64V192h-64z m128 0v64h64V192h-64z m128 0v64h64V192h-64z m96 96v64h64V288h-64z m0 128v64h64v-64h-64z m0 128v64h64v-64h-64z m0 128v64h64v-64h-64z m0 128v64h64v-64h-64z m-96 96v64h64v-64h-64z m-128 0v64h64v-64h-64z m-128 0v64h64v-64h-64z m-128 0v64h64v-64h-64z m-128 0v64h64v-64H288z m-96-96v64h64v-64H192z m0-128v64h64v-64H192z m0-128v64h64v-64H192z m0-128v64h64v-64H192z m0-128v64h64V288H192z m160 416c0-17.664 14.592-32 32.064-32h319.872a31.968 31.968 0 1 1 0 64h-319.872A31.968 31.968 0 0 1 352 704z m0-128c0-17.664 14.4-32 32.224-32h383.552c17.792 0 32.224 14.208 32.224 32 0 17.664-14.4 32-32.224 32H384.224A32.032 32.032 0 0 1 352 576z m0-128c0-17.664 14.4-32 32.224-32h383.552c17.792 0 32.224 14.208 32.224 32 0 17.664-14.4 32-32.224 32H384.224A32.032 32.032 0 0 1 352 448z m512 47.936V192h-64V159.968A31.776 31.776 0 0 0 768.032 128H160A31.776 31.776 0 0 0 128 159.968V768c0 17.92 14.304 31.968 31.968 31.968H192v64h303.936H128.128A63.968 63.968 0 0 1 64 799.872V128.128C64 92.704 92.48 64 128.128 64h671.744C835.296 64 864 92.48 864 128.128v367.808z\" />\n    </SVGIcon>\n  );\n}\n\nIconClone.displayName = 'Clone';\n"
  },
  {
    "path": "packages/designer/src/icons/component.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconComponent(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M783.5648 437.4528h-18.0224V336.6912c0-43.8272-35.6352-79.4624-79.4624-79.4624h-110.592V241.664c0-90.9312-73.728-164.6592-164.6592-164.6592-90.9312 0-164.6592 73.728-164.6592 164.6592v15.5648H155.2384c-43.8272 0-79.4624 35.6352-79.4624 79.4624v131.4816c0 16.7936 13.9264 30.72 30.72 30.72h56.1152c56.9344 0 103.2192 46.2848 103.2192 103.2192s-46.2848 103.2192-103.2192 103.2192H106.496c-16.7936 0-30.72 13.9264-30.72 30.72v131.4816c0 43.8272 35.6352 79.4624 79.4624 79.4624h531.2512c43.8272 0 79.4624-35.6352 79.4624-79.4624v-100.7616h18.0224c90.9312 0 164.6592-73.728 164.6592-164.6592-0.4096-90.9312-74.1376-164.6592-165.0688-164.6592z m0 267.8784h-48.7424c-16.7936 0-30.72 13.9264-30.72 30.72v131.4816c0 9.8304-8.192 18.0224-18.0224 18.0224H155.2384c-9.8304 0-18.0224-8.192-18.0224-18.0224v-100.7616h25.3952c90.9312 0 164.6592-73.728 164.6592-164.6592 0-90.9312-73.728-164.6592-164.6592-164.6592h-25.3952V336.6912c0-9.8304 8.192-18.0224 18.0224-18.0224h121.6512c16.7936 0 30.72-13.9264 30.72-30.72V241.664c0-56.9344 46.2848-103.2192 103.2192-103.2192s103.2192 46.2848 103.2192 103.2192v46.2848c0 16.7936 13.9264 30.72 30.72 30.72h141.312c9.8304 0 18.0224 8.192 18.0224 18.0224v131.4816c0 16.7936 13.9264 30.72 30.72 30.72h48.7424c56.9344 0 103.2192 46.2848 103.2192 103.2192s-46.2848 103.2192-103.2192 103.2192z\" />\n    </SVGIcon>\n  );\n}\nIconComponent.displayName = 'Component';\n"
  },
  {
    "path": "packages/designer/src/icons/container.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconContainer(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M800 800h64v64h-64v-64z m-128 0h64v64h-64v-64z m-128 0h64v64h-64v-64z m-128 0h64v64h-64v-64z m-256 0h64v64h-64v-64z m0-640h64v64h-64v-64z m128 640h64v64h-64v-64zM160 672h64v64h-64v-64z m0-128h64v64h-64v-64z m0-128h64v64h-64v-64z m0-128h64v64h-64v-64z m640 384h64v64h-64v-64z m0-128h64v64h-64v-64z m0-128h64v64h-64v-64z m0-128h64v64h-64v-64z m0-128h64v64h-64v-64z m-128 0h64v64h-64v-64z m-128 0h64v64h-64v-64z m-128 0h64v64h-64v-64z m-128 0h64v64h-64v-64z\" />\n      <path d=\"M896 64H128c-35.2 0-64 28.8-64 64v768c0 35.2 28.8 64 64 64h768c35.2 0 64-28.8 64-64V128c0-35.2-28.8-64-64-64z m0 800c0 19.2-12.8 32-32 32H160c-19.2 0-32-12.8-32-32V160c0-19.2 12.8-32 32-32h704c19.2 0 32 12.8 32 32v704z\" />\n    </SVGIcon>\n  );\n}\nIconContainer.displayName = 'Container';\n"
  },
  {
    "path": "packages/designer/src/icons/hidden.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconHidden(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M183.423543 657.078213l163.499771-98.484012c-4.233418-14.908548-6.646374-30.585599-6.646374-46.852074 0-94.665033 76.739778-171.404812 171.404812-171.404812 45.983287 0 87.641059 18.20871 118.42518 47.679929l129.791042-78.17957c-73.254398-41.73145-157.866471-65.812915-248.216221-65.812915-192.742792 0-360.068705 108.505249-444.453604 267.715321C96.636944 567.228859 136.301316 616.355743 183.423543 657.078213zM841.253886 367.552144l-164.382884 99.015108c3.934612 14.415314 6.215562 29.513174 6.215562 45.174875 0 94.665033-76.739778 171.404812-171.404812 171.404812-45.361117 0-86.484723-17.747199-117.142977-46.515407l-129.419582 77.955466c72.874751 41.149189 156.893306 64.871473 246.563582 64.871473 192.742792 0 360.068705-108.505249 444.453604-267.717368C927.000805 456.773188 887.794875 408.054603 841.253886 367.552144zM420.280042 511.741104c0 0.550539 0.152473 1.060145 0.161682 1.608637l135.080511-81.366146c-13.065574-7.198959-27.854395-11.658528-43.826158-11.658528C461.20922 420.325068 420.280042 461.254246 420.280042 511.741104zM447.739441 576.947198l69.02098-41.574884L948.364369 275.395234c10.812253-6.512321 14.297634-20.558222 7.785314-31.369452-6.512321-10.812253-20.556175-14.296611-31.368428-7.785314L575.654762 446.537056l0 0-151.20577 91.078345 0 0L75.027787 748.090043c-10.812253 6.512321-14.297634 20.556175-7.785314 31.368428 6.512321 10.812253 20.556175 14.297634 31.369452 7.785314L447.739441 576.947198 447.739441 576.947198zM511.696078 603.157139c50.487881 0 91.416036-40.928155 91.416036-91.416036 0-0.549515-0.152473-1.057075-0.161682-1.605567l-135.079488 81.364099C480.935494 598.699618 495.724315 603.157139 511.696078 603.157139z\" />\n    </SVGIcon>\n  );\n}\nIconHidden.displayName = 'Hidden';\n"
  },
  {
    "path": "packages/designer/src/icons/index.ts",
    "content": "export * from './lock';\nexport * from './hidden';\nexport * from './remove';\nexport * from './setting';\nexport * from './component';\nexport * from './clone';\nexport * from './page';\nexport * from './container';\nexport * from './unlock';\n"
  },
  {
    "path": "packages/designer/src/icons/lock.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconLock(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M704 480v-160c0-105.6-86.4-192-192-192s-192 86.4-192 192v160H160v416h704V480h-160z m-320-160c0-70.4 57.6-128 128-128s128 57.6 128 128v160h-256v-160z m416 512H224v-288h576v288z\" fill=\"#ffffff\" p-id=\"2680\" />\n      <path d=\"M480 768h64v-160h-64z\" fill=\"#ffffff\" p-id=\"2681\" />\n    </SVGIcon>\n  );\n}\nIconLock.displayName = 'IconLock';\n"
  },
  {
    "path": "packages/designer/src/icons/page.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconPage(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M381.6 864H162.4c-6.9 0-12.4 4.6-12.4 10.3v19.3c0 5.7 5.6 10.3 12.4 10.3h219.1c6.8 0 12.4-4.6 12.4-10.3v-19.3c0.1-5.7-5.5-10.3-12.3-10.3zM382 780.6H162c-6.9 0-12.5 4.6-12.5 10.3v19.3c0 5.7 5.6 10.3 12.5 10.3h220c6.9 0 12.5-4.6 12.5-10.3v-19.3c0-5.7-5.6-10.3-12.5-10.3zM162.4 737.2h219.1c6.8 0 12.4-4.6 12.4-10.3v-19.3c0-5.7-5.6-10.3-12.4-10.3H162.4c-6.9 0-12.4 4.6-12.4 10.3v19.3c0 5.7 5.6 10.3 12.4 10.3z\" />\n      <path d=\"M977.1 0H46.9C21 0 0 21 0 46.9v930.2c0 25.9 21 46.9 46.9 46.9h930.2c25.9 0 46.9-21 46.9-46.9V46.9C1024 21 1003 0 977.1 0z m-18.7 911.6c0 25.9-21 46.9-46.9 46.9H112.4c-25.9 0-46.9-21-46.9-47V112.4c0-25.9 21-46.9 46.9-46.9h799.1c25.9 0 46.9 21 46.9 46.9v799.2z\" />\n      <path d=\"M207.9 342.7h608.2c32 0 57.9-25.9 57.9-57.9v-83c0-32-25.9-57.9-57.9-57.9H207.9c-32 0-57.9 25.9-57.9 57.9v83c0 32 25.9 57.9 57.9 57.9zM200 201.8c0-4.4 3.5-7.9 7.9-7.9h608.2c4.4 0 7.9 3.5 7.9 7.9v83c0 4.4-3.5 7.9-7.9 7.9H207.9c-4.4 0-7.9-3.5-7.9-7.9v-83zM806.4 405.7h-277c-37.3 0-67.6 30.2-67.6 67.6v363.2c0 37.3 30.2 67.6 67.6 67.6h277c37.3 0 67.6-30.2 67.6-67.6V473.3c0-37.4-30.2-67.6-67.6-67.6zM824 836.4c0 9.7-7.9 17.6-17.6 17.6h-277c-9.7 0-17.6-7.9-17.6-17.6V473.3c0-9.7 7.9-17.6 17.6-17.6h277c9.7 0 17.6 7.9 17.6 17.6v363.1zM272 649.7c67.4 0 122-54.6 122-122s-54.6-122-122-122-122 54.6-122 122 54.6 122 122 122z m0-204c45.2 0 82 36.8 82 82s-36.8 82-82 82-82-36.8-82-82 36.8-82 82-82z\" />\n    </SVGIcon>\n  );\n}\nIconPage.displayName = 'Page';\n"
  },
  {
    "path": "packages/designer/src/icons/remove.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconRemove(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M224 256v639.84A64 64 0 0 0 287.84 960h448.32A64 64 0 0 0 800 895.84V256h64a32 32 0 1 0 0-64H160a32 32 0 1 0 0 64h64zM384 96c0-17.664 14.496-32 31.904-32h192.192C625.696 64 640 78.208 640 96c0 17.664-14.496 32-31.904 32H415.904A31.872 31.872 0 0 1 384 96z m-96 191.744C288 270.208 302.4 256 320.224 256h383.552C721.6 256 736 270.56 736 287.744v576.512C736 881.792 721.6 896 703.776 896H320.224A32.224 32.224 0 0 1 288 864.256V287.744zM352 352c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z m128 0c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z m128 0c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z\" />\n    </SVGIcon>\n  );\n}\nIconRemove.displayName = 'Remove';\n"
  },
  {
    "path": "packages/designer/src/icons/setting.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconSetting(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M965.824 405.952a180.48 180.48 0 0 1-117.12-85.376 174.464 174.464 0 0 1-16-142.08 22.208 22.208 0 0 0-7.04-23.552 480.576 480.576 0 0 0-153.6-89.216 23.104 23.104 0 0 0-24.32 5.76 182.208 182.208 0 0 1-135.68 57.92 182.208 182.208 0 0 1-133.12-56.64 23.104 23.104 0 0 0-26.88-7.04 478.656 478.656 0 0 0-153.6 89.856 22.208 22.208 0 0 0-7.04 23.552 174.464 174.464 0 0 1-16 141.44A180.48 180.48 0 0 1 58.24 405.952a22.4 22.4 0 0 0-17.28 17.792 455.08 455.08 0 0 0 0 176.512 22.4 22.4 0 0 0 17.28 17.792 180.48 180.48 0 0 1 117.12 84.736c25.408 42.944 31.232 94.592 16 142.08a22.208 22.208 0 0 0 7.04 23.552A480.576 480.576 0 0 0 352 957.632h7.68a23.04 23.04 0 0 0 16.64-7.04 184.128 184.128 0 0 1 266.944 0c6.592 8.96 18.752 11.968 28.8 7.04a479.36 479.36 0 0 0 156.16-88.576 22.208 22.208 0 0 0 7.04-23.552 174.464 174.464 0 0 1 13.44-142.72 180.48 180.48 0 0 1 117.12-84.736 22.4 22.4 0 0 0 17.28-17.792 452.613 452.613 0 0 0 0-176.512 23.04 23.04 0 0 0-17.28-17.792z m-42.88 169.408a218.752 218.752 0 0 0-128 98.112 211.904 211.904 0 0 0-21.76 156.736 415.936 415.936 0 0 1-112 63.68 217.472 217.472 0 0 0-149.12-63.68 221.312 221.312 0 0 0-149.12 63.68 414.592 414.592 0 0 1-112-63.68c12.8-53.12 4.288-109.12-23.68-156.096A218.752 218.752 0 0 0 101.12 575.36a386.176 386.176 0 0 1 0-127.36 218.752 218.752 0 0 0 128-98.112c27.2-47.552 34.944-103.68 21.76-156.8a415.296 415.296 0 0 1 112-63.68A221.44 221.44 0 0 0 512 187.392a218.24 218.24 0 0 0 149.12-57.984 413.952 413.952 0 0 1 112 63.744 211.904 211.904 0 0 0 23.04 156.096 218.752 218.752 0 0 0 128 98.112 386.65 386.65 0 0 1 0 127.36l-1.28 0.64z\" />\n      <path d=\"M512 320.576c-105.984 0-192 85.568-192 191.104a191.552 191.552 0 0 0 192 191.104c106.112 0 192.064-85.568 192.064-191.104a190.72 190.72 0 0 0-56.256-135.168 192.448 192.448 0 0 0-135.744-55.936z m0 318.528c-70.656 0-128-57.088-128-127.424 0-70.4 57.344-127.36 128-127.36 70.72 0 128 56.96 128 127.36 0 33.792-13.44 66.176-37.44 90.112a128.32 128.32 0 0 1-90.496 37.312z\" />\n    </SVGIcon>\n  );\n}\n\nIconSetting.displayName = 'Setting';\n"
  },
  {
    "path": "packages/designer/src/icons/unlock.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconUnlock(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M384 480v-160c0-70.4 57.6-128 128-128s128 57.6 128 128v64h64v-64c0-105.6-86.4-192-192-192s-192 86.4-192 192v160H160v416h704V480H384z m416 352H224v-288h576v288z\" fill=\"#ffffff\" p-id=\"2813\" />\n      <path d=\"M416 736h192v-64h-192z\" fill=\"#ffffff\" p-id=\"2814\" />\n    </SVGIcon>\n  );\n}\nIconUnlock.displayName = 'IconUnlock';\n"
  },
  {
    "path": "packages/designer/src/index.ts",
    "content": "export * from './component-meta';\nexport * from './simulator';\nexport * from './designer';\nexport * from './document';\nexport * from './project';\nexport * from './builtin-simulator';\nexport * from './plugin';\nexport * from './types';\nexport * from './context-menu-actions';\n"
  },
  {
    "path": "packages/designer/src/less-variables.less",
    "content": "/*\n * 基础的 DPL 定义使用了 kuma base 的定义，参考：\n * https://github.com/uxcore/kuma-base/tree/master/variables\n */\n\n/**\n * ===========================================================\n * ==================== Font Family ==========================\n * ===========================================================\n */\n\n/*\n * @font-family: \"STHeiti\", \"Microsoft Yahei\", \"Lucida Grande\", \"Lucida Sans Unicode\", Helvetica, Arial, Verdana, sans-serif;\n */\n\n@font-family: 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial, sans-serif;\n@font-family-code: Monaco, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial,\n  sans-serif;\n\n/**\n * ===========================================================\n * ===================== Color DPL ===========================\n * ===========================================================\n  */\n\n@brand-color-1: rgba(0, 108, 255, 1);\n@brand-color-2: rgba(25, 122, 255, 1);\n@brand-color-3: rgba(0, 96, 229, 1);\n\n@brand-color-1-3: rgba(0, 108, 255, 0.6);\n@brand-color-1-4: rgba(0, 108, 255, 0.4);\n@brand-color-1-5: rgba(0, 108, 255, 0.3);\n@brand-color-1-6: rgba(0, 108, 255, 0.2);\n@brand-color-1-7: rgba(0, 108, 255, 0.1);\n\n@brand-color: @brand-color-1;\n\n@white-alpha-1: rgb(255, 255, 255); // W-1\n@white-alpha-2: rgba(255, 255, 255, 0.8); // W-2 A80\n@white-alpha-3: rgba(255, 255, 255, 0.6); // W-3 A60\n@white-alpha-4: rgba(255, 255, 255, 0.4); // W-4 A40\n@white-alpha-5: rgba(255, 255, 255, 0.3); // W-5 A30\n@white-alpha-6: rgba(255, 255, 255, 0.2); // W-6 A20\n@white-alpha-7: rgba(255, 255, 255, 0.1); // W-7 A10\n@white-alpha-8: rgba(255, 255, 255, 0.06); // W-8 A6\n\n@dark-alpha-1: rgba(0, 0, 0, 1); // D-1 A100\n@dark-alpha-2: rgba(0, 0, 0, 0.8); // D-2 A80\n@dark-alpha-3: rgba(0, 0, 0, 0.6); // D-3 A60\n@dark-alpha-4: rgba(0, 0, 0, 0.4); // D-4 A40\n@dark-alpha-5: rgba(0, 0, 0, 0.3); // D-5 A30\n@dark-alpha-6: rgba(0, 0, 0, 0.2); // D-6 A20\n@dark-alpha-7: rgba(0, 0, 0, 0.1); // D-7 A10\n@dark-alpha-8: rgba(0, 0, 0, 0.06); // D-8 A6\n@dark-alpha-9: rgba(0, 0, 0, 0.04); // D-9 A4\n\n@normal-alpha-1: rgba(31, 56, 88, 1); // N-1 A100\n@normal-alpha-2: rgba(31, 56, 88, 0.8); // N-2 A80\n@normal-alpha-3: rgba(31, 56, 88, 0.6); // N-3 A60\n@normal-alpha-4: rgba(31, 56, 88, 0.4); // N-4 A40\n@normal-alpha-5: rgba(31, 56, 88, 0.3); // N-5 A30\n@normal-alpha-6: rgba(31, 56, 88, 0.2); // N-6 A20\n@normal-alpha-7: rgba(31, 56, 88, 0.1); // N-7 A10\n@normal-alpha-8: rgba(31, 56, 88, 0.06); // N-8 A6\n@normal-alpha-9: rgba(31, 56, 88, 0.04); // N-9 A4\n\n@normal-3: #77879c;\n@normal-4: #a3aebd;\n@normal-5: #bac3cc;\n@normal-6: #d1d7de;\n\n@gray-dark: #333; // N2_4\n@gray: #666; // N2_3\n@gray-light: #999; // N2_2\n@gray-lighter: #ccc; // N2_1\n\n@brand-secondary: #2c2f33; // B2_3\n// 补色\n@brand-complement: #00b3e8; // B3_1\n// 复合\n@brand-comosite: #00c587; // B3_2\n// 浓度\n@brand-deep: #73461d; // B3_3\n\n// F1-1\n@brand-danger: rgb(240, 70, 49);\n// F1-2 (10% white)\n@brand-danger-hover: rgba(240, 70, 49, 0.9);\n// F1-3 (5% black)\n@brand-danger-focus: rgba(240, 70, 49, 0.95);\n\n// F2-1\n@brand-warning: rgb(250, 189, 14);\n// F3-1\n@brand-success: rgb(102, 188, 92);\n// F4-1\n@brand-link: rgb(102, 188, 92);\n// F4-2\n@brand-link-hover: #2e76a6;\n\n// F1-1-7 A10\n@brand-danger-alpha-7: rgba(240, 70, 49, 0.1);\n// F1-1-8 A6\n@brand-danger-alpha-8: rgba(240, 70, 49, 0.8);\n// F2-1-2 A80\n@brand-warning-alpha-2: rgba(250, 189, 14, 0.8);\n// F2-1-7 A10\n@brand-warning-alpha-7: rgba(250, 189, 14, 0.1);\n// F3-1-2 A80\n@brand-success-alpha-2: rgba(102, 188, 92, 0.8);\n// F3-1-7 A10\n@brand-success-alpha-7: rgba(102, 188, 92, 0.1);\n// F4-1-7 A10\n@brand-link-alpha-7: rgba(102, 188, 92, 0.1);\n\n// 文本色\n@text-primary-color: @dark-alpha-3;\n@text-secondary-color: @normal-alpha-3;\n@text-thirdary-color: @dark-alpha-4;\n@text-disabled-color: @normal-alpha-5;\n@text-helper-color: @dark-alpha-4;\n@text-danger-color: @brand-danger;\n@text-ali-color: #ec6c00;\n\n/**\n  * ===========================================================\n  * =================== Shadow Box ============================\n  * ===========================================================\n  */\n\n@box-shadow-1: 0 1px 4px 0 rgba(31, 56, 88, 0.15); // 1 级阴影，物体由原来存在于底面的物体展开，物体和底面关联紧密\n@box-shadow-2: 0 2px 10px 0 rgba(31, 56, 88, 0.15); // 2 级阴影，hover状态，物体层级较高\n@box-shadow-3: 0 4px 15px 0 rgba(31, 56, 88, 0.15); // 3 级阴影，当物体层级高于所有界面元素，弹窗用\n\n/**\n  * ===========================================================\n  * ================= FontSize of Level =======================\n  * ===========================================================\n  */\n\n@fontSize-1: 26px;\n@fontSize-2: 20px;\n@fontSize-3: 16px;\n@fontSize-4: 14px;\n@fontSize-5: 12px;\n\n@fontLineHeight-1: 38px;\n@fontLineHeight-2: 30px;\n@fontLineHeight-3: 26px;\n@fontLineHeight-4: 24px;\n@fontLineHeight-5: 20px;\n\n/**\n  * ===========================================================\n  * ================= FontSize of Level =======================\n  * ===========================================================\n  */\n\n@global-border-radius: 3px;\n@input-border-radius: 3px;\n@popup-border-radius: 6px;\n\n/**\n  * ===========================================================\n  * ===================== Transistion =========================\n  * ===========================================================\n  */\n\n@transition-duration: 0.3s;\n@transition-ease: cubic-bezier(0.23, 1, 0.32, 1);\n@transition-delay: 0s;\n\n/**\n  * ===========================================================\n  * ================ Global Configruations ====================\n  * ===========================================================\n  */\n\n@topPaneHeight: 48px;\n@actionpane-height: 48px;\n@tabPaneWidth: 260px;\n@input-standard-height: 32px;\n@dockpane-width: 48px;\n\n/**\n  * ===========================================================\n  * =================== Deprecated Items ======================\n  * ===========================================================\n  */\n\n@head-bgcolor: @white-alpha-1;\n@pane-bgcolor: @white-alpha-1;\n@pane-dark-bgcolor: @white-alpha-1;\n@pane-bdcolor: @normal-4;\n@blank-bgcolor: @normal-5;\n@title-bgcolor: @white-alpha-1;\n@title-bdcolor: transparent;\n@section-bgcolor: transparent;\n@section-bdcolor: @white-alpha-1;\n@button-bgcolor: @white-alpha-1;\n@button-bdcolor: transparent;\n@button-blue-color: @brand-color;\n@button-blue-hover-color: @brand-color;\n@sub-title-bgcolor: @white-alpha-1;\n@sub-title-bdcolor: transparent;\n@text-color: @text-primary-color;\n@icon-color: @gray;\n@icon-color-active: @gray-light;\n@ghost-bgcolor: @dark-alpha-3;\n@input-bgcolor: transparent;\n@input-bdcolor: @normal-alpha-5;\n@hover-color: #5a99cc;\n@active-color: #5a99cc;\n@disabled-color: #666;\n@setter-popup-bg: rgb(80, 86, 109);\n"
  },
  {
    "path": "packages/designer/src/locale/en-US.json",
    "content": "{\n  \"copy\": \"Copy\",\n  \"remove\": \"Remove\",\n  \"hide\": \"Hide\",\n  \"lock\": \"Lock\",\n  \"unlock\": \"Unlock\",\n  \"Condition Group\": \"Condition Group\",\n  \"No opened document\": \"No opened document, open some document to editing\",\n  \"locked\": \"locked\",\n  \"Item\": \"Item\"\n}\n"
  },
  {
    "path": "packages/designer/src/locale/index.ts",
    "content": "import { createIntl } from '@alilc/lowcode-editor-core';\nimport enUS from './en-US.json';\nimport zhCN from './zh-CN.json';\n\nconst { intl, intlNode, getLocale, setLocale } = createIntl({\n  'en-US': enUS,\n  'zh-CN': zhCN,\n});\n\nexport { intl, intlNode, getLocale, setLocale };\n"
  },
  {
    "path": "packages/designer/src/locale/zh-CN.json",
    "content": "{\n  \"copy\": \"复制\",\n  \"remove\": \"删除\",\n  \"hide\": \"隐藏\",\n  \"lock\": \"锁定\",\n  \"unlock\": \"解锁\",\n  \"Condition Group\": \"条件组\",\n  \"No opened document\": \"没有打开的页面，请选择页面打开编辑\",\n  \"locked\": \"已锁定\",\n  \"Item\": \"项目\"\n}\n"
  },
  {
    "path": "packages/designer/src/plugin/index.ts",
    "content": "export * from './plugin-context';\nexport * from './plugin-manager';\nexport * from './plugin-types';\nexport * from './plugin';\n"
  },
  {
    "path": "packages/designer/src/plugin/plugin-context.ts",
    "content": "/* eslint-disable no-multi-assign */\nimport { engineConfig, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicApiHotkey,\n  IPublicApiProject,\n  IPublicApiSkeleton,\n  IPublicApiSetters,\n  IPublicApiMaterial,\n  IPublicApiEvent,\n  IPublicApiCommon,\n  IPublicModelPluginContext,\n  IPluginPreferenceMananger,\n  IPublicTypePreferenceValueType,\n  IPublicModelEngineConfig,\n  IPublicApiLogger,\n  IPublicApiPlugins,\n  IPublicTypePluginDeclaration,\n  IPublicApiCanvas,\n  IPublicApiWorkspace,\n  IPublicEnumPluginRegisterLevel,\n  IPublicModelWindow,\n  IPublicApiCommonUI,\n} from '@alilc/lowcode-types';\nimport {\n  IPluginContextOptions,\n  ILowCodePluginContextApiAssembler,\n  ILowCodePluginContextPrivate,\n} from './plugin-types';\nimport { isValidPreferenceKey } from './plugin-utils';\n\nexport default class PluginContext implements\n  IPublicModelPluginContext, ILowCodePluginContextPrivate {\n  hotkey: IPublicApiHotkey;\n  project: IPublicApiProject;\n  skeleton: IPublicApiSkeleton;\n  setters: IPublicApiSetters;\n  material: IPublicApiMaterial;\n  event: IPublicApiEvent;\n  config: IPublicModelEngineConfig;\n  common: IPublicApiCommon;\n  logger: IPublicApiLogger;\n  plugins: IPublicApiPlugins;\n  preference: IPluginPreferenceMananger;\n  pluginEvent: IPublicApiEvent;\n  canvas: IPublicApiCanvas;\n  workspace: IPublicApiWorkspace;\n  registerLevel: IPublicEnumPluginRegisterLevel;\n  editorWindow: IPublicModelWindow;\n  commonUI: IPublicApiCommonUI;\n  isPluginRegisteredInWorkspace: false;\n\n  constructor(\n      options: IPluginContextOptions,\n      contextApiAssembler: ILowCodePluginContextApiAssembler,\n    ) {\n    const { pluginName = 'anonymous', meta = {} } = options;\n    contextApiAssembler.assembleApis(this, pluginName, meta);\n    this.pluginEvent = createModuleEventBus(pluginName, 200);\n    const enhancePluginContextHook = engineConfig.get('enhancePluginContextHook');\n    if (enhancePluginContextHook) {\n      enhancePluginContextHook(this);\n    }\n  }\n\n  setPreference(\n    pluginName: string,\n    preferenceDeclaration: IPublicTypePluginDeclaration,\n  ): void {\n    const getPreferenceValue = (\n      key: string,\n      defaultValue?: IPublicTypePreferenceValueType,\n      ): IPublicTypePreferenceValueType | undefined => {\n      if (!isValidPreferenceKey(key, preferenceDeclaration)) {\n        return undefined;\n      }\n      const pluginPreference = this.plugins.getPluginPreference(pluginName) || {};\n      if (pluginPreference[key] === undefined || pluginPreference[key] === null) {\n        return defaultValue;\n      }\n      return pluginPreference[key];\n    };\n\n    this.preference = {\n      getPreferenceValue,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/plugin/plugin-manager.ts",
    "content": "import { engineConfig } from '@alilc/lowcode-editor-core';\nimport { getLogger } from '@alilc/lowcode-utils';\nimport {\n  ILowCodePluginRuntime,\n  ILowCodePluginManager,\n  IPluginContextOptions,\n  PluginPreference,\n  ILowCodePluginContextApiAssembler,\n} from './plugin-types';\nimport { filterValidOptions, isLowCodeRegisterOptions } from './plugin-utils';\nimport { LowCodePluginRuntime } from './plugin';\n// eslint-disable-next-line import/no-named-as-default\nimport LowCodePluginContext from './plugin-context';\nimport { invariant } from '../utils';\nimport sequencify from './sequencify';\nimport semverSatisfies from 'semver/functions/satisfies';\nimport {\n  IPublicTypePluginRegisterOptions,\n  IPublicTypePreferenceValueType,\n  IPublicTypePlugin,\n} from '@alilc/lowcode-types';\n\nconst logger = getLogger({ level: 'warn', bizName: 'designer:pluginManager' });\n\n// 保留的事件前缀\nconst RESERVED_EVENT_PREFIX = ['designer', 'editor', 'skeleton', 'renderer', 'render', 'utils', 'plugin', 'engine', 'editor-core', 'engine-core', 'plugins', 'event', 'events', 'log', 'logger', 'ctx', 'context'];\n\nexport class LowCodePluginManager implements ILowCodePluginManager {\n  private plugins: ILowCodePluginRuntime[] = [];\n\n  pluginsMap: Map<string, ILowCodePluginRuntime> = new Map();\n  pluginContextMap: Map<string, LowCodePluginContext> = new Map();\n\n  private pluginPreference?: PluginPreference = new Map();\n\n  contextApiAssembler: ILowCodePluginContextApiAssembler;\n\n  constructor(contextApiAssembler: ILowCodePluginContextApiAssembler, readonly viewName = 'global') {\n    this.contextApiAssembler = contextApiAssembler;\n  }\n\n  _getLowCodePluginContext = (options: IPluginContextOptions) => {\n    const { pluginName } = options;\n    let context = this.pluginContextMap.get(pluginName);\n    if (!context) {\n      context = new LowCodePluginContext(options, this.contextApiAssembler);\n      this.pluginContextMap.set(pluginName, context);\n    }\n    return context;\n  };\n\n  isEngineVersionMatched(versionExp: string): boolean {\n    const engineVersion = engineConfig.get('ENGINE_VERSION');\n    // ref: https://github.com/npm/node-semver#functions\n    // 1.0.1-beta should match '^1.0.0'\n    return semverSatisfies(engineVersion, versionExp, { includePrerelease: true });\n  }\n\n  /**\n   * register a plugin\n   * @param pluginConfigCreator - a creator function which returns the plugin config\n   * @param options - the plugin options\n   * @param registerOptions - the plugin register options\n   */\n  async register(\n    pluginModel: IPublicTypePlugin,\n    options?: any,\n    registerOptions?: IPublicTypePluginRegisterOptions,\n  ): Promise<void> {\n    // registerOptions maybe in the second place\n    if (isLowCodeRegisterOptions(options)) {\n      registerOptions = options;\n      options = {};\n    }\n    let { pluginName, meta = {} } = pluginModel;\n    const { preferenceDeclaration, engines } = meta;\n    // filter invalid eventPrefix\n    const { eventPrefix } = meta;\n    const isReservedPrefix = RESERVED_EVENT_PREFIX.find((item) => item === eventPrefix);\n    if (isReservedPrefix) {\n      meta.eventPrefix = undefined;\n      logger.warn(`plugin ${pluginName} is trying to use ${eventPrefix} as event prefix, which is a reserved event prefix, please use another one`);\n    }\n    const ctx = this._getLowCodePluginContext({ pluginName, meta });\n    const customFilterValidOptions = engineConfig.get('customPluginFilterOptions', filterValidOptions);\n    const pluginTransducer = engineConfig.get('customPluginTransducer', null);\n    const newPluginModel = pluginTransducer ? await pluginTransducer(pluginModel, ctx, options) : pluginModel;\n    const newOptions = customFilterValidOptions(options, newPluginModel.meta?.preferenceDeclaration);\n    const config = newPluginModel(ctx, newOptions);\n    // compat the legacy way to declare pluginName\n    // @ts-ignore\n    pluginName = pluginName || config.name;\n    invariant(\n      pluginName,\n      'pluginConfigCreator.pluginName required',\n      config,\n    );\n\n    ctx.setPreference(pluginName, preferenceDeclaration);\n\n    const allowOverride = registerOptions?.override === true;\n\n    if (this.pluginsMap.has(pluginName)) {\n      if (!allowOverride) {\n        throw new Error(`Plugin with name ${pluginName} exists`);\n      } else {\n        // clear existing plugin\n        const originalPlugin = this.pluginsMap.get(pluginName);\n        logger.log(\n          'plugin override, originalPlugin with name ',\n          pluginName,\n          ' will be destroyed, config:',\n          originalPlugin?.config,\n        );\n        originalPlugin?.destroy();\n        this.pluginsMap.delete(pluginName);\n      }\n    }\n\n    const engineVersionExp = engines && engines.lowcodeEngine;\n    if (engineVersionExp && !this.isEngineVersionMatched(engineVersionExp)) {\n      throw new Error(`plugin ${pluginName} skipped, engine check failed, current engine version is ${engineConfig.get('ENGINE_VERSION')}, meta.engines.lowcodeEngine is ${engineVersionExp}`);\n    }\n\n    const plugin = new LowCodePluginRuntime(pluginName, this, config, meta);\n    // support initialization of those plugins which registered\n    // after normal initialization by plugin-manager\n    if (registerOptions?.autoInit) {\n      await plugin.init();\n    }\n    this.plugins.push(plugin);\n    this.pluginsMap.set(pluginName, plugin);\n    logger.log(`plugin registered with pluginName: ${pluginName}, config: `, config, 'meta:', meta);\n  }\n\n  get(pluginName: string): ILowCodePluginRuntime | undefined {\n    return this.pluginsMap.get(pluginName);\n  }\n\n  getAll(): ILowCodePluginRuntime[] {\n    return this.plugins;\n  }\n\n  has(pluginName: string): boolean {\n    return this.pluginsMap.has(pluginName);\n  }\n\n  async delete(pluginName: string): Promise<boolean> {\n    const plugin = this.plugins.find(({ name }) => name === pluginName);\n    if (!plugin) return false;\n    await plugin.destroy();\n    const idx = this.plugins.indexOf(plugin);\n    this.plugins.splice(idx, 1);\n    return this.pluginsMap.delete(pluginName);\n  }\n\n  async init(pluginPreference?: PluginPreference) {\n    const pluginNames: string[] = [];\n    const pluginObj: { [name: string]: ILowCodePluginRuntime } = {};\n    this.pluginPreference = pluginPreference;\n    this.plugins.forEach((plugin) => {\n      pluginNames.push(plugin.name);\n      pluginObj[plugin.name] = plugin;\n    });\n    const { missingTasks, sequence } = sequencify(pluginObj, pluginNames);\n    invariant(!missingTasks.length, 'plugin dependency missing', missingTasks);\n    logger.log('load plugin sequence:', sequence);\n\n    for (const pluginName of sequence) {\n      try {\n        await this.pluginsMap.get(pluginName)!.init();\n      } catch (e) /* istanbul ignore next */ {\n        logger.error(\n          `Failed to init plugin:${pluginName}, it maybe affect those plugins which depend on this.`,\n        );\n        logger.error(e);\n      }\n    }\n  }\n\n  async destroy() {\n    for (const plugin of this.plugins) {\n      await plugin.destroy();\n    }\n  }\n\n  get size() {\n    return this.pluginsMap.size;\n  }\n\n  getPluginPreference(pluginName: string): Record<string, IPublicTypePreferenceValueType> | null | undefined {\n    if (!this.pluginPreference) {\n      return null;\n    }\n    return this.pluginPreference.get(pluginName);\n  }\n\n  toProxy() {\n    return new Proxy(this, {\n      get(target, prop, receiver) {\n        if (target.pluginsMap.has(prop as string)) {\n          // 禁用态的插件，直接返回 undefined\n          if (target.pluginsMap.get(prop as string)!.disabled) {\n            return undefined;\n          }\n          return target.pluginsMap.get(prop as string)?.toProxy();\n        }\n        return Reflect.get(target, prop, receiver);\n      },\n    });\n  }\n\n  /* istanbul ignore next */\n  setDisabled(pluginName: string, flag = true) {\n    logger.warn(`plugin:${pluginName} has been set disable:${flag}`);\n    this.pluginsMap.get(pluginName)?.setDisabled(flag);\n  }\n\n  async dispose() {\n    await this.destroy();\n    this.plugins = [];\n    this.pluginsMap.clear();\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/plugin/plugin-types.ts",
    "content": "import {\n  IPublicApiHotkey,\n  IPublicApiProject,\n  IPublicApiSkeleton,\n  IPublicApiSetters,\n  IPublicApiMaterial,\n  IPublicApiEvent,\n  IPublicApiCommon,\n  IPublicApiPlugins,\n  IPublicTypePluginConfig,\n  IPublicApiLogger,\n  IPublicTypePreferenceValueType,\n  IPublicModelEngineConfig,\n  IPublicTypePlugin,\n  IPublicApiCanvas,\n  IPublicApiWorkspace,\n  IPublicTypePluginMeta,\n  IPublicTypePluginRegisterOptions,\n  IPublicModelWindow,\n  IPublicEnumPluginRegisterLevel,\n  IPublicApiCommonUI,\n  IPublicApiCommand,\n} from '@alilc/lowcode-types';\nimport PluginContext from './plugin-context';\n\nexport type PluginPreference = Map<string, Record<string, IPublicTypePreferenceValueType>>;\n\nexport interface ILowCodePluginRuntimeCore {\n  name: string;\n  dep: string[];\n  disabled: boolean;\n  config: IPublicTypePluginConfig;\n  logger: IPublicApiLogger;\n  meta: IPublicTypePluginMeta;\n  init(forceInit?: boolean): void;\n  isInited(): boolean;\n  destroy(): void;\n  toProxy(): any;\n  setDisabled(flag: boolean): void;\n}\n\ninterface ILowCodePluginRuntimeExportsAccessor {\n  [propName: string]: any;\n}\n\n// eslint-disable-next-line max-len\nexport type ILowCodePluginRuntime = ILowCodePluginRuntimeCore & ILowCodePluginRuntimeExportsAccessor;\n\nexport interface ILowCodePluginContextPrivate {\n  set hotkey(hotkey: IPublicApiHotkey);\n  set project(project: IPublicApiProject);\n  set skeleton(skeleton: IPublicApiSkeleton);\n  set setters(setters: IPublicApiSetters);\n  set material(material: IPublicApiMaterial);\n  set event(event: IPublicApiEvent);\n  set config(config: IPublicModelEngineConfig);\n  set common(common: IPublicApiCommon);\n  set plugins(plugins: IPublicApiPlugins);\n  set logger(plugins: IPublicApiLogger);\n  set pluginEvent(event: IPublicApiEvent);\n  set canvas(canvas: IPublicApiCanvas);\n  set workspace(workspace: IPublicApiWorkspace);\n  set editorWindow(window: IPublicModelWindow);\n  set registerLevel(level: IPublicEnumPluginRegisterLevel);\n  set isPluginRegisteredInWorkspace(flag: boolean);\n  set commonUI(commonUI: IPublicApiCommonUI);\n  set command(command: IPublicApiCommand);\n}\nexport interface ILowCodePluginContextApiAssembler {\n  assembleApis(\n    context: ILowCodePluginContextPrivate,\n    pluginName: string,\n    meta: IPublicTypePluginMeta,\n  ): void;\n}\n\ninterface ILowCodePluginManagerPluginAccessor {\n  [pluginName: string]: ILowCodePluginRuntime | any;\n}\n\nexport interface ILowCodePluginManagerCore {\n  register(\n    pluginModel: IPublicTypePlugin,\n    pluginOptions?: any,\n    options?: IPublicTypePluginRegisterOptions,\n  ): Promise<void>;\n  init(pluginPreference?: Map<string, Record<string, IPublicTypePreferenceValueType>>): Promise<void>;\n  get(pluginName: string): ILowCodePluginRuntime | undefined;\n  getAll(): ILowCodePluginRuntime[];\n  has(pluginName: string): boolean;\n  delete(pluginName: string): any;\n  setDisabled(pluginName: string, flag: boolean): void;\n  dispose(): void;\n  _getLowCodePluginContext (options: IPluginContextOptions): PluginContext;\n}\n\nexport type ILowCodePluginManager = ILowCodePluginManagerCore & ILowCodePluginManagerPluginAccessor;\n\nexport interface IPluginContextOptions {\n  pluginName: string;\n  meta?: IPublicTypePluginMeta;\n}\n"
  },
  {
    "path": "packages/designer/src/plugin/plugin-utils.ts",
    "content": "import { isPlainObject } from 'lodash';\nimport { IPublicTypePluginRegisterOptions, IPublicTypePluginDeclaration } from '@alilc/lowcode-types';\n\nexport function isValidPreferenceKey(\n  key: string,\n  preferenceDeclaration: IPublicTypePluginDeclaration,\n): boolean {\n  if (!preferenceDeclaration || !Array.isArray(preferenceDeclaration.properties)) {\n    return false;\n  }\n  return preferenceDeclaration.properties.some((prop) => {\n    return prop.key === key;\n  });\n}\n\nexport function isLowCodeRegisterOptions(opts: any): opts is IPublicTypePluginRegisterOptions {\n  return opts && ('autoInit' in opts || 'override' in opts);\n}\n\nexport function filterValidOptions(\n    opts: any,\n    preferenceDeclaration: IPublicTypePluginDeclaration,\n  ) {\n  if (!opts || !isPlainObject(opts)) return opts;\n  const filteredOpts = {} as any;\n  Object.keys(opts).forEach((key) => {\n    if (isValidPreferenceKey(key, preferenceDeclaration)) {\n      const v = opts[key];\n      if (v !== undefined && v !== null) {\n        filteredOpts[key] = v;\n      }\n    }\n  });\n  return filteredOpts;\n}"
  },
  {
    "path": "packages/designer/src/plugin/plugin.ts",
    "content": "import { getLogger, Logger } from '@alilc/lowcode-utils';\nimport {\n  ILowCodePluginRuntime,\n  ILowCodePluginManager,\n} from './plugin-types';\nimport {\n  IPublicTypePluginConfig,\n  IPublicTypePluginMeta,\n} from '@alilc/lowcode-types';\nimport { invariant } from '../utils';\n\nexport class LowCodePluginRuntime implements ILowCodePluginRuntime {\n  config: IPublicTypePluginConfig;\n\n  logger: Logger;\n\n  private manager: ILowCodePluginManager;\n\n  private _inited: boolean;\n\n  private pluginName: string;\n\n  meta: IPublicTypePluginMeta;\n\n  /**\n   * 标识插件状态，是否被 disabled\n   */\n  private _disabled: boolean;\n\n  constructor(\n    pluginName: string,\n    manager: ILowCodePluginManager,\n    config: IPublicTypePluginConfig,\n    meta: IPublicTypePluginMeta,\n  ) {\n    this.manager = manager;\n    this.config = config;\n    this.pluginName = pluginName;\n    this.meta = meta;\n    this.logger = getLogger({ level: 'warn', bizName: `plugin:${pluginName}` });\n  }\n\n  get name() {\n    return this.pluginName;\n  }\n\n  get dep() {\n    if (typeof this.meta.dependencies === 'string') {\n      return [this.meta.dependencies];\n    }\n    // compat legacy way to declare dependencies\n    const legacyDepValue = (this.config as any).dep;\n    if (typeof legacyDepValue === 'string') {\n      return [legacyDepValue];\n    }\n    return this.meta.dependencies || legacyDepValue || [];\n  }\n\n  get disabled() {\n    return this._disabled;\n  }\n\n  isInited() {\n    return this._inited;\n  }\n\n  async init(forceInit?: boolean) {\n    if (this._inited && !forceInit) return;\n    this.logger.log('method init called');\n    await this.config.init?.call(undefined);\n    this._inited = true;\n  }\n\n  async destroy() {\n    if (!this._inited) return;\n    this.logger.log('method destroy called');\n    await this.config?.destroy?.call(undefined);\n    this._inited = false;\n  }\n\n  setDisabled(flag = true) {\n    this._disabled = flag;\n  }\n\n  toProxy() {\n    invariant(this._inited, 'Could not call toProxy before init');\n    const exports = this.config.exports?.();\n    return new Proxy(this, {\n      get(target, prop, receiver) {\n        if ({}.hasOwnProperty.call(exports, prop)) {\n          return exports?.[prop as string];\n        }\n        return Reflect.get(target, prop, receiver);\n      },\n    });\n  }\n\n  async dispose() {\n    await this.manager.delete(this.name);\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/plugin/sequencify.ts",
    "content": "interface ITaks {\n  [key: string]: {\n    name: string;\n    dep: string[];\n  };\n}\n\nexport function sequence({\n  tasks,\n  names,\n  results,\n  missing,\n  recursive,\n  nest,\n  parentName,\n}: {\n  tasks: ITaks;\n  names: string[];\n  results: string[];\n  missing: string[];\n  recursive: string[][];\n  nest: string[];\n  parentName: string;\n}) {\n  names.forEach((name) => {\n    if (results.indexOf(name) !== -1) {\n      return; // de-dup results\n    }\n    const node = tasks[name];\n    if (!node) {\n      missing.push([parentName, name].filter((d => !!d)).join('.'));\n    } else if (nest.indexOf(name) > -1) {\n      nest.push(name);\n      recursive.push(nest.slice(0));\n      nest.pop();\n    } else if (node.dep.length) {\n      nest.push(name);\n      sequence({\n        tasks,\n        parentName: name,\n        names: node.dep,\n        results,\n        missing,\n        recursive,\n        nest,\n      }); // recurse\n      nest.pop();\n    }\n    results.push(name);\n  });\n}\n\n// tasks: object with keys as task names\n// names: array of task names\nexport default function (tasks: ITaks, names: string[]) {\n  let results: string[] = []; // the final sequence\n  const missing: string[] = []; // missing tasks\n  const recursive: string[][] = []; // recursive task dependencies\n\n  sequence({\n    tasks,\n    names,\n    results,\n    missing,\n    recursive,\n    nest: [],\n  });\n\n  if (missing.length || recursive.length) {\n    results = []; // results are incomplete at best, completely wrong at worst, remove them to avoid confusion\n  }\n\n  return {\n    sequence: results,\n    missingTasks: missing,\n    recursiveDependencies: recursive,\n  };\n}\n"
  },
  {
    "path": "packages/designer/src/project/index.ts",
    "content": "export * from './project';\nexport * from './project-view';\n"
  },
  {
    "path": "packages/designer/src/project/project-view.tsx",
    "content": "import { Component } from 'react';\nimport { observer, engineConfig } from '@alilc/lowcode-editor-core';\nimport { Designer } from '../designer';\nimport { BuiltinSimulatorHostView } from '../builtin-simulator';\nimport './project.less';\n\nexport class BuiltinLoading extends Component {\n  render() {\n    return (\n      <div id=\"engine-loading-wrapper\">\n        <img width=\"154\" height=\"100\" src=\"https://img.alicdn.com/tfs/TB1CmVgayERMeJjy0FcXXc7opXa-308-200.gif\" />\n      </div>\n    );\n  }\n}\n\n@observer\nexport class ProjectView extends Component<{ designer: Designer }> {\n  componentDidMount() {\n    const { designer } = this.props;\n    const { project } = designer;\n\n    project.onRendererReady(() => {\n      this.forceUpdate();\n    });\n  }\n  render() {\n    const { designer } = this.props;\n    const { project, projectSimulatorProps: simulatorProps } = designer;\n    const Simulator = designer.simulatorComponent || BuiltinSimulatorHostView;\n    const Loading = engineConfig.get('loadingComponent', BuiltinLoading);\n\n    return (\n      <div className=\"lc-project\">\n        <div className=\"lc-simulator-shell\">\n          {!project?.simulator?.renderer && <Loading />}\n          <Simulator {...simulatorProps} />\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/project/project.less",
    "content": ".lc-project {\n  position: absolute;\n  top: 0;\n  right: 0;\n  width: 100%;\n  height: 100%;\n  .lc-project-empty {\n    width: 100%;\n    height: 100%;\n    font-size: 16px;\n    text-align: center;\n    background: transparent url(//img.alicdn.com/tfs/TB1xLKQAbj1gK0jSZFuXXcrHpXa-90-90.png) center 30% no-repeat;\n    padding-top: 50%;\n  }\n\n  .lc-simulator {\n    background-color: var(--color-background, rgb(237, 239, 243));\n  }\n\n  .lc-simulator-shell {\n    width: 100%;\n    height: 100%;\n  }\n}\n\n#engine-loading-wrapper {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  height: 100vh;\n}\n"
  },
  {
    "path": "packages/designer/src/project/project.ts",
    "content": "import { obx, computed, makeObservable, action, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { IDesigner } from '../designer';\nimport { DocumentModel, isDocumentModel } from '../document';\nimport type { IDocumentModel } from '../document';\nimport { IPublicEnumTransformStage } from '@alilc/lowcode-types';\nimport type {\n  IBaseApiProject,\n  IPublicTypeProjectSchema,\n  IPublicTypeRootSchema,\n  IPublicTypeComponentsMap,\n  IPublicTypeSimulatorRenderer,\n} from '@alilc/lowcode-types';\nimport { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils';\nimport { ISimulatorHost } from '../simulator';\n\nexport interface IProject extends Omit<IBaseApiProject<\n  IDocumentModel\n>,\n  'simulatorHost' |\n  'importSchema' |\n  'exportSchema' |\n  'openDocument' |\n  'getDocumentById' |\n  'getCurrentDocument' |\n  'addPropsTransducer' |\n  'onRemoveDocument' |\n  'onChangeDocument' |\n  'onSimulatorHostReady' |\n  'onSimulatorRendererReady' |\n  'setI18n' |\n  'setConfig' |\n  'currentDocument' |\n  'selection' |\n  'documents' |\n  'createDocument' |\n  'getDocumentByFileName'\n> {\n\n  get designer(): IDesigner;\n\n  get simulator(): ISimulatorHost | null;\n\n  get currentDocument(): IDocumentModel | null | undefined;\n\n  get documents(): IDocumentModel[];\n\n  get i18n(): {\n    [local: string]: {\n      [key: string]: any;\n    };\n  };\n\n  mountSimulator(simulator: ISimulatorHost): void;\n\n  open(doc?: string | IDocumentModel | IPublicTypeRootSchema): IDocumentModel | null;\n\n  getDocumentByFileName(fileName: string): IDocumentModel | null;\n\n  createDocument(data?: IPublicTypeRootSchema): IDocumentModel;\n\n  load(schema?: IPublicTypeProjectSchema, autoOpen?: boolean | string): void;\n\n  getSchema(\n    stage?: IPublicEnumTransformStage,\n  ): IPublicTypeProjectSchema;\n\n  getDocument(id: string): IDocumentModel | null;\n\n  onCurrentDocumentChange(fn: (doc: IDocumentModel) => void): () => void;\n\n  onSimulatorReady(fn: (args: any) => void): () => void;\n\n  onRendererReady(fn: () => void): () => void;\n\n  /**\n   * 分字段设置储存数据，不记录操作记录\n   */\n  set<T extends keyof IPublicTypeProjectSchema>(key: T, value: IPublicTypeProjectSchema[T]): void;\n  set(key: string, value: unknown): void;\n\n  /**\n   * 分字段获取储存数据\n   */\n  get<T extends keyof IPublicTypeProjectSchema>(key: T): IPublicTypeProjectSchema[T];\n  get<T>(key: string): T;\n  get(key: string): unknown;\n\n  checkExclusive(activeDoc: DocumentModel): void;\n\n  setRendererReady(renderer: IPublicTypeSimulatorRenderer<any, any>): void;\n}\n\nexport class Project implements IProject {\n  private emitter: IEventBus = createModuleEventBus('Project');\n\n  @obx.shallow readonly documents: IDocumentModel[] = [];\n\n  private data: IPublicTypeProjectSchema = {\n    version: '1.0.0',\n    componentsMap: [],\n    componentsTree: [],\n    i18n: {},\n  };\n\n  private _simulator?: ISimulatorHost;\n\n  private isRendererReady: boolean = false;\n\n  /**\n   * 模拟器\n   */\n  get simulator(): ISimulatorHost | null {\n    return this._simulator || null;\n  }\n\n  @computed get currentDocument(): IDocumentModel | null | undefined {\n    return this.documents.find((doc) => doc.active);\n  }\n\n  @obx private _config: any = {};\n  @computed get config(): any {\n    // TODO: parse layout Component\n    return this._config;\n  }\n  set config(value: any) {\n    this._config = value;\n  }\n\n  @obx.ref private _i18n: any = {};\n  @computed get i18n(): any {\n    return this._i18n;\n  }\n  set i18n(value: any) {\n    this._i18n = value || {};\n  }\n\n  private documentsMap = new Map<string, DocumentModel>();\n\n  constructor(readonly designer: IDesigner, schema?: IPublicTypeProjectSchema, readonly viewName = 'global') {\n    makeObservable(this);\n    this.load(schema);\n  }\n\n  private getComponentsMap(): IPublicTypeComponentsMap {\n    return this.documents.reduce<IPublicTypeComponentsMap>((\n      componentsMap: IPublicTypeComponentsMap,\n      curDoc: IDocumentModel,\n    ): IPublicTypeComponentsMap => {\n      const curComponentsMap = curDoc.getComponentsMap();\n      if (Array.isArray(curComponentsMap)) {\n        curComponentsMap.forEach((item) => {\n          const found = componentsMap.find((eItem) => {\n            if (\n              isProCodeComponentType(eItem) &&\n              isProCodeComponentType(item) &&\n              eItem.package === item.package &&\n              eItem.componentName === item.componentName\n            ) {\n              return true;\n            } else if (\n              isLowCodeComponentType(eItem) &&\n              eItem.componentName === item.componentName\n            ) {\n              return true;\n            }\n            return false;\n          });\n          if (found) return;\n          componentsMap.push(item);\n        });\n      }\n      return componentsMap;\n    }, [] as IPublicTypeComponentsMap);\n  }\n\n  /**\n   * 获取项目整体 schema\n   */\n  getSchema(\n    stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save,\n  ): IPublicTypeProjectSchema {\n    return {\n      ...this.data,\n      componentsMap: this.getComponentsMap(),\n      componentsTree: this.documents\n        .filter((doc) => !doc.isBlank())\n        .map((doc) => doc.export(stage) || {} as IPublicTypeRootSchema),\n      i18n: this.i18n,\n    };\n  }\n\n  /**\n   * 替换当前 document 的 schema，并触发渲染器的 render\n   * @param schema\n   */\n  setSchema(schema?: IPublicTypeProjectSchema) {\n    // FIXME: 这里的行为和 getSchema 并不对等，感觉不太对\n    const doc = this.documents.find((doc) => doc.active);\n    doc && schema?.componentsTree[0] && doc.import(schema?.componentsTree[0]);\n    this.simulator?.rerender();\n  }\n\n  /**\n   * 整体设置项目 schema\n   *\n   * @param autoOpen true 自动打开文档 string 指定打开的文件\n   */\n  @action\n  load(schema?: IPublicTypeProjectSchema, autoOpen?: boolean | string) {\n    this.unload();\n    // load new document\n    this.data = {\n      version: '1.0.0',\n      componentsMap: [],\n      componentsTree: [],\n      i18n: {},\n      ...schema,\n    };\n    this.config = schema?.config || this.config;\n    this.i18n = schema?.i18n || this.i18n;\n\n    if (autoOpen) {\n      if (autoOpen === true) {\n        // auto open first document or open a blank page\n        // this.open(this.data.componentsTree[0]);\n        const documentInstances = this.data.componentsTree.map((data) => this.createDocument(data));\n        // TODO: 暂时先读 config tabBar 里的值，后面看整个 layout 结构是否能作为引擎规范\n        if (this.config?.layout?.props?.tabBar?.items?.length > 0) {\n          // slice(1) 这个贼不雅，默认任务 fileName 是类'/fileName'的形式\n          documentInstances\n            .find((i) => i.fileName === this.config.layout.props.tabBar.items[0].path?.slice(1))\n            ?.open();\n        } else {\n          documentInstances[0].open();\n        }\n      } else {\n        // auto open should be string of fileName\n        this.open(autoOpen);\n      }\n    }\n  }\n\n  /**\n   * 卸载当前项目数据\n   */\n  unload() {\n    if (this.documents.length < 1) {\n      return;\n    }\n    for (let i = this.documents.length - 1; i >= 0; i--) {\n      this.documents[i].remove();\n    }\n  }\n\n  removeDocument(doc: IDocumentModel) {\n    const index = this.documents.indexOf(doc);\n    if (index < 0) {\n      return;\n    }\n    this.documents.splice(index, 1);\n    this.documentsMap.delete(doc.id);\n  }\n\n  /**\n   * 分字段设置储存数据，不记录操作记录\n   */\n  set<T extends keyof IPublicTypeProjectSchema>(key: T, value: IPublicTypeProjectSchema[T]): void;\n  set(key: string, value: unknown): void;\n  set(key: string, value: unknown): void {\n    if (key === 'config') {\n      this.config = value;\n    }\n    if (key === 'i18n') {\n      this.i18n = value;\n    }\n    Object.assign(this.data, { [key]: value });\n  }\n\n  /**\n   * 分字段设置储存数据\n   */\n  get<T extends keyof IPublicTypeRootSchema>(key: T): IPublicTypeRootSchema[T];\n  get<T>(key: string): T;\n  get(key: string): unknown;\n  get(key: string): any {\n    if (key === 'config') {\n      return this.config;\n    }\n    if (key === 'i18n') {\n      return this.i18n;\n    }\n    return Reflect.get(this.data, key);\n  }\n\n  getDocument(id: string): IDocumentModel | null {\n    // 此处不能使用 this.documentsMap.get(id)，因为在乐高 rollback 场景，document.id 会被改成其他值\n    return this.documents.find((doc) => doc.id === id) || null;\n  }\n\n  getDocumentByFileName(fileName: string): IDocumentModel | null {\n    return this.documents.find((doc) => doc.fileName === fileName) || null;\n  }\n\n  @action\n  createDocument(data?: IPublicTypeRootSchema): IDocumentModel {\n    const doc = new DocumentModel(this, data || this?.data?.componentsTree?.[0]);\n    this.documents.push(doc);\n    this.documentsMap.set(doc.id, doc);\n    return doc;\n  }\n\n  open(doc?: string | IDocumentModel | IPublicTypeRootSchema): IDocumentModel | null {\n    if (!doc) {\n      const got = this.documents.find((item) => item.isBlank());\n      if (got) {\n        return got.open();\n      }\n      doc = this.createDocument();\n      return doc.open();\n    }\n    if (typeof doc === 'string' || typeof doc === 'number') {\n      const got = this.documents.find((item) => item.fileName === String(doc) || String(item.id) === String(doc));\n      if (got) {\n        return got.open();\n      }\n\n      const data = this.data.componentsTree.find((data) => data.fileName === String(doc));\n      if (data) {\n        doc = this.createDocument(data);\n        return doc.open();\n      }\n\n      return null;\n    } else if (isDocumentModel(doc)) {\n      return doc.open();\n    }\n    //  else if (isPageSchema(doc)) {\n    // 暂时注释掉，影响了 diff 功能\n    // const foundDoc = this.documents.find(curDoc => curDoc?.rootNode?.id && curDoc?.rootNode?.id === doc?.id);\n    // if (foundDoc) {\n    //   foundDoc.remove();\n    // }\n    // }\n\n    doc = this.createDocument(doc);\n    return doc.open();\n  }\n\n  checkExclusive(activeDoc: DocumentModel) {\n    this.documents.forEach((doc) => {\n      if (doc !== activeDoc) {\n        doc.suspense();\n      }\n    });\n    this.emitter.emit('current-document.change', activeDoc);\n  }\n\n  closeOthers(opened: DocumentModel) {\n    this.documents.forEach((doc) => {\n      if (doc !== opened) {\n        doc.close();\n      }\n    });\n  }\n\n  mountSimulator(simulator: ISimulatorHost) {\n    // TODO: 多设备 simulator 支持\n    this._simulator = simulator;\n    this.emitter.emit('lowcode_engine_simulator_ready', simulator);\n  }\n\n  setRendererReady(renderer: any) {\n    this.isRendererReady = true;\n    this.emitter.emit('lowcode_engine_renderer_ready', renderer);\n  }\n\n  onSimulatorReady(fn: (args: any) => void): () => void {\n    if (this._simulator) {\n      fn(this._simulator);\n      return () => {};\n    }\n    this.emitter.on('lowcode_engine_simulator_ready', fn);\n    return () => {\n      this.emitter.removeListener('lowcode_engine_simulator_ready', fn);\n    };\n  }\n\n  onRendererReady(fn: () => void): () => void {\n    if (this.isRendererReady) {\n      fn();\n    }\n    this.emitter.on('lowcode_engine_renderer_ready', fn);\n    return () => {\n      this.emitter.removeListener('lowcode_engine_renderer_ready', fn);\n    };\n  }\n\n  onCurrentDocumentChange(fn: (doc: IDocumentModel) => void): () => void {\n    this.emitter.on('current-document.change', fn);\n    return () => {\n      this.emitter.removeListener('current-document.change', fn);\n    };\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/simulator.ts",
    "content": "import { ComponentType } from 'react';\nimport { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance, IPublicTypePackage } from '@alilc/lowcode-types';\nimport { Point, ScrollTarget, ILocateEvent, IDesigner } from './designer';\nimport { BuiltinSimulatorRenderer } from './builtin-simulator/renderer';\nimport { INode } from './document';\nimport { IProject } from './project';\n\nexport type AutoFit = '100%';\n// eslint-disable-next-line no-redeclare\nexport const AutoFit = '100%';\n\nexport interface IScrollable extends IPublicTypeScrollable {\n}\nexport interface IViewport extends IScrollable {\n\n  /**\n   * 视口大小\n   */\n  width: number;\n  height: number;\n\n  /**\n   * 内容大小\n   */\n  contentWidth: number | AutoFit;\n  contentHeight: number | AutoFit;\n\n  /**\n   * 内容缩放\n   */\n  scale: number;\n\n  /**\n   * 视口矩形维度\n   */\n  readonly bounds: DOMRect;\n\n  /**\n   * 内容矩形维度\n   */\n  readonly contentBounds: DOMRect;\n\n  /**\n   * 视口滚动对象\n   */\n  readonly scrollTarget?: ScrollTarget;\n\n  /**\n   * 是否滚动中\n   */\n  readonly scrolling: boolean;\n\n  /**\n   * 内容当前滚动 X\n   */\n  readonly scrollX: number;\n\n  /**\n   * 内容当前滚动 Y\n   */\n  readonly scrollY: number;\n\n  /**\n   * 全局坐标系转化为本地坐标系\n   */\n  toLocalPoint(point: Point): Point;\n\n  /**\n   * 本地坐标系转化为全局坐标系\n   */\n  toGlobalPoint(point: Point): Point;\n}\n\nexport interface DropContainer {\n  container: INode;\n  instance: IPublicTypeComponentInstance;\n}\n\n/**\n * 模拟器控制进程协议\n */\nexport interface ISimulatorHost<P = object> extends IPublicModelSensor<INode> {\n  readonly isSimulator: true;\n\n  /**\n   * 获得边界维度等信息\n   */\n  readonly viewport: IViewport;\n  readonly contentWindow?: Window;\n  readonly contentDocument?: Document;\n  readonly renderer?: BuiltinSimulatorRenderer;\n\n  readonly project: IProject;\n\n  readonly designer: IDesigner;\n\n  // dependsAsset // like react jQuery lodash\n  // themesAsset\n  // componentsAsset\n  // simulatorUrl //\n  // utils, dataSource, constants 模拟\n  //\n  // later:\n  // layout: ComponentName\n  // 获取区块代码，通过 components 传递，可异步获取\n  // 设置 simulator Props\n  setProps(props: P): void;\n  // 设置单个 Prop\n  set(key: string, value: any): void;\n\n  setSuspense(suspensed: boolean): void;\n\n  // #region ========= drag and drop helpers =============\n\n  /**\n   * 设置文字拖选\n   */\n  setNativeSelection(enableFlag: boolean): void;\n\n  /**\n   * 设置拖拽态\n   */\n  setDraggingState(state: boolean): void;\n\n  /**\n   * 设置拷贝态\n   */\n  setCopyState(state: boolean): void;\n\n  /**\n   * 清除所有态：拖拽态、拷贝态\n   */\n  clearState(): void;\n\n  // #endregion\n\n  /**\n   * 滚动视口到节点\n   */\n  scrollToNode(node: INode, detail?: any): void;\n\n  /**\n   * 描述组件\n   */\n  generateComponentMetadata(componentName: string): IPublicTypeComponentMetadata;\n\n  /**\n   * 根据组件信息获取组件类\n   */\n  getComponent(componentName: string): Component | any;\n\n  /**\n   * 根据节点获取节点的组件实例\n   */\n  getComponentInstances(node: INode): IPublicTypeComponentInstance[] | null;\n\n  /**\n   * 根据 schema 创建组件类\n   */\n  createComponent(schema: IPublicTypeNodeSchema): Component | null;\n\n  /**\n   * 根据节点获取节点的组件运行上下文\n   */\n  getComponentContext(node: INode): object | null;\n\n  getClosestNodeInstance(from: IPublicTypeComponentInstance, specId?: string): IPublicTypeNodeInstance | null;\n\n  computeRect(node: INode): DOMRect | null;\n\n  computeComponentInstanceRect(instance: IPublicTypeComponentInstance, selector?: string): DOMRect | null;\n\n  findDOMNodes(instance: IPublicTypeComponentInstance, selector?: string): Array<Element | Text> | null;\n\n  getDropContainer(e: ILocateEvent): DropContainer | null;\n\n  postEvent(evtName: string, evtData: any): void;\n\n  rerender(): void;\n\n  /**\n   * 销毁\n   */\n  purge(): void;\n\n  setupComponents(library: IPublicTypePackage[]): Promise<void>;\n}\n\nexport function isSimulatorHost(obj: any): obj is ISimulatorHost {\n  return obj && obj.isSimulator;\n}\n\n/**\n * 组件类定义\n */\nexport type Component = ComponentType<any> | object;\n\nexport interface INodeSelector {\n  node: INode;\n  instance?: IPublicTypeComponentInstance;\n}\n"
  },
  {
    "path": "packages/designer/src/transducers/index.ts",
    "content": "import { IPublicTypeTransformedComponentMetadata as Metadata } from '@alilc/lowcode-types';\n\nexport function legacyIssues(metadata: Metadata): Metadata {\n  const { devMode } = metadata;\n  return {\n    ...metadata,\n    devMode: devMode?.replace(/(low|pro)code/, '$1Code') as Metadata['devMode'],\n  };\n}\n\nexport function componentDefaults(metadata: Metadata): Metadata {\n  const { configure, componentName } = metadata;\n  const { component = {} } = configure;\n  if (!component.nestingRule) {\n    let m;\n    // uri match xx.Group set subcontrolling: true, childWhiteList\n    // eslint-disable-next-line no-cond-assign\n    if ((m = /^(.+)\\.Group$/.exec(componentName))) {\n      // component.subControlling = true;\n      component.nestingRule = {\n        childWhitelist: [`${m[1]}`],\n      };\n      // eslint-disable-next-line no-cond-assign\n    } else if ((m = /^(.+)\\.Node$/.exec(componentName))) {\n      // uri match xx.Node set selfControlled: false, parentWhiteList\n      // component.selfControlled = false;\n      component.nestingRule = {\n        parentWhitelist: [`${m[1]}`, componentName],\n      };\n      // eslint-disable-next-line no-cond-assign\n    } else if ((m = /^(.+)\\.(Item|Node|Option)$/.exec(componentName))) {\n      // uri match .Item .Node .Option set parentWhiteList\n      component.nestingRule = {\n        parentWhitelist: [`${m[1]}`],\n      };\n    }\n  }\n  // if (component.isModal == null && /Dialog/.test(componentName)) {\n  //   component.isModal = true;\n  // }\n  return {\n    ...metadata,\n    configure: {\n      ...configure,\n      component,\n    },\n  };\n}\n"
  },
  {
    "path": "packages/designer/src/types/index.ts",
    "content": "import { isFormEvent, compatibleLegaoSchema, getNodeSchemaById, isNodeSchema } from '@alilc/lowcode-utils';\n\nexport type NodeRemoveOptions = {\n  suppressRemoveEvent?: boolean;\n};\n\nexport const utils = {\n  isNodeSchema,\n  isFormEvent,\n  compatibleLegaoSchema,\n  getNodeSchemaById,\n};\n\nexport enum EDITOR_EVENT {\n  NODE_CHILDREN_CHANGE = 'node.children.change',\n\n  NODE_VISIBLE_CHANGE = 'node.visible.change',\n}\n\nexport type Utils = typeof utils;"
  },
  {
    "path": "packages/designer/src/utils/index.ts",
    "content": "export * from './invariant';\nexport * from './slot';\nexport * from './tree';\n"
  },
  {
    "path": "packages/designer/src/utils/invariant.ts",
    "content": "export function invariant(check: any, message: string, thing?: any) {\n  if (!check) {\n    throw new Error(`[designer] Invariant failed: ${message}${thing ? ` in '${thing}'` : ''}`);\n  }\n}\n"
  },
  {
    "path": "packages/designer/src/utils/misc.ts",
    "content": "import Viewport from '../builtin-simulator/viewport';\nimport { ISimulatorHost } from '../simulator';\n\nexport function isElementNode(domNode: Element) {\n  return domNode.nodeType === Node.ELEMENT_NODE;\n}\n\n/**\n * 判断节点是否在 viewport 内，判断依据：只要节点有一部分在 viewport 内，都算 true，其余情况 false\n * @param domNode 待检测的节点\n * @param viewport 画布 viewport\n * @returns 是否在 viewport 内\n */\nexport function isDOMNodeVisible(domNode: Element, viewport: Viewport) {\n  const domNodeRect = domNode.getBoundingClientRect();\n  const { width, height } = viewport.contentBounds;\n  const { left, right, top, bottom, width: nodeWidth, height: nodeHeight } = domNodeRect;\n  return (\n    left >= -nodeWidth &&\n    top >= -nodeHeight &&\n    bottom <= height + nodeHeight &&\n    right <= width + nodeWidth\n  );\n}\n\n/**\n * normalize triggers\n * @param triggers\n */\nexport function normalizeTriggers(triggers: string[]) {\n  return triggers.map((trigger: string) => trigger?.toUpperCase());\n}\n\n/**\n * make a handler that listen all sensors:document, avoid frame lost\n */\n export function makeEventsHandler(\n  boostEvent: MouseEvent | DragEvent,\n  sensors: ISimulatorHost[],\n): (fn: (sdoc: Document) => void) => void {\n  const topDoc = window.document;\n  const sourceDoc = boostEvent.view?.document || topDoc;\n  const docs = new Set<Document>();\n  docs.add(topDoc);\n  docs.add(sourceDoc);\n  sensors.forEach((sim) => {\n    const sdoc = sim.contentDocument;\n    if (sdoc) {\n      docs.add(sdoc);\n    }\n  });\n\n  return (handle: (sdoc: Document) => void) => {\n    docs.forEach((doc) => handle(doc));\n  };\n}"
  },
  {
    "path": "packages/designer/src/utils/slot.ts",
    "content": "import { Node } from '../document/node/node';\n\nexport function includeSlot(node: Node, slotName: string | undefined): boolean {\n  const { slots = [] } = node;\n  return slots.some((slot) => {\n    return slotName && slotName === slot?.getExtraProp('name')?.getAsString();\n  });\n}\n\nexport function removeSlot(node: Node, slotName: string | undefined): boolean {\n  const { slots = [] } = node;\n  return slots.some((slot, idx) => {\n    if (slotName && slotName === slot?.getExtraProp('name')?.getAsString()) {\n      slot.remove();\n      slots.splice(idx, 1);\n      return true;\n    }\n    return false;\n  });\n}\n"
  },
  {
    "path": "packages/designer/src/utils/tree.ts",
    "content": "import { NodeChildren } from '../document/node/node-children';\n\ntype IterableArray = NodeChildren | any[];\n\nexport function foreachReverse(\n  arr: IterableArray,\n  action: (item: any) => void,\n  getter: (arr: IterableArray, index: number) => any,\n  context: any = {},\n) {\n  for (let i = arr.length - 1; i >= 0; i--) {\n    action.call(context, getter(arr, i));\n  }\n}\n"
  },
  {
    "path": "packages/designer/tests/__mocks__/document-model.ts",
    "content": "export class DocumentModel {\n  a = 1;\n  c = {};\n  constructor() {\n    const b = { x: { y: 2 } };\n    const c: number = 2;\n    this.a = b?.x?.y;\n  }\n}\n"
  },
  {
    "path": "packages/designer/tests/__mocks__/node.ts",
    "content": "export class Node2 {\n  a = 1;\n  c = {};\n  constructor() {\n    const b = { x: { y: 2 } };\n    const c: number = 2;\n    this.a = b?.x?.y;\n  }\n}\n"
  },
  {
    "path": "packages/designer/tests/bugs/misc.ts.bak",
    "content": "import set from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport '../fixtures/window';\nimport { Project } from '../../src/project/project';\n// import { Node } from '../../../src/document/node/node';\nimport { Designer } from '../../src/designer/designer';\nimport formSchema from '../fixtures/schema/form';\nimport { getIdsFromSchema, getNodeFromSchemaById } from '../utils';\n\nconst mockCreateSettingEntry = jest.fn();\njest.mock('../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      return {\n        getComponentMeta() {\n          return {\n            getMetadata() {\n              return { configure: { advanced: null } };\n            },\n          };\n        },\n        transformProps(props) { return props; },\n        createSettingEntry: mockCreateSettingEntry,\n        postEvent() {},\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({});\n});\n\nit.todo('在同一个节点下，相同名称的 slot 只能有一个', () => {\n  const project = new Project(designer, {\n    componentsTree: [\n      formSchema,\n    ],\n  });\n  project.open();\n  expect(project).toBeTruthy();\n  const { currentDocument } = project;\n  const { nodesMap } = currentDocument;\n  const ids = getIdsFromSchema(formSchema);\n  const expectedNodeCnt = ids.length;\n  expect(nodesMap.size).toBe(expectedNodeCnt);\n  ids.forEach(id => {\n    expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);\n  });\n\n  const exportSchema = currentDocument?.export(1);\n  expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);\n  expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);\n});\n"
  },
  {
    "path": "packages/designer/tests/bugs/prop-variable-jse.test.ts",
    "content": "import { Editor } from '@alilc/lowcode-editor-core';\nimport { IPublicEnumTransformStage } from '@alilc/lowcode-types';\nimport { isPlainObject, isVariable, isJSBlock } from '@alilc/lowcode-utils';\nimport '../fixtures/window';\nimport { Designer } from '../../src/designer/designer';\nimport { DocumentModel } from '../../src/document/document-model';\nimport { Project } from '../../src/project/project';\nimport formSchema from '../fixtures/schema/form';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\n\n/**\n * bug 背景：\n * Prop 在每次 setValue 时都会调用 dispose 方法用于重新计算子 Prop，我认为在 Node 未完成初始化之前的 dispose 都是\n * 无意义的，所以增加了判断条件来调用 dispose，结果导致了 variable 结果没有正确转成 JSExpression 结构。\n *\n * 因为 propsReducer 的 Init / Upgrade 阶段依然可以更改 props，且此时的 Node 也未完成初始化，不调用 dispose 则导致新的 Prop 结构无法生效\n */\n\nfunction upgradePropsReducer(props: any): any {\n  if (!props || !isPlainObject(props)) {\n    return props;\n  }\n\n  if (isJSBlock(props)) {\n    if (props.value.componentName === 'Slot') {\n      return {\n        type: 'JSSlot',\n        title: (props.value.props as any)?.slotTitle,\n        name: (props.value.props as any)?.slotName,\n        value: props.value.children,\n      };\n    } else {\n      return props.value;\n    }\n  }\n  if (isVariable(props)) {\n    return {\n      type: 'JSExpression',\n      value: props.variable,\n      mock: props.value,\n    };\n  }\n  const newProps: any = {};\n  Object.keys(props).forEach((key) => {\n    if (/^__slot__/.test(key) && props[key] === true) {\n      return;\n    }\n    newProps[key] = upgradePropsReducer(props[key]);\n  });\n  return newProps;\n}\n\ndescribe('Node 方法测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n\n  it('原始 prop 值是 variable 结构，通过一个 propsReducer 转成了 JSExpression 结构', () => {\n    editor = new Editor();\n    designer = new Designer({ editor, shellModelFactory });\n    designer.addPropsReducer(upgradePropsReducer, IPublicEnumTransformStage.Upgrade);\n    project = designer.project;\n    doc = new DocumentModel(project, formSchema);\n\n    const form = doc.getNode('form');\n    expect(form.getPropValue('dataSource')).toEqual({\n      type: 'JSExpression',\n      value: 'state.formData',\n    })\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/bugs/why.md",
    "content": "背景：\n在 UT 的基础上，希望借助一些 Bug 修复来完成场景测试，从而进一步增强稳定性。\n至少在真正的 E2E 测试来临之前，我们保证不会重复犯两次相同的错误。\n\n做法：\nBugs 文件夹每个文件记录一个 bug 修复的场景测试~"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/bem-tools/drag-resize-engine.test.ts",
    "content": "import '../../fixtures/window';\nimport { Editor, globalContext } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../../src/project/project';\nimport { DocumentModel } from '../../../src/document/document-model';\nimport { Designer } from '../../../src/designer/designer';\nimport DragResizeEngine from '../../../src/builtin-simulator/bem-tools/drag-resize-engine';\nimport formSchema from '../../fixtures/schema/form';\nimport { fireEvent, createEvent } from '@testing-library/react';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\ndescribe('DragResizeEngine 测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n  let resizeEngine: DragResizeEngine;\n\n  beforeAll(() => {\n    editor = new Editor();\n    !globalContext.has(Editor) && globalContext.register(editor, Editor);\n  });\n\n  beforeEach(() => {\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    doc = project.createDocument(formSchema);\n    doc.open();\n    resizeEngine = new DragResizeEngine(designer);\n  });\n\n  afterEach(() => {\n    project.unload();\n    project.mountSimulator(undefined);\n    designer.purge();\n    resizeEngine = null;\n    designer = null;\n    project = null;\n  });\n\n  it('from', () => {\n    const resizeStartMockFn = jest.fn();\n    const resizeMockFn = jest.fn();\n    const resizeEndMockFn = jest.fn();\n\n    const offResizeStart = resizeEngine.onResizeStart(resizeStartMockFn);\n    const offResize = resizeEngine.onResize(resizeMockFn);\n    const offResizeEnd = resizeEngine.onResizeEnd(resizeEndMockFn);\n    const boostedNode = doc.getNode('node_k1ow3cbn');\n    const mockBoostFn = jest\n      .fn((e) => {\n        return boostedNode;\n      });\n\n    // do nothing\n    const noop = resizeEngine.from();\n    noop();\n\n    const offFrom = resizeEngine.from(document, 'e', mockBoostFn);\n\n    const mouseDownEvt = createEvent.mouseDown(document, { clientX: 100, clientY: 100 });\n    fireEvent(document, mouseDownEvt);\n\n    expect(resizeStartMockFn).toHaveBeenCalledTimes(1);\n    expect(resizeStartMockFn.mock.calls[0][0]).toBe(mouseDownEvt);\n    expect(resizeStartMockFn.mock.calls[0][1]).toBe('e');\n    expect(resizeStartMockFn.mock.calls[0][2]).toBe(boostedNode);\n    expect(resizeEngine.isDragResizing()).toBeTruthy();\n\n    const mouseMoveEvt1 = createEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n    fireEvent(document, mouseMoveEvt1);\n    expect(resizeMockFn).toHaveBeenCalledTimes(1);\n    expect(resizeMockFn.mock.calls[0][0]).toBe(mouseMoveEvt1);\n    expect(resizeMockFn.mock.calls[0][1]).toBe('e');\n    expect(resizeMockFn.mock.calls[0][2]).toBe(boostedNode);\n    expect(resizeMockFn.mock.calls[0][3]).toBe(8);\n    expect(resizeMockFn.mock.calls[0][4]).toBe(8);\n\n    const mouseMoveEvt2 = createEvent.mouseMove(document, { clientX: 110, clientY: 110 }, 10, 10);\n    fireEvent(document, mouseMoveEvt2);\n    expect(resizeMockFn).toHaveBeenCalledTimes(2);\n    expect(resizeMockFn.mock.calls[1][0]).toBe(mouseMoveEvt2);\n    expect(resizeMockFn.mock.calls[1][1]).toBe('e');\n    expect(resizeMockFn.mock.calls[1][2]).toBe(boostedNode);\n    expect(resizeMockFn.mock.calls[1][3]).toBe(10);\n    expect(resizeMockFn.mock.calls[1][4]).toBe(10);\n\n    const mouseUpEvt = createEvent.mouseUp(document, { clientX: 118, clientY: 118 });\n    fireEvent(document, mouseUpEvt);\n\n    expect(resizeEndMockFn).toHaveBeenCalledTimes(1);\n    expect(resizeEndMockFn.mock.calls[0][0]).toBe(mouseUpEvt);\n    expect(resizeEndMockFn.mock.calls[0][1]).toBe('e');\n    expect(resizeEndMockFn.mock.calls[0][2]).toBe(boostedNode);\n    expect(resizeEngine.isDragResizing()).toBeFalsy();\n\n    offResizeStart();\n    offResize();\n    offResizeEnd();\n    resizeStartMockFn.mockClear();\n    resizeMockFn.mockClear();\n\n    fireEvent.mouseMove(document, { clientX: 100, clientY: 100 });\n    expect(resizeMockFn).not.toHaveBeenCalled();\n\n    offFrom();\n    fireEvent.mouseDown(document, { clientX: 100, clientY: 100 });\n    expect(resizeStartMockFn).not.toHaveBeenCalled();\n  });\n\n  it('has sensor', () => {\n    const mockDoc = document.createElement('iframe').contentWindow?.document;\n    project.mountSimulator({\n      sensorAvailable: true,\n      contentDocument: document,\n    });\n\n    const mockBoostFn = jest\n      .fn((e) => {\n        return doc.getNode('node_k1ow3cbn');\n      });\n\n    const offFrom = resizeEngine.from(document, 'e', mockBoostFn);\n\n    // TODO: 想办法 mock 一个 iframe.currentDocument\n    fireEvent.mouseDown(document, { clientX: 100, clientY: 100 });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/bem-tools/manager.test.tsx",
    "content": "import '../../fixtures/window';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport { Designer } from '../../../src/designer/designer';\nimport { BemToolsManager } from '../../../src/builtin-simulator/bem-tools/manager';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\ndescribe('Node 方法测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  // let project: Project;\n  // let doc: DocumentModel;\n  let manager: BemToolsManager;\n\n  beforeEach(() => {\n    editor = new Editor();\n    designer = new Designer({ editor, shellModelFactory });\n    // project = designer.project;\n    // doc = new DocumentModel(project, formSchema);\n    manager = new BemToolsManager(designer);\n  });\n\n  afterEach(() => {\n    // project.unload();\n    designer.purge();\n    editor = null;\n    designer = null;\n    // project = null;\n  });\n\n  it('addBemTools / removeBemTools / getAllBemTools', () => {\n    manager.addBemTools({\n      name: 't1',\n      item: (props: any) => { return <div />; },\n    });\n    expect(manager.getAllBemTools().length).toBe(1);\n\n    expect(() => {\n      manager.addBemTools({\n        name: 't1',\n        item: (props: any) => { return <div />; },\n      });\n    }).toThrow(/already exists/);\n\n    manager.removeBemTools('t2');\n    expect(manager.getAllBemTools().length).toBe(1);\n\n    manager.removeBemTools('t1');\n    expect(manager.getAllBemTools().length).toBe(0);\n  });\n});"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/host.test.ts",
    "content": "import { IPublicTypePluginMeta } from './../../../../lib/packages/types/src/shell/type/plugin-meta.d';\nimport '../fixtures/window';\nimport {\n  Editor,\n  globalContext,\n  Hotkey as InnerHotkey,\n  Setters as InnerSetters,\n} from '@alilc/lowcode-editor-core';\nimport { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace';\nimport {\n  AssetType,\n} from '@alilc/lowcode-utils';\nimport {\n  IPublicEnumDragObjectType,\n} from '@alilc/lowcode-types';\nimport { Project } from '../../src/project/project';\nimport pageMetadata from '../fixtures/component-metadata/page';\nimport { Designer } from '../../src/designer/designer';\nimport { DocumentModel } from '../../src/document/document-model';\nimport formSchema from '../fixtures/schema/form';\nimport { getMockDocument, getMockWindow, getMockEvent, delayObxTick } from '../utils';\nimport { BuiltinSimulatorHost } from '../../src/builtin-simulator/host';\nimport { fireEvent } from '@testing-library/react';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\nimport { Setters, Workspace } from '@alilc/lowcode-shell';\nimport { ILowCodePluginContextApiAssembler, ILowCodePluginContextPrivate, LowCodePluginManager } from '@alilc/lowcode-designer';\nimport {\n  Skeleton as InnerSkeleton,\n} from '@alilc/lowcode-editor-skeleton';\n\ndescribe('Host 测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n  let host: BuiltinSimulatorHost;\n\n  beforeAll(() => {\n    editor = new Editor();\n    const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      assembleApis: (context: ILowCodePluginContextPrivate, pluginName: string, meta: IPublicTypePluginMeta) => {\n        context.project = project;\n        const eventPrefix = meta?.eventPrefix || 'common';\n        context.workspace = workspace;\n      },\n    };\n    const innerPlugins = new LowCodePluginManager(pluginContextApiAssembler);\n    const innerWorkspace = new InnerWorkspace(() => {}, {});\n    const workspace = new Workspace(innerWorkspace);\n    const innerSkeleton = new InnerSkeleton(editor);\n    editor.set('skeleton' as any, innerSkeleton);\n    editor.set('innerHotkey', new InnerHotkey())\n    editor.set('setters', new Setters(new InnerSetters()));\n    editor.set('innerPlugins' as any, innerPlugins);\n    !globalContext.has(Editor) && globalContext.register(editor, Editor);\n    !globalContext.has('workspace') && globalContext.register(innerWorkspace, 'workspace');\n  });\n\n  beforeEach(() => {\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    designer.createComponentMeta(pageMetadata);\n    doc = project.createDocument(formSchema);\n    host = new BuiltinSimulatorHost(designer.project, designer);\n  });\n\n  afterEach(() => {\n    project.unload();\n    project.mountSimulator(undefined);\n    designer._componentMetasMap.clear();\n    designer.purge();\n    host.purge();\n    designer = null;\n    project = null;\n    host = null;\n  });\n\n  describe('基础方法测试', () => {\n    it('setProps / get / set', async () => {\n      expect(host.currentDocument).toBe(designer.project.currentDocument);\n      expect(host.renderEnv).toBe('default');\n      expect(host.device).toBe('default');\n      expect(host.deviceClassName).toBeUndefined();\n      expect(host.requestHandlersMap).toBeNull();\n      host.setProps({\n        renderEnv: 'rax',\n        device: 'mobile',\n        deviceClassName: 'mobile-rocks',\n        componentsAsset: [\n          {\n            type: AssetType.JSText,\n            content: 'console.log(1)',\n          },\n          {\n            type: AssetType.JSUrl,\n            content: '//path/to/js',\n          },\n        ],\n        theme: {\n          type: AssetType.CSSText,\n          content: '.theme {font-size: 50px;}',\n        },\n        requestHandlersMap: {},\n      });\n      expect(host.renderEnv).toBe('rax');\n      expect(host.device).toBe('mobile');\n      expect(host.deviceClassName).toBe('mobile-rocks');\n      expect(host.componentsAsset).toEqual([\n        {\n          type: AssetType.JSText,\n          content: 'console.log(1)',\n        },\n        {\n          type: AssetType.JSUrl,\n          content: '//path/to/js',\n        },\n      ]);\n      expect(host.theme).toEqual({\n        type: AssetType.CSSText,\n        content: '.theme {font-size: 50px;}',\n      });\n      expect(host.componentsMap).toEqual(designer.componentsMap);\n      expect(host.requestHandlersMap).toEqual({});\n\n      host.set('renderEnv', 'vue');\n      expect(host.renderEnv).toBe('vue');\n\n      expect(host.getComponentContext).toThrow('Method not implemented.');\n    });\n\n    it('connect', () => {\n      const mockFn = jest.fn();\n      const mockRenderer = { isSimulatorRenderer: true };\n      host.connect(mockRenderer, mockFn);\n      expect(host.renderer).toEqual(mockRenderer);\n\n      // await delayObxTick();\n      expect(mockFn).toHaveBeenCalled();\n    });\n\n    it('mountViewport', () => {\n      const mockBounds = {\n        top: 10,\n        bottom: 100,\n        left: 10,\n        right: 100,\n      };\n      host.mountViewport({\n        getBoundingClientRect() {\n          return mockBounds;\n        },\n      });\n      expect(host.viewport.bounds).toEqual(mockBounds);\n    });\n\n    it('autorun', () => {\n      const mockFn = jest.fn();\n      host.autorun(mockFn);\n      expect(mockFn).toHaveBeenCalled();\n    });\n\n    it('purge', () => {\n      host.purge();\n    });\n\n    it('isEnter', () => {\n      const mockBounds = {\n        top: 10,\n        bottom: 100,\n        left: 10,\n        right: 100,\n      };\n      host.mountViewport({\n        getBoundingClientRect() {\n          return mockBounds;\n        },\n      });\n      expect(\n        host.isEnter({\n          globalX: 5,\n          globalY: 50,\n        }),\n      ).toBeFalsy();\n      expect(\n        host.isEnter({\n          globalX: 115,\n          globalY: 50,\n        }),\n      ).toBeFalsy();\n      expect(\n        host.isEnter({\n          globalX: 50,\n          globalY: 50,\n        }),\n      ).toBeTruthy();\n      expect(\n        host.isEnter({\n          globalX: 50,\n          globalY: 5,\n        }),\n      ).toBeFalsy();\n      expect(\n        host.isEnter({\n          globalX: 50,\n          globalY: 150,\n        }),\n      ).toBeFalsy();\n      expect(\n        host.isEnter({\n          globalX: 150,\n          globalY: 150,\n        }),\n      ).toBeFalsy();\n    });\n\n    it('fixEvent', () => {\n      expect(host.fixEvent({ fixed: true, clientX: 1 })).toEqual({ fixed: true, clientX: 1 });\n    });\n\n    it('findDOMNodes', () => {\n      host.connect({\n        findDOMNodes: () => {\n          return null;\n        },\n      }, () => {});\n      expect(host.findDOMNodes()).toBeNull();\n\n      const mockElems = [document.createElement('div')];\n      host.connect({\n        findDOMNodes: () => {\n          return mockElems;\n        },\n      }, () => {});\n      expect(host.findDOMNodes({})).toBe(mockElems);\n      expect(host.findDOMNodes({}, 'xxx')).toBeNull();\n      expect(host.findDOMNodes({}, 'div')).toEqual(mockElems);\n    });\n\n    it('getClosestNodeInstance', () => {\n      const mockFn = jest.fn(() => {\n        return {\n          node: {},\n          nodeId: 'id',\n          docId: 'docId',\n        };\n      });\n      host.connect({\n        getClosestNodeInstance: mockFn,\n      }, () => {});\n      expect(host.getClosestNodeInstance()).toEqual({\n        node: {},\n        nodeId: 'id',\n        docId: 'docId',\n      });\n    });\n\n    it('getNodeInstanceFromElement', () => {\n      expect(host.getNodeInstanceFromElement()).toBeNull();\n      host.getClosestNodeInstance = () => {\n        return null;\n      };\n      expect(host.getNodeInstanceFromElement({})).toBeNull();\n      host.getClosestNodeInstance = () => {\n        return {\n          docId: project.currentDocument.id,\n          nodeId: 'xxx',\n        };\n      };\n      expect(host.getNodeInstanceFromElement({})).toBeTruthy();\n    });\n\n    it('getDropContainer', () => {\n      host.getNodeInstanceFromElement = () => {\n        return {\n          node: doc.rootNode,\n        };\n      };\n      host.getDropContainer({\n        target: {},\n        dragObject: {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [doc.getNode('page')],\n        },\n      });\n    });\n\n    it('getComponentInstances', () => {\n      const mockNode = {\n        document: { id: 'docId' },\n      };\n      host.instancesMap = {\n        docId: {\n          get() {\n            return [{ comp: true }, { comp2: true }];\n          },\n        },\n      };\n      expect(host.getComponentInstances(mockNode))\n        .toEqual([{ comp: true }, { comp2: true }]);\n\n      const mockInst = { inst: true };\n      host.getClosestNodeInstance = () => {\n        return {\n          instance: mockInst,\n        };\n      };\n      expect(host.getComponentInstances(mockNode, { instance: mockInst }))\n        .toEqual([{ comp: true }, { comp2: true }]);\n    });\n\n    it('setNativeSelection / setDraggingState / setCopyState / clearState', () => {\n      const mockFn1 = jest.fn();\n      const mockFn2 = jest.fn();\n      const mockFn3 = jest.fn();\n      const mockFn4 = jest.fn();\n      host.connect({\n        setNativeSelection: mockFn1,\n        setDraggingState: mockFn2,\n        setCopyState: mockFn3,\n        clearState: mockFn4,\n      }, () => {});\n      host.setNativeSelection(true);\n      expect(mockFn1).toHaveBeenCalledWith(true);\n      host.setDraggingState(false);\n      expect(mockFn2).toHaveBeenCalledWith(false);\n      host.setCopyState(true);\n      expect(mockFn3).toHaveBeenCalledWith(true);\n      host.clearState();\n      expect(mockFn4).toHaveBeenCalled();\n    });\n\n    it('sensorAvailable / deactiveSensor', () => {\n      expect(host.sensorAvailable).toBeTruthy();\n      host.deactiveSensor();\n      expect(host.sensing).toBeFalsy();\n    });\n\n    it('getComponent', () => {\n      host.connect({\n        getComponent: () => {\n          return {};\n        },\n      }, () => {});\n      expect(host.getComponent()).toEqual({});\n      expect(host.createComponent()).toBeNull();\n      expect(host.setSuspense()).toBeFalsy();\n    });\n\n    it('setInstance', () => {\n      host.instancesMap = {};\n      host.setInstance('docId1', 'id1', [{}]);\n      expect(host.instancesMap.docId1.get('id1')).toEqual([{}]);\n\n      host.setInstance('docId1', 'id1', null);\n      expect(host.instancesMap.docId1.get('id1')).toBeUndefined();\n    });\n  });\n\n  describe('locate 方法', () => {\n    beforeEach(() => {\n      const mockBounds = {\n        top: 10,\n        bottom: 100,\n        left: 10,\n        right: 100,\n      };\n      host.mountViewport({\n        getBoundingClientRect() {\n          return mockBounds;\n        },\n      });\n    });\n    it('locate，没有 nodes', () => {\n      expect(host.locate({\n        dragObject: {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [],\n        },\n      })).toBeUndefined();\n    });\n    it('locate，没有 document', () => {\n      project.removeDocument(doc);\n      expect(host.locate({\n        dragObject: {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [doc.getNode('page')],\n        },\n      })).toBeNull();\n    });\n    it('notFoundComponent', () => {\n      expect(host.locate({\n        dragObject: {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [doc.getNode('form')],\n        },\n      })).toBeUndefined();\n    })\n    it('locate', () => {\n      host.locate({\n        dragObject: {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [doc.getNode('page')],\n        },\n      });\n    });\n  });\n\n  describe('事件测试', () => {\n    it('setupDragAndClick', () => {});\n    it('setupContextMenu', async () => {\n      const mockDocument = getMockDocument();\n      const mockWindow = getMockWindow(mockDocument);\n      const mockIframe = {\n        contentWindow: mockWindow,\n        contentDocument: mockDocument,\n        dispatchEvent() {},\n      };\n\n      host.set('library', [\n        {\n          package: '@ali/vc-deep',\n          library: 'lib',\n          urls: ['a.js', 'b.js'],\n        },\n      ]);\n\n      host.componentsConsumer.consume(() => {});\n      host.injectionConsumer.consume(() => {});\n      await host.mountContentFrame(mockIframe);\n\n      host.setupContextMenu();\n      host.getNodeInstanceFromElement = () => {\n        return {\n          node: { componentMeta: { componentName: 'Button', getMetadata() { return {} } }, contains() {} },\n        };\n      };\n      const mockFn = jest.fn();\n      host.designer.editor.on('designer.builtinSimulator.contextmenu', mockFn);\n      fireEvent.contextMenu(document, {});\n      // TODO:\n      // expect(mockFn).toHaveBeenCalledWith({ selected: 'Button' });\n    });\n  });\n\n  it('事件测试', async () => {\n    const mockDocument = getMockDocument();\n    const mockWindow = getMockWindow(mockDocument);\n    const mockIframe = {\n      contentWindow: mockWindow,\n      contentDocument: mockDocument,\n      dispatchEvent() {},\n    };\n\n    // 非法分支测试\n    host.mountContentFrame();\n    expect(host._iframe).toBeUndefined();\n\n    host.set('library', [\n      {\n        package: '@ali/vc-deep',\n        library: 'lib',\n        urls: ['a.js', 'b.js'],\n      },\n    ]);\n\n    host.componentsConsumer.consume(() => {});\n    host.injectionConsumer.consume(() => {});\n    await host.mountContentFrame(mockIframe);\n\n    expect(host.contentWindow).toBe(mockWindow);\n\n    mockDocument.triggerEventListener(\n      'mouseover',\n      getMockEvent(mockDocument.createElement('div')),\n      host,\n    );\n    mockDocument.triggerEventListener(\n      'mouseleave',\n      getMockEvent(mockDocument.createElement('div')),\n      host,\n    );\n    mockDocument.triggerEventListener(\n      'mousedown',\n      getMockEvent(mockDocument.createElement('div')),\n      host,\n    );\n    mockDocument.triggerEventListener(\n      'mouseup',\n      getMockEvent(mockDocument.createElement('div')),\n      host,\n    );\n    mockDocument.triggerEventListener(\n      'mousemove',\n      getMockEvent(mockDocument.createElement('div')),\n      host,\n    );\n    mockDocument.triggerEventListener('click', getMockEvent(document.createElement('input')), host);\n    mockDocument.triggerEventListener(\n      'dblclick',\n      getMockEvent(mockDocument.createElement('div')),\n      host,\n    );\n    mockDocument.triggerEventListener(\n      'contextmenu',\n      getMockEvent(mockDocument.createElement('div')),\n      host,\n    );\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/renderer.test.tsx",
    "content": "import React from 'react';\nimport set from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport '../fixtures/window';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../src/project/project';\nimport { Node } from '../../src/document/node/node';\nimport TestRenderer from 'react-test-renderer';\nimport { configure, render, mount } from 'enzyme';\nimport Adapter from 'enzyme-adapter-react-16';\nimport { Designer } from '../../src/designer/designer';\nimport formSchema from '../fixtures/schema/form';\nimport { getMockRenderer } from '../utils';\nimport { isSimulatorRenderer } from '../../src/builtin-simulator/renderer';\n\n\ndescribe('renderer 测试', () => {\n  it('renderer', () => {\n    expect(isSimulatorRenderer(getMockRenderer())).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/resource-consumer.test.ts",
    "content": "import ResourceConsumer from '../../src/builtin-simulator/resource-consumer';\nimport { delayObxTick, delay } from '../utils';\n\nit('ResourceConsumer 测试，先消费再监听', async () => {\n  const con = new ResourceConsumer(() => ({ a: 1, b: 2 }));\n\n  const mockFn = jest.fn();\n  con.consume((data) => {\n    mockFn(data);\n  });\n\n  await delay(1000);\n\n  expect(mockFn).toHaveBeenCalledWith({ a: 1, b: 2 });\n  con.consume(() => {});\n\n  await con.waitFirstConsume();\n\n  con.dispose();\n});\n\nit('ResourceConsumer 测试，先消费再监听，isSimulatorRenderer', async () => {\n  const mockFn = jest.fn();\n  const con = new ResourceConsumer(() => ({ a: 1, b: 2 }), () => {\n    const o = { a: 3, b: 4 };\n    mockFn(o);\n    return o;\n  });\n\n  con.consume({ isSimulatorRenderer: true });\n\n  await delay(1000);\n\n  expect(mockFn).toHaveBeenCalledWith({ a: 3, b: 4 });\n  con.consume(() => {});\n\n  await con.waitFirstConsume();\n});\n\nit('ResourceConsumer 测试，先消费再监听，isSimulatorRenderer，没有 consume', async () => {\n  const mockFn = jest.fn();\n  const con = new ResourceConsumer(() => ({ a: 1, b: 2 }));\n\n  con.consume({ isSimulatorRenderer: true });\n});\n\nit('ResourceConsumer 测试，先监听再消费', async () => {\n  const con = new ResourceConsumer(() => ({ a: 1, b: 2 }));\n\n  con.waitFirstConsume();\n\n  const mockFn = jest.fn();\n  con.consume((data) => {\n    mockFn(data);\n  });\n\n  await delay(1000);\n\n  expect(mockFn).toHaveBeenCalledWith({ a: 1, b: 2 });\n});\n"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts",
    "content": "import '../../fixtures/window';\nimport PropTypes from 'prop-types';\nimport { LowcodeTypes, parseMetadata, parseProps } from '../../../src/builtin-simulator/utils/parse-metadata';\nimport { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret';\n\ndescribe('parseMetadata', () => {\n  it('parseMetadata', async () => {\n    const md1 = parseMetadata('Div');\n    const md2 = parseMetadata({ componentName: 'Div' });\n  });\n  it('LowcodeTypes.shape', async () => {\n    const result = (window as any).PropTypes.shape()\n    expect(result).toBeDefined();\n  });\n});\n\ndescribe('LowcodeTypes basic type validators', () => {\n  it('should validate string types', () => {\n    const stringValidator = LowcodeTypes.string;\n    // 对 stringValidator 进行测试\n    const props = { testProp: 'This is a string' };\n    const propName = 'testProp';\n    const componentName = 'TestComponent';\n\n    const result = stringValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n    expect(result).toBeNull(); // No error for valid string\n  });\n\n  it('should fail with a non-string type', () => {\n    const stringValidator = LowcodeTypes.string;\n    const props = { testProp: 42 };\n    const propName = 'testProp';\n    const componentName = 'TestComponent';\n\n    const result = stringValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n    expect(result).toBeInstanceOf(Error); // Error for non-string type\n    expect(result.message).toContain('Invalid prop `testProp` of type `number` supplied to `TestComponent`, expected `string`.');\n  });\n\n  it('should pass with a valid number', () => {\n    const numberValidator = LowcodeTypes.number;\n    const props = { testProp: 42 };\n    const propName = 'testProp';\n    const componentName = 'TestComponent';\n\n    const result = numberValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n    expect(result).toBeNull(); // No error for valid number\n  });\n\n  it('should fail with a non-number type', () => {\n    const numberValidator = LowcodeTypes.number;\n    const props = { testProp: 'Not a number' };\n    const propName = 'testProp';\n    const componentName = 'TestComponent';\n\n    const result = numberValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n    expect(result).toBeInstanceOf(Error); // Error for non-number type\n    expect(result.message).toContain('Invalid prop `testProp` of type `string` supplied to `TestComponent`, expected `number`.');\n  });\n});\n\ndescribe('Custom type constructors', () => {\n  it('should create a custom type validator using define', () => {\n    const customType = LowcodeTypes.define(PropTypes.string, 'customType');\n    const props = { testProp: 'This is a string' };\n    const propName = 'testProp';\n    const componentName = 'TestComponent';\n\n    // 测试有效值\n    const validResult = customType(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n    expect(validResult).toBeNull(); // No error for valid string\n\n    // 测试无效值\n    const invalidProps = { testProp: 42 };\n    const invalidResult = customType(invalidProps, propName, componentName, 'prop', null, ReactPropTypesSecret);\n    expect(invalidResult).toBeInstanceOf(Error); // Error for non-string type\n\n    // 验证 lowcodeType 属性\n    expect(customType.lowcodeType).toEqual('customType');\n\n    // 验证 isRequired 属性\n    const requiredResult = customType.isRequired(invalidProps, propName, componentName, 'prop', null, ReactPropTypesSecret);\n    expect(requiredResult).toBeInstanceOf(Error); // Error for non-string type\n  });\n});\n\n\ndescribe('Advanced type constructors', () => {\n  describe('oneOf Type Validator', () => {\n    const oneOfValidator = LowcodeTypes.oneOf(['red', 'green', 'blue']);\n    const propName = 'color';\n    const componentName = 'ColorPicker';\n\n    it('should pass with a valid value', () => {\n      const props = { color: 'red' };\n      const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n      expect(result).toBeNull(); // No error for valid value\n    });\n\n    it('should fail with an invalid value', () => {\n      const props = { color: 'yellow' };\n      const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n      expect(result).toBeInstanceOf(Error); // Error for invalid value\n      expect(result.message).toContain(`Invalid prop \\`${propName}\\` of value \\`yellow\\` supplied to \\`${componentName}\\`, expected one of [\"red\",\"green\",\"blue\"].`);\n    });\n\n    it('should fail with a non-existing value', () => {\n      const props = { color: 'others' };\n      const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret);\n      expect(result).toBeInstanceOf(Error); // Error for non-existing value\n      expect(result.message).toContain(`Invalid prop \\`${propName}\\` of value \\`others\\` supplied to \\`${componentName}\\`, expected one of [\"red\",\"green\",\"blue\"].`);\n    });\n  });\n});\n\n\ndescribe('parseProps function', () => {\n  it('should correctly parse propTypes and defaultProps', () => {\n    const component = {\n      propTypes: {\n        name: LowcodeTypes.string,\n        age: LowcodeTypes.number,\n      },\n      defaultProps: {\n        name: 'John Doe',\n        age: 30,\n      },\n    };\n    const parsedProps = parseProps(component);\n\n    // 测试结果长度\n    expect(parsedProps.length).toBe(2);\n\n    // 测试 name 属性\n    const nameProp: any = parsedProps.find(prop => prop.name === 'name');\n    expect(nameProp).toBeDefined();\n    expect(nameProp.propType).toEqual('string');\n    expect(nameProp.defaultValue).toEqual('John Doe');\n\n    // 测试 age 属性\n    const ageProp: any = parsedProps.find(prop => prop.name === 'age');\n    expect(ageProp).toBeDefined();\n    expect(ageProp.propType).toEqual('number');\n    expect(ageProp.defaultValue).toEqual(30);\n  });\n});\n\ndescribe('parseProps function', () => {\n  it('should correctly parse propTypes and defaultProps', () => {\n    const component = {\n      propTypes: {\n        name: LowcodeTypes.string,\n        age: LowcodeTypes.number,\n      },\n      defaultProps: {\n        name: 'John Doe',\n        age: 30,\n      },\n    };\n    const parsedProps = parseProps(component);\n\n    // 测试结果长度\n    expect(parsedProps.length).toBe(2);\n\n    // 测试 name 属性\n    const nameProp: any = parsedProps.find(prop => prop.name === 'name');\n    expect(nameProp).toBeDefined();\n    expect(nameProp.propType).toEqual('string');\n    expect(nameProp.defaultValue).toEqual('John Doe');\n\n    // 测试 age 属性\n    const ageProp: any = parsedProps.find(prop => prop.name === 'age');\n    expect(ageProp).toBeDefined();\n    expect(ageProp.propType).toEqual('number');\n    expect(ageProp.defaultValue).toEqual(30);\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/utils/path.test.ts",
    "content": "import {\n  generateComponentName,\n  getNormalizedImportPath,\n  isPackagePath,\n  toTitleCase,\n  makeRelativePath,\n  removeVersion,\n  resolveAbsoluatePath,\n  joinPath,\n} from '../../../src/builtin-simulator/utils/path';\n\ndescribe('builtin-simulator/utils/path 测试', () => {\n  it('isPackagePath', () => {\n    expect(isPackagePath('a')).toBeTruthy();\n    expect(isPackagePath('@ali/a')).toBeTruthy();\n    expect(isPackagePath('@alife/a')).toBeTruthy();\n    expect(isPackagePath('a.b')).toBeTruthy();\n    expect(isPackagePath('./a')).toBeFalsy();\n    expect(isPackagePath('../a')).toBeFalsy();\n    expect(isPackagePath('/a')).toBeFalsy();\n  });\n\n  it('toTitleCase', () => {\n    expect(toTitleCase('a')).toBe('A');\n    expect(toTitleCase('a_b')).toBe('AB');\n    expect(toTitleCase('a b')).toBe('AB');\n    expect(toTitleCase('a-b')).toBe('AB');\n    expect(toTitleCase('a.b')).toBe('AB');\n    expect(toTitleCase('a.b.cx')).toBe('ABCx');\n  });\n\n  it('generateComponentName', () => {\n    expect(generateComponentName('a/index.js')).toBe('A');\n    expect(generateComponentName('a_b/index.js')).toBe('AB');\n    expect(generateComponentName('a_b/index.web.js')).toBe('AB');\n    expect(generateComponentName('a_b/index.xxx.js')).toBe('AB');\n    expect(generateComponentName('a_b')).toBe('AB');\n    expect(generateComponentName('')).toBe('Component');\n  });\n\n  it('getNormalizedImportPath', () => {\n    expect(getNormalizedImportPath('/a')).toBe('/a');\n    expect(getNormalizedImportPath('/a/')).toBe('/a/');\n    expect(getNormalizedImportPath('/a/index.js')).toBe('/a');\n    expect(getNormalizedImportPath('/a/index.ts')).toBe('/a');\n    expect(getNormalizedImportPath('/a/index.jsx')).toBe('/a');\n    expect(getNormalizedImportPath('/a/index.tsx')).toBe('/a');\n    expect(getNormalizedImportPath('/a/index.x')).toBe('/a/index.x');\n  });\n\n  it('makeRelativePath', () => {\n    expect(makeRelativePath('/a/b/c', '/a/b')).toBe('c');\n    expect(makeRelativePath('a/b/c', '/a/c')).toBe('a/b/c');\n    expect(makeRelativePath('/a/b/c', '/a/c')).toBe('./b/c');\n    expect(makeRelativePath('/a/b/c', '/a/c/d')).toBe('../b/c');\n  });\n\n  it('resolveAbsoluatePath', () => {\n    expect(resolveAbsoluatePath('/a/b/c', '/a')).toBe('/a/b/c');\n    expect(resolveAbsoluatePath('@ali/fe', '/a')).toBe('@ali/fe');\n    expect(resolveAbsoluatePath('./a/b', '/c')).toBe('/c/a/b');\n    expect(resolveAbsoluatePath('./a/b/d', '/c')).toBe('/c/a/b/d');\n    expect(resolveAbsoluatePath('../a/b', '/c')).toBe('/a/b');\n    expect(resolveAbsoluatePath('../a/b/d', '/c')).toBe('/a/b/d');\n    expect(resolveAbsoluatePath('../../a', 'c')).toBe('../a');\n  });\n\n  it('joinPath', () => {\n    expect(joinPath('/a', 'b', 'c')).toBe('/a/b/c');\n    expect(joinPath('a', 'b', 'c')).toBe('./a/b/c');\n  });\n\n  it('removeVersion', () => {\n    expect(removeVersion('@ali/fe')).toBe('@ali/fe');\n    expect(removeVersion('@ali/fe@1.0.0/index')).toBe('@ali/fe/index');\n    expect(removeVersion('haha')).toBe('haha');\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/utils/throttle.test.ts",
    "content": "import '../../fixtures/disable-raf';\nimport { throttle } from '../../../src/builtin-simulator/utils/throttle';\n\nconst delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));\n\nconst cb = jest.fn();\n\ndescribe('throttle', () => {\n  it('simple', async () => {\n    const fn = throttle(cb, 1000);\n    fn();\n\n    expect(cb).toBeCalledTimes(1);\n\n    await delay(200);\n    fn();\n\n    await delay(400);\n    fn();\n    expect(cb).toBeCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/builtin-simulator/viewport.test.ts",
    "content": "import '../fixtures/window';\nimport { getMockWindow, getMockElement, delay } from '../utils';\nimport { Editor, globalContext } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../src/project/project';\nimport { DocumentModel } from '../../src/document/document-model';\nimport Viewport from '../../src/builtin-simulator/viewport';\nimport { Designer } from '../../src/designer/designer';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\n\n\ndescribe('Viewport 测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n  let viewport: Viewport;\n  let viewportElem;\n\n  beforeAll(() => {\n    editor = new Editor();\n    !globalContext.has(Editor) && globalContext.register(editor, Editor);\n\n    window.DOMRect = class {\n      constructor(top, left, width, height) {\n        return { top, left, width, height };\n      }\n    };\n  });\n\n  beforeEach(() => {\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    // doc = project.createDocument(formSchema);\n  });\n\n  afterEach(() => {\n    project.unload();\n    // project.mountSimulator(undefined);\n    designer.purge();\n    designer = null;\n    project = null;\n    viewport = null;\n  });\n\n  it('基本函数测试', async () => {\n    const rect = {\n      width: 500,\n      height: 500,\n      top: 100,\n      bottom: 500,\n      left: 100,\n      right: 500,\n    };\n    viewportElem = getMockElement('div', rect);\n    viewport = new Viewport();\n    viewport.mount();\n    expect(viewport.viewportElement).toBeUndefined();\n    expect(viewport.width).toBe(1000);\n    expect(viewport.height).toBe(600);\n    expect(viewport.toGlobalPoint({ left: 0, top: 0 })).toEqual({ left: 0, top: 0 });\n    expect(viewport.toLocalPoint({ left: 0, top: 0 })).toEqual({ left: 0, top: 0 });\n\n    viewport.mount(viewportElem);\n    expect(viewport.viewportElement).toBe(viewportElem);\n\n    expect(viewport.bounds).toEqual(rect);\n    expect(viewport.contentBounds).toEqual({ top: 0, left: 0, width: 500, height: 500 });\n    expect(viewport.rect).toEqual(rect);\n\n    expect(viewport.width).toBe(500);\n    expect(viewport.contentWidth).toBe('100%');\n    expect(viewport.height).toBe(500);\n    expect(viewport.contentHeight).toBe('100%');\n\n    await delay(100);\n    viewportElem.setWidth(300);\n    viewport.width = 300;\n    expect(viewport.width).toBe(300);\n\n    await delay(100);\n    viewportElem.setHeight(300);\n    viewport.height = 300;\n    expect(viewport.height).toBe(300);\n\n    viewport.contentWidth = 200;\n    expect(viewport.contentWidth).toBe(200);\n\n    viewport.contentHeight = 200;\n    expect(viewport.contentHeight).toBe(200);\n  });\n\n  it('scale', () => {\n    const rect = {\n      width: 500,\n      height: 500,\n      top: 100,\n      bottom: 500,\n      left: 100,\n      right: 500,\n    };\n    viewportElem = getMockElement('div', rect);\n    viewport = new Viewport();\n    viewport.mount(viewportElem);\n\n    expect(viewport.scale).toBe(1);\n    viewport.scale = 2;\n    expect(viewport.scale).toBe(2);\n\n    expect(viewport.contentWidth).toBe(500 / 2);\n    expect(viewport.contentHeight).toBe(500 / 2);\n\n    viewport.width = 300;\n    viewportElem.setWidth(300);\n    expect(viewport.contentWidth).toBe(300 / 2);\n\n    viewport.height = 300;\n    viewportElem.setHeight(300);\n    expect(viewport.contentHeight).toBe(300 / 2);\n\n    expect(() => { viewport.scale = NaN; }).toThrow();\n    expect(() => { viewport.scale = -1; }).toThrow();\n  });\n\n  it('setScrollTarget / scrollTarget / scrolling', async () => {\n    const rect = {\n      width: 500,\n      height: 500,\n      top: 100,\n      bottom: 500,\n      left: 100,\n      right: 500,\n    };\n    viewportElem = getMockElement('div', rect);\n    viewport = new Viewport();\n    viewport.mount(viewportElem);\n\n    const mockWindow = getMockWindow();\n    viewport.setScrollTarget(mockWindow);\n    // TODO: 待 mock\n    viewport.scrollTarget;\n    // expect(viewport.scrollTarget).toBe(mockWindow);\n\n    // mock scrollTarget\n    // viewport._scrollTarget = { left: 0, top: 0 };\n    // viewport._scrollTarget.left = 123;\n    // viewport._scrollTarget.top = 1234;\n    mockWindow.triggerEventListener('scroll');\n    expect(viewport.scrolling).toBeTruthy();\n    // TODO: 待 mock\n    viewport.scrollX;\n    viewport.scrollY;\n    // expect(viewport.scrollX).toBe(123);\n    // expect(viewport.scrollY).toBe(1234);\n    await delay(100);\n    expect(viewport.scrolling).toBeFalsy();\n\n    mockWindow.triggerEventListener('resize');\n  });\n\n  it('toGlobalPoint / toLocalPoint', () => {\n    const rect = {\n      width: 500,\n      height: 500,\n      top: 100,\n      bottom: 500,\n      left: 100,\n      right: 500,\n    };\n    viewportElem = getMockElement('div', rect);\n    viewport = new Viewport();\n    viewport.mount(viewportElem);\n\n    expect(viewport.toGlobalPoint({ clientX: 100, clientY: 100 })).toEqual({ clientX: 200, clientY: 200 });\n    expect(viewport.toLocalPoint({ clientX: 200, clientY: 200 })).toEqual({ clientX: 100, clientY: 100 });\n\n    viewport.scale = 2;\n    expect(viewport.toGlobalPoint({ clientX: 100, clientY: 100 })).toEqual({ clientX: 300, clientY: 300 });\n    expect(viewport.toLocalPoint({ clientX: 300, clientY: 300 })).toEqual({ clientX: 100, clientY: 100 });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/active-tracker.test.ts",
    "content": "import '../fixtures/window';\nimport { ActiveTracker } from '../../src/designer/active-tracker';\n\nit('ActiveTracker 测试，Node', () => {\n  const tracker = new ActiveTracker();\n\n  const mockFn = jest.fn();\n  const mockNode = { isNode: true };\n  const off = tracker.onChange(mockFn);\n\n  tracker.track(mockNode);\n  expect(mockFn).toHaveBeenCalledWith({ node: mockNode });\n\n  expect(tracker.currentNode).toBe(mockNode);\n\n  off();\n  mockFn.mockClear();\n  tracker.track(mockNode);\n  expect(mockFn).not.toHaveBeenCalled();\n});\n\nit('ActiveTracker 测试，ActiveTarget', () => {\n  const tracker = new ActiveTracker();\n\n  const mockFn = jest.fn();\n  const mockNode = { isNode: true };\n  const off = tracker.onChange(mockFn);\n  const mockTarget = { node: mockNode, detail: { isDetail: true }, instance: { isInstance: true } };\n\n  tracker.track(mockTarget);\n  expect(mockFn).toHaveBeenCalledWith(mockTarget);\n\n  expect(tracker.currentNode).toBe(mockNode);\n  expect(tracker.detail).toEqual({ isDetail: true });\n  expect(tracker.instance).toEqual({ isInstance: true });\n\n  off();\n  mockFn.mockClear();\n  tracker.track(mockNode);\n  expect(mockFn).not.toHaveBeenCalled();\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/builtin-hotkey.test.ts",
    "content": "import '../fixtures/window';\nimport {\n  Editor,\n  globalContext,\n  Hotkey as InnerHotkey,\n} from '@alilc/lowcode-editor-core';\nimport { Designer } from '../../src/designer/designer';\nimport formSchema from '../fixtures/schema/form';\nimport { fireEvent } from '@testing-library/react';\nimport { builtinHotkey } from '../../../engine/src/inner-plugins/builtin-hotkey';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\nimport { ILowCodePluginContextPrivate, LowCodePluginManager } from '@alilc/lowcode-designer';\nimport { IPublicApiPlugins } from '@alilc/lowcode-types';\nimport { Logger, Project, Canvas } from '@alilc/lowcode-shell';\nimport { Workspace } from '@alilc/lowcode-workspace';\n\nconst editor = new Editor();\nconst workspace = new Workspace();\n\nlet designer: Designer;\n\n// keyCode 对应表：https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode\n// hotkey 模块底层用的 keyCode，所以还不能用 key / code 测试\ndescribe('快捷键测试', () => {\n  let pluginManager: LowCodePluginManager;\n  let project: any = {};\n  beforeAll(() => {\n    return new Promise((resolve, reject) => {\n      const hotkey: any = new InnerHotkey();\n      const logger = new Logger({ level: 'warn', bizName: 'common' });\n      const contextApiAssembler = {\n        assembleApis(context: ILowCodePluginContextPrivate){\n          context.plugins = pluginManager as IPublicApiPlugins;\n          context.hotkey = hotkey;\n          context.logger = logger;\n          context.project = project;\n          context.canvas = new Canvas(editor);\n        }\n      };\n      pluginManager = new LowCodePluginManager(contextApiAssembler).toProxy();\n      pluginManager.register(builtinHotkey);\n      globalContext.register(editor, Editor);\n      globalContext.register(editor, 'editor');\n      globalContext.register(workspace, 'workspace');\n      pluginManager.init().then(() => {\n        resolve({});\n      });\n    })\n  });\n  afterAll(() => {\n    pluginManager.dispose();\n  });\n  beforeEach(() => {\n    designer = new Designer({ editor, shellModelFactory });\n    editor.set('designer', designer);\n    designer.project.open(formSchema);\n    project.__proto__ = new Project(designer.project);\n  });\n  afterEach(() => {\n    designer = null;\n  });\n\n  it('right', () => {\n    const firstCardNode = designer.currentDocument?.getNode('node_k1ow3cbj')!;\n    firstCardNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 39 });\n\n    expect(designer.currentSelection?.selected.includes('node_k1ow3cbl')).toBeTruthy();\n  });\n\n  it('left', () => {\n    const firstCardNode = designer.currentDocument?.getNode('node_k1ow3cbl')!;\n    firstCardNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 37 });\n\n    expect(designer.currentSelection?.selected.includes('node_k1ow3cbj')).toBeTruthy();\n  });\n\n  it('down', () => {\n    const firstCardNode = designer.currentDocument?.getNode('node_k1ow3cbl')!;\n    firstCardNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 40 });\n\n    expect(designer.currentSelection?.selected.includes('node_k1ow3cbo')).toBeTruthy();\n  });\n\n  it('up', () => {\n    const secondCardNode = designer.currentDocument?.getNode('node_k1ow3cbm')!;\n    secondCardNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 38 });\n\n    expect(designer.currentSelection?.selected.includes('node_k1ow3cbl')).toBeTruthy();\n  });\n\n  // 跟右侧节点调换位置\n  it('option + right', () => {\n    const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!;\n    firstButtonNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 39, altKey: true });\n\n    expect(firstButtonNode.prevSibling?.getId()).toBe('node_k1ow3cbp');\n  });\n\n  // 跟左侧节点调换位置\n  it('option + left', () => {\n    const secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    secondButtonNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 37, altKey: true });\n\n    expect(secondButtonNode.nextSibling?.getId()).toBe('node_k1ow3cbn');\n  });\n\n  // 向父级移动该节点\n  it('option + up', () => {\n    const firstCardNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    firstCardNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 38, altKey: true });\n  });\n\n  // 将节点移入到兄弟节点中\n  it('option + up', () => {\n    const firstCardNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    firstCardNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 40, altKey: true });\n  });\n\n  // 撤销\n  it('command + z', async () => {\n    const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!;\n    let secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n\n    // 等待第一个 session 结束\n    await new Promise(resolve => setTimeout(resolve, 1000));\n\n    firstButtonNode.remove();\n    expect(secondButtonNode.getParent()?.children.size).toBe(1);\n\n    await new Promise(resolve => setTimeout(resolve, 1000));\n\n    fireEvent.keyDown(document, { keyCode: 90, metaKey: true });\n\n    // 重新获取一次节点，因为 documentModel.import 是全画布刷新\n    secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    expect(secondButtonNode.getParent()?.children.size).toBe(2);\n  });\n\n  // 重做\n  it('command + y', async () => {\n    const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!;\n    let secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n\n    // 等待第一个 session 结束\n    await new Promise(resolve => setTimeout(resolve, 1000));\n\n    firstButtonNode.remove();\n    expect(secondButtonNode.getParent()?.children.size).toBe(1);\n\n    await new Promise(resolve => setTimeout(resolve, 1000));\n\n    fireEvent.keyDown(document, { keyCode: 90, metaKey: true });\n\n    // 重新获取一次节点，因为 documentModel.import 是全画布刷新\n    secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    expect(secondButtonNode.getParent()?.children.size).toBe(2);\n\n    await new Promise(resolve => setTimeout(resolve, 1000));\n\n    fireEvent.keyDown(document, { keyCode: 89, metaKey: true });\n\n    // 重新获取一次节点，因为 documentModel.import 是全画布刷新\n    secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    expect(secondButtonNode.getParent()?.children.size).toBe(1);\n  });\n\n  it('command + c', () => {\n    const firstCardNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    firstCardNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 67, metaKey: true });\n  });\n\n  it('command + v', async () => {\n    const secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    secondButtonNode.select();\n\n    fireEvent.keyDown(document, { keyCode: 67, metaKey: true });\n\n    fireEvent.keyDown(document, { keyCode: 86, metaKey: true });\n\n    await new Promise(resolve => setTimeout(resolve, 1000));\n\n    // clipboard 异步，先注释\n    // expect(secondButtonNode.getParent()?.children.size).toBe(3);\n  });\n\n  // 撤销所有选中\n  it('escape', () => {\n    const firstCardNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    firstCardNode.select();\n\n    expect(designer.currentSelection!.selected.includes('node_k1ow3cbp')).toBeTruthy();\n\n    fireEvent.keyDown(document, { keyCode: 27 });\n\n    expect(designer.currentSelection!.selected.length).toBe(0);\n  });\n\n  // 删除节点\n  it('delete', () => {\n    const firstButtonNode = designer.currentDocument?.getNode('node_k1ow3cbn')!;\n    const secondButtonNode = designer.currentDocument?.getNode('node_k1ow3cbp')!;\n    firstButtonNode.select();\n\n    expect(secondButtonNode.prevSibling.id).toBe('node_k1ow3cbn');\n\n    fireEvent.keyDown(document, { keyCode: 46 });\n\n    expect(secondButtonNode.prevSibling).toBeNull();\n  });\n\n\n  describe('非正常分支', () => {\n    it('liveEditing mode', () => {\n      designer.project.mountSimulator({\n        liveEditing: {\n          editing: {},\n        },\n      });\n      editor.set('designer', designer);\n      designer.currentDocument?.selection.select('page');\n      // nothing happened\n      fireEvent.keyDown(document, { keyCode: 39 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 37 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 40 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 38 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 39, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 37, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 40, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 38, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 90, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 89, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 67, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 86, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 27 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(document, { keyCode: 46 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n    });\n\n    it('isFormEvent: true', () => {\n      const inputDOMNode = document.createElement('INPUT');\n      document.body.appendChild(inputDOMNode);\n      designer.currentDocument?.selection.select('page');\n      // nothing happened\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 39 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 37 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 40 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 38 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 39, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 37, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 40, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 38, altKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 90, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 89, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 67, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 86, metaKey: true });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 27 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n\n      fireEvent.keyDown(inputDOMNode, { keyCode: 46 });\n      expect(designer.currentDocument?.selection.selected[0]).toBe('page');\n    });\n\n    it('doc is null', () => {\n      designer.currentDocument?.selection.select('page');\n      designer.project.documents = [];\n\n      fireEvent.keyDown(document, { keyCode: 39 });\n\n      fireEvent.keyDown(document, { keyCode: 37 });\n\n      fireEvent.keyDown(document, { keyCode: 40 });\n\n      fireEvent.keyDown(document, { keyCode: 38 });\n\n      fireEvent.keyDown(document, { keyCode: 39, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 37, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 40, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 38, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 90, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 89, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 67, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 86, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 27 });\n\n      fireEvent.keyDown(document, { keyCode: 46 });\n    });\n\n    it('selected is []', () => {\n      fireEvent.keyDown(document, { keyCode: 39 });\n\n      fireEvent.keyDown(document, { keyCode: 37 });\n\n      fireEvent.keyDown(document, { keyCode: 40 });\n\n      fireEvent.keyDown(document, { keyCode: 38 });\n\n      fireEvent.keyDown(document, { keyCode: 39, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 37, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 40, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 38, altKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 90, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 89, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 67, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 86, metaKey: true });\n\n      fireEvent.keyDown(document, { keyCode: 27 });\n\n      fireEvent.keyDown(document, { keyCode: 46 });\n    });\n  });\n});"
  },
  {
    "path": "packages/designer/tests/designer/designer.test.ts",
    "content": "import '../fixtures/window';\nimport { Editor, globalContext, Setters } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../src/project/project';\nimport { DocumentModel } from '../../src/document/document-model';\nimport { Designer } from '../../src/designer/designer';\nimport { Dragon } from '../../src/designer/dragon';\n// import { TransformStage } from '../../src/document/node/transform-stage';\nimport formSchema from '../fixtures/schema/form';\nimport buttonMetadata from '../fixtures/component-metadata/button';\nimport pageMetadata from '../fixtures/component-metadata/page';\nimport divMetadata from '../fixtures/component-metadata/div';\nimport { delayObxTick } from '../utils';\nimport { fireEvent } from '@testing-library/react';\nimport { IPublicEnumDragObjectType, IPublicEnumTransformStage } from '@alilc/lowcode-types';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\n\nconst mockNode = {\n  internalToShellNode() {\n    return 'mockNode';\n  },\n};\n\ndescribe('Designer 测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n  let dragon: Dragon;\n\n  beforeAll(() => {\n    editor = new Editor();\n    const setters = new Setters();\n    editor.set('setters', setters);\n    !globalContext.has(Editor) && globalContext.register(editor, Editor);\n  });\n\n  beforeEach(() => {\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    doc = project.createDocument(formSchema);\n    dragon = new Dragon(designer);\n  });\n\n  afterEach(() => {\n    project.unload();\n    project.mountSimulator(undefined);\n    designer.purge();\n    designer = null;\n    project = null;\n    dragon = null;\n  });\n\n  describe('onDragstart / onDrag / onDragend', () => {\n    it('IPublicEnumDragObjectType.Node', () => {\n      const dragStartMockFn = jest.fn();\n      const dragMockFn = jest.fn();\n      const dragEndMockFn = jest.fn();\n      const dragStartMockFn2 = jest.fn();\n      const dragMockFn2 = jest.fn();\n      const dragEndMockFn2 = jest.fn();\n\n      const designer = new Designer({\n        editor,\n        shellModelFactory,\n        onDragstart: dragStartMockFn,\n        onDrag: dragMockFn,\n        onDragend: dragEndMockFn,\n      });\n      editor.on('designer.dragstart', dragStartMockFn2);\n      editor.on('designer.drag', dragMockFn2);\n      editor.on('designer.dragend', dragEndMockFn2);\n      const { dragon } = designer;\n\n      dragon.boost(\n        {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [doc.getNode('node_k1ow3cbn')],\n        },\n        new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n      );\n\n      fireEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n      expect(dragStartMockFn).toHaveBeenCalledTimes(1);\n      expect(dragStartMockFn2).toHaveBeenCalledTimes(1);\n      expect(dragMockFn).toHaveBeenCalledTimes(1);\n      expect(dragMockFn2).toHaveBeenCalledTimes(1);\n\n      fireEvent.mouseMove(document, { clientX: 110, clientY: 110 });\n      expect(dragMockFn).toHaveBeenCalledTimes(2);\n      expect(dragMockFn2).toHaveBeenCalledTimes(2);\n\n      setMockDropLocation();\n      fireEvent.mouseUp(document, { clientX: 118, clientY: 118 });\n\n      expect(dragEndMockFn).toHaveBeenCalledTimes(1);\n      expect(dragEndMockFn2).toHaveBeenCalledTimes(1);\n\n      function setMockDropLocation() {\n        const mockTarget = {\n          document: doc,\n          children: {\n            get(x) {\n              return x;\n            },\n            insert() {},\n            internalInsert() {},\n          },\n        };\n        const mockDetail = { type: 'Children', index: 1, near: { node: { x: 1 } } };\n        const mockSource = {};\n        const mockEvent = { type: 'LocateEvent', nodes: [] };\n\n        return designer.createLocation({\n          target: mockTarget,\n          detail: mockDetail,\n          source: mockSource,\n          event: mockEvent,\n        });\n      }\n    });\n\n    it('IPublicEnumDragObjectType.NodeData', () => {\n      const dragStartMockFn = jest.fn();\n      const dragMockFn = jest.fn();\n      const dragEndMockFn = jest.fn();\n      const dragStartMockFn2 = jest.fn();\n      const dragMockFn2 = jest.fn();\n      const dragEndMockFn2 = jest.fn();\n\n      const designer = new Designer({\n        editor,\n        shellModelFactory,\n        onDragstart: dragStartMockFn,\n        onDrag: dragMockFn,\n        onDragend: dragEndMockFn,\n      });\n      editor.on('designer.dragstart', dragStartMockFn2);\n      editor.on('designer.drag', dragMockFn2);\n      editor.on('designer.dragend', dragEndMockFn2);\n      const { dragon } = designer;\n\n      dragon.boost(\n        {\n          type: IPublicEnumDragObjectType.NodeData,\n          data: [{\n            componentName: 'Button',\n          }],\n        },\n        new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n      );\n\n      fireEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n      expect(dragStartMockFn).toHaveBeenCalledTimes(1);\n      expect(dragStartMockFn2).toHaveBeenCalledTimes(1);\n      expect(dragMockFn).toHaveBeenCalledTimes(1);\n      expect(dragMockFn2).toHaveBeenCalledTimes(1);\n\n      fireEvent.mouseMove(document, { clientX: 110, clientY: 110 });\n      expect(dragMockFn).toHaveBeenCalledTimes(2);\n      expect(dragMockFn2).toHaveBeenCalledTimes(2);\n\n      setMockDropLocation();\n      fireEvent.mouseUp(document, { clientX: 118, clientY: 118 });\n\n      expect(dragEndMockFn).toHaveBeenCalledTimes(1);\n      expect(dragEndMockFn2).toHaveBeenCalledTimes(1);\n\n      function setMockDropLocation() {\n        const mockTarget = {\n          document: doc,\n          children: {\n            get(x) {\n              return x;\n            },\n            insert() {},\n            internalInsert() {},\n          },\n        };\n        const mockDetail = { type: 'Children', index: 1, near: { node: { x: 1 } } };\n        const mockSource = {};\n        const mockEvent = { type: 'LocateEvent', nodes: [] };\n\n        return designer.createLocation({\n          target: mockTarget,\n          detail: mockDetail,\n          source: mockSource,\n          event: mockEvent,\n        });\n      }\n    });\n  });\n\n  it('addPropsReducer / transformProps', () => {\n    // 没有相应的 reducer\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Init)).toEqual({ num: 1 });\n    // props 是数组\n    expect(designer.transformProps([{ num: 1 }], mockNode, IPublicEnumTransformStage.Init)).toEqual([{ num: 1 }]);\n\n    designer.addPropsReducer((props, node) => {\n      props.num += 1;\n      return props;\n    }, IPublicEnumTransformStage.Init);\n\n    designer.addPropsReducer((props, node) => {\n      props.num += 1;\n      return props;\n    }, IPublicEnumTransformStage.Init);\n\n    designer.addPropsReducer((props, node) => {\n      props.num += 1;\n      return props;\n    }, IPublicEnumTransformStage.Clone);\n\n    designer.addPropsReducer((props, node) => {\n      props.num += 1;\n      return props;\n    }, IPublicEnumTransformStage.Serilize);\n\n    designer.addPropsReducer((props, node) => {\n      props.num += 1;\n      return props;\n    }, IPublicEnumTransformStage.Render);\n\n    designer.addPropsReducer((props, node) => {\n      props.num += 1;\n      return props;\n    }, IPublicEnumTransformStage.Save);\n\n    designer.addPropsReducer((props, node) => {\n      props.num += 1;\n      return props;\n    }, IPublicEnumTransformStage.Upgrade);\n\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Init)).toEqual({ num: 3 });\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Clone)).toEqual({ num: 2 });\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Serilize)).toEqual({ num: 2 });\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Render)).toEqual({ num: 2 });\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Save)).toEqual({ num: 2 });\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Upgrade)).toEqual({ num: 2 });\n\n    designer.addPropsReducer((props, node) => {\n      throw new Error('calculate error');\n    }, IPublicEnumTransformStage.Upgrade);\n    expect(designer.transformProps({ num: 1 }, mockNode, IPublicEnumTransformStage.Upgrade)).toEqual({ num: 2 });\n  });\n\n  it('setProps', () => {\n    // 第一次设置 props\n    const initialProps = {\n      simulatorComponent: { isSimulatorComp: true },\n      simulatorProps: { designMode: 'design' },\n      suspensed: true,\n      componentMetadatas: [buttonMetadata, divMetadata],\n    };\n    designer = new Designer({\n      editor,\n      shellModelFactory,\n      ...initialProps,\n     });\n\n    expect(designer.simulatorComponent).toEqual({ isSimulatorComp: true });\n    expect(designer.simulatorProps).toEqual({ designMode: 'design' });\n    expect(designer.suspensed).toBeTruthy();\n    expect((designer as any)._componentMetasMap.has('Div')).toBeTruthy();\n    expect((designer as any)._componentMetasMap.has('Button')).toBeTruthy();\n    const { editor: editorFromDesigner, shellModelFactory: shellModelFactoryFromDesigner, ...others } = (designer as any).props;\n    expect(others).toEqual(initialProps);\n    expect(designer.get('simulatorProps')).toEqual({ designMode: 'design' });\n    expect(designer.get('suspensed')).toBeTruthy();\n    expect(designer.get('xxx')).toBeUndefined();\n\n    // 第二次设置 props\n    const updatedProps = {\n      simulatorComponent: { isSimulatorComp2: true },\n      simulatorProps: { designMode: 'live' },\n      suspensed: false,\n      componentMetadatas: [buttonMetadata],\n    };\n    designer.setProps(updatedProps);\n\n    expect(designer.simulatorComponent).toEqual({ isSimulatorComp2: true });\n    expect(designer.simulatorProps).toEqual({ designMode: 'live' });\n    expect(designer.suspensed).toBeFalsy();\n    expect((designer as any)._componentMetasMap.has('Button')).toBeTruthy();\n    expect((designer as any)._componentMetasMap.has('Div')).toBeTruthy();\n    const { editor: editorFromDesigner2, shellModelFactory: shellModelFactoryFromDesigner2,  ...others2 } = (designer as any).props;\n    expect(others2).toEqual(updatedProps);\n\n    // 第三次设置 props，跟第二次值一样，for 覆盖率测试\n    const updatedProps2 = updatedProps;\n    designer.setProps(updatedProps2);\n\n    expect(designer.simulatorComponent).toEqual({ isSimulatorComp2: true });\n    expect(designer.simulatorProps).toEqual({ designMode: 'live' });\n    expect(designer.suspensed).toBeFalsy();\n    expect((designer as any)._componentMetasMap.has('Button')).toBeTruthy();\n    expect((designer as any)._componentMetasMap.has('Div')).toBeTruthy();\n    const { editor: editorFromDesigner3, shellModelFactory: shellModelFactoryFromDesigner3, ...others3 } = (designer as any).props;\n    expect(others3).toEqual(updatedProps);\n  });\n\n  describe('getSuitableInsertion', () => {\n    it('没有 currentDocument', () => {\n      project.unload();\n      expect(designer.getSuitableInsertion({})).toBeNull();\n    });\n\n    it('有选中节点，isContainer && 允许放子节点', () => {\n      designer.createComponentMeta(divMetadata);\n      designer.createComponentMeta(buttonMetadata);\n      designer.currentSelection?.select('node_k1ow3cbo');\n      const { target, index } = designer.getSuitableInsertion(\n        doc.createNode({ componentName: 'Button' }),\n      );\n      expect(target).toBe(doc.getNode('node_k1ow3cbo'));\n      expect(index).toBeUndefined();\n    });\n\n    it('有选中节点，不是 isContainer', () => {\n      designer.createComponentMeta(divMetadata);\n      designer.createComponentMeta(buttonMetadata);\n      designer.currentSelection?.select('node_k1ow3cbn');\n      const { target, index } = designer.getSuitableInsertion(\n        doc.createNode({ componentName: 'Button' }),\n      );\n      expect(target).toBe(doc.getNode('node_k1ow3cbo'));\n      expect(index).toBe(1);\n    });\n\n    it('无选中节点', () => {\n      designer.createComponentMeta(pageMetadata);\n      const { target, index } = designer.getSuitableInsertion(\n        doc.createNode({ componentName: 'Button' }),\n      );\n      expect(target).toBe(doc.getNode('page'));\n      expect(index).toBeUndefined();\n    });\n  });\n\n  it('getComponentMetasMap', () => {\n    designer.createComponentMeta({\n      componentName: 'Div',\n      title: '容器',\n      docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',\n      devMode: 'procode',\n      tags: ['布局'],\n    });\n\n    expect(designer.getComponentMetasMap().get('Div')).not.toBeUndefined();\n  });\n\n  it('refreshComponentMetasMap', () => {\n    designer.createComponentMeta({\n      componentName: 'Div',\n      title: '容器',\n      docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',\n      devMode: 'procode',\n      tags: ['布局'],\n    });\n\n    const originalMetasMap = designer.getComponentMetasMap();\n    designer.refreshComponentMetasMap();\n\n    expect(originalMetasMap).not.toBe(designer.getComponentMetasMap());\n  });\n\n  describe('loadIncrementalAssets', () => {\n    it('components && packages', async () => {\n      editor.set('assets', { components: [], packages: [] });\n      const fn = jest.fn();\n\n      project.mountSimulator({\n        setupComponents: fn,\n      });\n      await designer.loadIncrementalAssets({\n        components: [{\n          componentName: 'Div2',\n          title: '容器',\n          docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',\n          devMode: 'proCode',\n          tags: ['布局'],\n        }],\n        packages: [],\n      });\n\n      const comps = editor.get('assets').components;\n      expect(comps).toHaveLength(1);\n      expect(fn).toHaveBeenCalled();\n    });\n\n    it('no components && packages', async () => {\n      editor.set('assets', { components: [], packages: [] });\n      const fn = jest.fn();\n\n      project.mountSimulator({\n        setupComponents: fn,\n      });\n      await designer.loadIncrementalAssets({});\n\n      expect(fn).not.toHaveBeenCalled();\n    });\n  });\n\n  it('createLocation / clearLocation', () => {\n    const mockTarget = {\n      document: doc,\n      children: {\n        get(x) {\n          return x;\n        },\n        insert() {},\n        internalInsert() {},\n      },\n    };\n    const mockDetail = { type: 'Children', index: 1, near: { node: { x: 1 } } };\n    const mockSource = {};\n    const mockEvent = { type: 'LocateEvent', nodes: [] };\n\n    const loc = designer.createLocation({\n      target: mockTarget,\n      detail: mockDetail,\n      source: mockSource,\n      event: mockEvent,\n    });\n\n    expect(designer.dropLocation).toBe(loc);\n\n    const doc2 = project.createDocument({ componentName: 'Page' });\n    designer.createLocation({\n      target: {\n        document: doc2,\n        children: {\n          get(x) {\n            return x;\n          },\n          insert() {},\n          internalInsert() {},\n        },\n      },\n      detail: mockDetail,\n      source: mockSource,\n      event: mockEvent,\n    });\n\n    designer.clearLocation();\n    expect(designer.dropLocation).toBeUndefined();\n  });\n\n  it('autorun', async () => {\n    const mockFn = jest.fn();\n    designer.autorun(() => {\n      mockFn();\n    }, true);\n\n    await delayObxTick();\n\n    expect(mockFn).toHaveBeenCalled();\n  });\n\n  it('suspensed', () => {\n    designer.suspensed = true;\n    expect(designer.suspensed).toBeTruthy();\n    designer.suspensed = false;\n    expect(designer.suspensed).toBeFalsy();\n  });\n\n  it('schema', () => {\n    // TODO: matchSnapshot\n    designer.schema;\n    designer.setSchema({\n      componentsTree: [\n        {\n          componentName: 'Page',\n          props: {},\n        },\n      ],\n    });\n  });\n\n  it('createOffsetObserver / clearOobxList / touchOffsetObserver', () => {\n    project.mountSimulator({\n      computeComponentInstanceRect() {},\n    });\n    designer.createOffsetObserver({ node: doc.getNode('page'), instance: {} });\n    expect(designer.oobxList).toHaveLength(1);\n    designer.createOffsetObserver({ node: doc.getNode('page'), instance: {} });\n    expect(designer.oobxList).toHaveLength(2);\n\n    designer.clearOobxList(true);\n    expect(designer.oobxList).toHaveLength(0);\n\n    const obx = designer.createOffsetObserver({ node: doc.getNode('page'), instance: {} });\n    obx.pid = 'xxx';\n    obx.compute = () => {};\n    expect(designer.oobxList).toHaveLength(1);\n\n    designer.touchOffsetObserver();\n    expect(designer.oobxList).toHaveLength(1);\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/detecting.test.ts",
    "content": "import { Detecting } from '../../src/designer/detecting';\n\nit('Detecting 测试', () => {\n  const fn = jest.fn();\n  const detecting = new Detecting();\n  detecting.onDetectingChange(fn);\n\n  expect(detecting.enable).toBeTruthy();\n\n  const mockNode = { document };\n  detecting.capture(mockNode);\n  expect(fn).toHaveBeenCalledWith(detecting.current);\n  expect(detecting.current).toBe(mockNode);\n\n  detecting.release({});\n  detecting.release(mockNode);\n  expect(detecting.current).toBeNull();\n\n  detecting.capture(mockNode);\n  detecting.leave(document);\n  expect(detecting.current).toBeNull();\n\n  detecting.capture(mockNode);\n  detecting.enable = false;\n  expect(detecting.current).toBeNull();\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/dragon.test.ts",
    "content": "import '../fixtures/window';\nimport { Editor, globalContext } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../src/project/project';\nimport { DocumentModel } from '../../src/document/document-model';\nimport { Designer } from '../../src/designer/designer';\nimport {\n  Dragon,\n  isDragNodeObject,\n  isDragNodeDataObject,\n  isDragAnyObject,\n  isLocateEvent,\n  isShaken,\n  setShaken,\n  isInvalidPoint,\n  isSameAs,\n} from '../../src/designer/dragon';\nimport { IPublicEnumDragObjectType } from '@alilc/lowcode-types';\nimport formSchema from '../fixtures/schema/form';\nimport { fireEvent } from '@testing-library/react';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\n\ndescribe('Dragon 测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n  let dragon: Dragon;\n\n  beforeAll(() => {\n    editor = new Editor();\n    !globalContext.has(Editor) && globalContext.register(editor, Editor);\n  });\n\n  beforeEach(() => {\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    doc = project.createDocument(formSchema);\n    dragon = new Dragon(designer);\n  });\n\n  afterEach(() => {\n    project.unload();\n    project.mountSimulator(undefined);\n    designer.purge();\n    designer = null;\n    project = null;\n    dragon = null;\n  });\n\n  it.skip('drag NodeData', () => {\n    const dragStartMockFn = jest.fn();\n    const dragMockFn = jest.fn();\n    const dragEndMockFn = jest.fn();\n\n    dragon.onDragstart((e) => {\n      console.log('start', e, e.originalEvent, e.originalEvent.clientX);\n    });\n\n    dragon.onDrag((e) => {\n      console.log('drag', e, e.originalEvent, e.originalEvent.clientX);\n    });\n\n    dragon.onDragend((e) => {\n      console.log('end', e, e.originalEvent);\n    });\n\n    dragon.boost(\n      {\n        type: IPublicEnumDragObjectType.NodeData,\n        data: [{ componentName: 'Button' }],\n      },\n      new Event('dragstart', { clientX: 100, clientY: 100 }),\n    );\n\n    fireEvent.dragOver(document, { clientX: 108, clientY: 108 });\n    fireEvent.dragEnd(document, { clientX: 118, clientY: 118 });\n  });\n\n  it.skip('drag Node', () => {\n    console.log(new MouseEvent('mousedown', { clientX: 1 }).clientX);\n    // console.log(new Event('mousedown', { clientX: 1 }).clientX);\n    // console.log(new Event('drag', { clientX: 1 }).clientX);\n    // console.log(new CustomEvent('drag', { clientX: 1 }).clientX);\n    console.log(document.createEvent('dragstart', { clientX: 1 }).clientX);\n  });\n\n  it('mouse NodeData', () => {\n    const dragStartMockFn = jest.fn();\n    const dragMockFn = jest.fn();\n    const dragEndMockFn = jest.fn();\n\n    const offDragStart = dragon.onDragstart(dragStartMockFn);\n\n    const offDrag = dragon.onDrag(dragMockFn);\n\n    const offDragEnd = dragon.onDragend(dragEndMockFn);\n\n    dragon.boost(\n      {\n        type: IPublicEnumDragObjectType.NodeData,\n        data: [{ componentName: 'Button' }],\n      },\n      new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n    );\n\n    fireEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n    fireEvent.mouseMove(document, { clientX: 110, clientY: 110 });\n    fireEvent.mouseUp(document, { clientX: 118, clientY: 118 });\n\n    expect(dragStartMockFn).toHaveBeenCalledTimes(1);\n    expect(dragMockFn).toHaveBeenCalledTimes(2);\n    expect(dragEndMockFn).toHaveBeenCalledTimes(1);\n  });\n\n  it('mouse Node', () => {\n    const dragStartMockFn = jest.fn();\n    const dragMockFn = jest.fn();\n    const dragEndMockFn = jest.fn();\n\n    const offDragStart = dragon.onDragstart(dragStartMockFn);\n    const offDrag = dragon.onDrag(dragMockFn);\n    const offDragEnd = dragon.onDragend(dragEndMockFn);\n\n    dragon.boost(\n      {\n        type: IPublicEnumDragObjectType.Node,\n        nodes: [doc.getNode('node_k1ow3cbn')],\n      },\n      new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n    );\n\n    // mouseDown 模式正常不会触发 dragStart 事件，除非 shaken 型\n    expect(dragStartMockFn).not.toHaveBeenCalled();\n\n    fireEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n    expect(dragStartMockFn).toHaveBeenCalledTimes(1);\n    expect(dragMockFn).toHaveBeenCalledTimes(1);\n    fireEvent.mouseMove(document, { clientX: 110, clientY: 110 });\n    expect(dragMockFn).toHaveBeenCalledTimes(2);\n    expect(dragon.dragging).toBeTruthy();\n\n    fireEvent.mouseUp(document, { clientX: 118, clientY: 118 });\n\n    expect(dragEndMockFn).toHaveBeenCalledTimes(1);\n\n    offDragStart();\n    offDrag();\n    offDragEnd();\n    dragMockFn.mockClear();\n\n    dragon.boost(\n      {\n        type: IPublicEnumDragObjectType.Node,\n        nodes: [doc.getNode('node_k1ow3cbn')],\n      },\n      new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n    );\n\n    fireEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n\n    expect(dragMockFn).not.toHaveBeenCalled();\n  });\n\n  it('mouse Node & esc', () => {\n    const dragStartMockFn = jest.fn();\n    const dragMockFn = jest.fn();\n    const dragEndMockFn = jest.fn();\n\n    const offDragStart = dragon.onDragstart(dragStartMockFn);\n    const offDrag = dragon.onDrag(dragMockFn);\n    const offDragEnd = dragon.onDragend(dragEndMockFn);\n\n    dragon.boost(\n      {\n        type: IPublicEnumDragObjectType.Node,\n        nodes: [doc.getNode('node_k1ow3cbn')],\n      },\n      new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n    );\n\n    fireEvent.keyDown(document, { keyCode: 27 });\n    expect(dragon.designer.dropLocation).toBeUndefined();\n  });\n\n  it('mouse Node & copy', () => {\n    const dragStartMockFn = jest.fn();\n    const dragMockFn = jest.fn();\n    const dragEndMockFn = jest.fn();\n\n    const offDragStart = dragon.onDragstart(dragStartMockFn);\n    const offDrag = dragon.onDrag(dragMockFn);\n    const offDragEnd = dragon.onDragend(dragEndMockFn);\n\n    dragon.boost(\n      {\n        type: IPublicEnumDragObjectType.Node,\n        nodes: [doc.getNode('node_k1ow3cbn')],\n      },\n      new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n    );\n\n    const mockFn1 = jest.fn();\n    project.mountSimulator({ setCopyState: mockFn1 });\n    expect(dragon.getSimulators().size).toBe(1);\n    fireEvent.keyDown(document, { ctrlKey: true });\n    expect(mockFn1).toHaveBeenCalled();\n  });\n\n  it('from', () => {\n    const dragStartMockFn = jest.fn();\n    const dragMockFn = jest.fn();\n    const dragEndMockFn = jest.fn();\n\n    const offDragStart = dragon.onDragstart(dragStartMockFn);\n    const offDrag = dragon.onDrag(dragMockFn);\n    const offDragEnd = dragon.onDragend(dragEndMockFn);\n    const mockBoostFn = jest\n      .fn((e) => {\n        return {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [doc.getNode('node_k1ow3cbn')],\n        };\n      })\n      .mockImplementationOnce(() => null);\n\n    const offFrom = dragon.from(document, mockBoostFn);\n\n    // 无用 mouseDown，无效的按钮\n    fireEvent.mouseDown(document, { button: 2 });\n    expect(dragStartMockFn).not.toHaveBeenCalled();\n\n    // 无用 mouseDown，无效的 dragObject\n    fireEvent.mouseDown(document, { clientX: 100, clientY: 100 });\n    expect(dragStartMockFn).not.toHaveBeenCalled();\n\n    fireEvent.mouseDown(document, { clientX: 100, clientY: 100 });\n    expect(dragStartMockFn).not.toHaveBeenCalled();\n\n    fireEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n    expect(dragStartMockFn).toHaveBeenCalledTimes(1);\n    expect(dragMockFn).toHaveBeenCalledTimes(1);\n    fireEvent.mouseMove(document, { clientX: 110, clientY: 110 });\n    expect(dragMockFn).toHaveBeenCalledTimes(2);\n    expect(dragon.dragging).toBeTruthy();\n\n    fireEvent.mouseUp(document, { clientX: 118, clientY: 118 });\n\n    expect(dragEndMockFn).toHaveBeenCalledTimes(1);\n\n    offDragStart();\n    offDrag();\n    offDragEnd();\n    dragMockFn.mockClear();\n\n    fireEvent.mouseMove(document, { clientX: 100, clientY: 100 });\n    expect(dragMockFn).not.toHaveBeenCalled();\n\n    offFrom();\n    fireEvent.mouseMove(document, { clientX: 100, clientY: 100 });\n    expect(dragMockFn).not.toHaveBeenCalled();\n  });\n\n  it('addSensor / removeSensor', () => {\n    const sensor = {\n      locate: () => {},\n      sensorAvailable: true,\n      isEnter: () => true,\n      fixEvent: () => {},\n      deactiveSensor: () => {},\n    };\n    const sensor2 = {};\n    dragon.addSensor(sensor);\n    expect(dragon.sensors.length).toBe(1);\n    expect(dragon.activeSensor).toBeUndefined();\n    dragon.boost(\n      {\n        type: IPublicEnumDragObjectType.NodeData,\n        data: [{ componentName: 'Button' }],\n      },\n      new MouseEvent('mousedown', { clientX: 100, clientY: 100 }),\n    );\n\n    fireEvent.mouseMove(document, { clientX: 108, clientY: 108 });\n    fireEvent.mouseMove(document, { clientX: 110, clientY: 110 });\n    fireEvent.mouseUp(document, { clientX: 118, clientY: 118 });\n    expect(dragon.activeSensor).toBe(sensor);\n    // remove a non-existing sensor\n    dragon.removeSensor(sensor2);\n    expect(dragon.sensors.length).toBe(1);\n    dragon.removeSensor(sensor);\n    expect(dragon.sensors.length).toBe(0);\n  });\n\n  it('has sensor', () => {\n    const mockFn1 = jest.fn();\n    const mockDoc = document.createElement('iframe').contentWindow?.document;\n    dragon.addSensor({\n      fixEvent: () => {},\n      locate: () => {},\n      contentDocument: mockDoc,\n    });\n    project.mountSimulator({\n      setCopyState: mockFn1,\n      setNativeSelection: () => {},\n      clearState: () => {},\n      setDraggingState: () => {},\n    });\n\n    const mockBoostFn = jest\n      .fn((e) => {\n        return {\n          type: IPublicEnumDragObjectType.Node,\n          nodes: [doc.getNode('node_k1ow3cbn')],\n        };\n      })\n      .mockImplementationOnce(() => null);\n\n    const offFrom = dragon.from(document, mockBoostFn);\n\n    // TODO: 想办法 mock 一个 iframe.currentDocument\n    fireEvent.mouseDown(document, { clientX: 100, clientY: 100 });\n  });\n});\n\ndescribe('导出的其他函数', () => {\n  it('isDragNodeObject', () => {\n    expect(isDragNodeObject({ type: IPublicEnumDragObjectType.Node, nodes: [] })).toBeTruthy();\n  });\n  it('isDragNodeDataObject', () => {\n    expect(isDragNodeDataObject({ type: IPublicEnumDragObjectType.NodeData, data: [] })).toBeTruthy();\n  });\n  it('isDragAnyObject', () => {\n    expect(isDragAnyObject()).toBeFalsy();\n    expect(isDragAnyObject({ type: IPublicEnumDragObjectType.Node, nodes: [] })).toBeFalsy();\n    expect(isDragAnyObject({ type: IPublicEnumDragObjectType.NodeData, data: [] })).toBeFalsy();\n    expect(isDragAnyObject({ type: 'others', data: [] })).toBeTruthy();\n  });\n  it('isLocateEvent', () => {\n    expect(isLocateEvent({ type: 'LocateEvent' })).toBeTruthy();\n  });\n  it('isShaken', () => {\n    expect(\n      isShaken(\n        { clientX: 1, clientY: 1, target: {} },\n        { clientX: 1, clientY: 1, target: { other: 1 } },\n      ),\n    ).toBeTruthy();\n    expect(isShaken({ shaken: true })).toBeTruthy();\n    expect(isShaken({ clientX: 1, clientY: 1 }, { clientX: 2, clientY: 2 })).toBeFalsy();\n    expect(isShaken({ clientX: 1, clientY: 1 }, { clientX: 3, clientY: 5 })).toBeTruthy();\n  });\n  it('setShaken', () => {\n    const e = {};\n    setShaken(e);\n    expect(isShaken(e)).toBeTruthy();\n  });\n\n  it('isInvalidPoint', () => {\n    expect(isInvalidPoint({ clientX: 0, clientY: 0 }, { clientX: 6, clientY: 1 })).toBeTruthy();\n    expect(isInvalidPoint({ clientX: 0, clientY: 0 }, { clientX: 1, clientY: 6 })).toBeTruthy();\n    expect(isInvalidPoint({ clientX: 0, clientY: 0 }, { clientX: 6, clientY: 6 })).toBeTruthy();\n    expect(isInvalidPoint({ clientX: 1, clientY: 1 }, { clientX: 2, clientY: 1 })).toBeFalsy();\n  });\n\n  it('isSameAs', () => {\n    expect(isSameAs({ clientX: 1, clientY: 1 }, { clientX: 1, clientY: 1 })).toBeTruthy();\n    expect(isSameAs({ clientX: 1, clientY: 1 }, { clientX: 2, clientY: 1 })).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/location.test.ts",
    "content": "import {\n  DropLocation,\n  isLocationData,\n  isLocationChildrenDetail,\n  isRowContainer,\n  isChildInline,\n  getRectTarget,\n  isVerticalContainer,\n  isVertical,\n  getWindow,\n} from '../../src/designer/location';\nimport { getMockElement } from '../utils';\n\ndescribe('DropLocation 测试', () => {\n  it('constructor', () => {\n    const mockTarget = { document };\n    const mockDetail = {};\n    const mockSource = {};\n    const mockEvent = { type: 'LocateEvent', nodes: [] };\n    const loc = new DropLocation({\n      target: mockTarget,\n      detail: mockDetail,\n      source: mockSource,\n      event: mockEvent,\n    });\n\n    expect(loc.getContainer()).toBe(mockTarget);\n    expect(loc.document).toBe(document);\n    expect(loc.target).toBe(mockTarget);\n    expect(loc.detail).toBe(mockDetail);\n    expect(loc.source).toBe(mockSource);\n    expect(loc.event).toBe(mockEvent);\n\n    const mockEvent2 = { type: 'LocateEvent', data: [] };\n    const loc2 = loc.clone(mockEvent2);\n    expect(loc2.target).toBe(mockTarget);\n    expect(loc2.detail).toBe(mockDetail);\n    expect(loc2.source).toBe(mockSource);\n    expect(loc2.event).toBe(mockEvent2);\n  });\n\n  it('constructor, detail: undefined', () => {\n    const mockTarget = { document };\n    const mockDetail = undefined;\n    const mockSource = {};\n    const mockEvent = { type: 'LocateEvent', nodes: [] };\n    const loc = new DropLocation({\n      target: mockTarget,\n      detail: mockDetail,\n      source: mockSource,\n      event: mockEvent,\n    });\n\n    expect(loc.getInsertion()).toBeNull();\n  });\n\n  it('constructor, detail.type: Children, detail.index <= 0', () => {\n    const mockTarget = { document };\n    const mockDetail = { type: 'Children', index: -1 };\n    const mockSource = {};\n    const mockEvent = { type: 'LocateEvent', nodes: [] };\n    const loc = new DropLocation({\n      target: mockTarget,\n      detail: mockDetail,\n      source: mockSource,\n      event: mockEvent,\n    });\n\n    expect(loc.getInsertion()).toBeNull();\n  });\n\n  it('constructor, detail.type: Children, detail.index > 0', () => {\n    const mockTarget = {\n      document,\n      children: {\n        get(x) {\n          return x;\n        },\n      },\n    };\n    const mockDetail = { type: 'Children', index: 1 };\n    const mockSource = {};\n    const mockEvent = { type: 'LocateEvent', nodes: [] };\n    const loc = new DropLocation({\n      target: mockTarget,\n      detail: mockDetail,\n      source: mockSource,\n      event: mockEvent,\n    });\n\n    expect(loc.getInsertion()).toBe(0);\n  });\n\n  it('constructor, detail.type: Prop', () => {\n    const mockTarget = {\n      document,\n      children: {\n        get(x) {\n          return x;\n        },\n      },\n    };\n    const mockDetail = { type: 'Prop', index: 1, near: { node: { x: 1 } } };\n    const mockSource = {};\n    const mockEvent = { type: 'LocateEvent', nodes: [] };\n    const loc = new DropLocation({\n      target: mockTarget,\n      detail: mockDetail,\n      source: mockSource,\n      event: mockEvent,\n    });\n\n    expect(loc.getInsertion()).toEqual({ x: 1 });\n  });\n});\n\nit('isLocationData', () => {\n  expect(isLocationData({ target: {}, detail: {} })).toBeTruthy();\n});\n\nit('isLocationChildrenDetail', () => {\n  expect(isLocationChildrenDetail({ type: 'Children' })).toBeTruthy();\n});\n\nit('isRowContainer', () => {\n  expect(isRowContainer({ nodeType: Node.TEXT_NODE })).toBeTruthy();\n  window.getComputedStyle = jest\n    .fn(() => {\n      return {\n        getPropertyValue: (pName) => {\n          return pName === 'display' ? 'flex' : '';\n        },\n      };\n    })\n    .mockImplementationOnce(() => {\n      return {\n        getPropertyValue: (pName) => {\n          return pName === 'display' ? 'flex' : 'column';\n        },\n      };\n    })\n    .mockImplementationOnce(() => {\n      return {\n        getPropertyValue: (pName) => {\n          return pName === 'display' ? 'grid' : 'column';\n        },\n      };\n    });\n  expect(isRowContainer(getMockElement('div'))).toBeFalsy();\n  expect(isRowContainer(getMockElement('div'))).toBeTruthy();\n  expect(isRowContainer(getMockElement('div'))).toBeTruthy();\n});\n\nit('isChildInline', () => {\n  window.getComputedStyle = jest\n    .fn(() => {\n      return {\n        getPropertyValue: (pName) => {\n          return pName === 'display' ? 'inline' : 'float';\n        },\n      };\n    });\n\n  expect(isChildInline({ nodeType: Node.TEXT_NODE })).toBeTruthy();\n  expect(isChildInline(getMockElement('div'))).toBeTruthy();\n});\n\nit('getRectTarget', () => {\n  expect(getRectTarget()).toBeNull();\n  expect(getRectTarget({ computed: false })).toBeNull();\n  expect(getRectTarget({ elements: [{}] })).toEqual({});\n});\n\nit('isVerticalContainer', () => {\n  window.getComputedStyle = jest\n    .fn(() => {\n      return {\n        getPropertyValue: (pName) => {\n          return pName === 'display' ? 'flex' : 'row';\n        },\n      };\n    });\n  expect(isVerticalContainer()).toBeFalsy();\n  expect(isVerticalContainer({ elements: [getMockElement('div')] })).toBeTruthy();\n});\n\nit('isVertical', () => {\n  expect(isVertical({ elements: [] })).toBeFalsy();\n  expect(isVertical({ elements: [getMockElement('div')] })).toBeFalsy();\n  const e1 = getMockElement('div');\n  const e2 = getMockElement('div');\n  e2.appendChild(e1);\n  expect(isVertical({ elements: [e1] })).toBeTruthy();\n  window.getComputedStyle = jest\n    .fn(() => {\n      return {\n        getPropertyValue: (pName) => {\n          return pName === 'display' ? 'inline' : 'float';\n        },\n      };\n    });\n  expect(isVertical({ elements: [getMockElement('div')] })).toBeTruthy();\n});\n\nit('getWindow', () => {\n  const mockElem = getMockElement('div');\n  expect(getWindow(mockElem)).toBe(window);\n  expect(getWindow(document)).toBe(window);\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/scroller.test.ts",
    "content": "import '../fixtures/window';\nimport { Editor, globalContext } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../src/project/project';\nimport { DocumentModel } from '../../src/document/document-model';\nimport { ScrollTarget, Scroller } from '../../src/designer/scroller';\nimport { Designer } from '../../src/designer/designer';\nimport {\n  Dragon,\n} from '../../src/designer/dragon';\nimport formSchema from '../fixtures/schema/form';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\n\ndescribe('Scroller 测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n  let dragon: Dragon;\n\n  beforeAll(() => {\n    editor = new Editor();\n    !globalContext.has(Editor) && globalContext.register(editor, Editor);\n  });\n\n  beforeEach(() => {\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    doc = project.createDocument(formSchema);\n    dragon = new Dragon(designer);\n  });\n\n  afterEach(() => {\n    project.unload();\n    project.mountSimulator(undefined);\n    designer.purge();\n    designer = null;\n    project = null;\n    dragon = null;\n  });\n\n  function getMockWindow() {\n    let scrollX = 0;\n    let scrollY = 0;\n    const mockWindow = {\n      scrollTo(x, y) {\n        if (typeof x === 'number') {\n          scrollX = x;\n          scrollY = y;\n        } else {\n          scrollX = x.left;\n          scrollY = x.top;\n        }\n      },\n      get scrollX() { return scrollX; },\n      get scrollY() { return scrollY; },\n      scrollHeight: 1000,\n      scrollWidth: 500,\n      document: {},\n      nodeType: Node.ELEMENT_NODE,\n    };\n    return mockWindow;\n  }\n\n  describe('ScrollTarget 测试', () => {\n    it('constructor', () => {\n      const win = getMockWindow();\n      const target = new ScrollTarget(win);\n      expect(target.scrollWidth).toBe(500);\n      expect(target.scrollHeight).toBe(1000);\n      target.scrollToXY(50, 50);\n      expect(target.left).toBe(50);\n      expect(target.top).toBe(50);\n\n      target.scrollTo({ left: 100, top: 100 });\n      expect(target.left).toBe(100);\n      expect(target.top).toBe(100);\n    });\n  });\n\n  function mockRAF() {\n    let rafCount = 0;\n    window.requestAnimationFrame = (fn) => {\n      if (rafCount++ < 2) {\n        fn();\n      } else {\n        window.requestAnimationFrame = () => {};\n      }\n    };\n  }\n  describe('Scroller 测试', () => {\n    it('scrollTarget: ScrollTarget', () => {\n      const win = getMockWindow();\n      const scrollTarget = new ScrollTarget(win);\n      const scroller = new Scroller({ scrollTarget, bounds: { width: 50, height: 50, top: 50, bottom: 50, left: 50, right: 50 } });\n      mockRAF();\n      scroller.scrollTo({ left: 50, top: 50 });\n\n      mockRAF();\n      scroller.scrolling({ globalX: 100, globalY: 100 });\n    });\n\n    it('scrollTarget: ScrollTarget, same left / top', () => {\n      const win = getMockWindow();\n      const scrollTarget = new ScrollTarget(win);\n      const scroller = new Scroller({ scrollTarget, bounds: { width: 50, height: 50, top: 50, bottom: 50, left: 50, right: 50 } });\n      mockRAF();\n      scrollTarget.scrollTo({ left: 50, top: 50 });\n      scroller.scrollTo({ left: 50, top: 50 });\n\n      mockRAF();\n      scroller.scrolling({ globalX: 100, globalY: 100 });\n    });\n\n    it('scrollTarget: Element', () => {\n      const win = getMockWindow();\n      // const scrollTarget = new ScrollTarget(win);\n      const scroller = new Scroller({ scrollTarget: win, bounds: { width: 50, height: 50, top: 50, bottom: 50, left: 50, right: 50 } });\n      mockRAF();\n      scroller.scrollTo({ left: 50, top: 50 });\n\n      mockRAF();\n      scroller.scrolling({ globalX: 100, globalY: 100 });\n    });\n\n    it('scrollTarget: null', () => {\n      const win = getMockWindow();\n      // const scrollTarget = new ScrollTarget(win);\n      const scroller = new Scroller({ scrollTarget: null, bounds: { width: 50, height: 50, top: 50, bottom: 50, left: 50, right: 50 } });\n      mockRAF();\n      scroller.scrollTo({ left: 50, top: 50 });\n\n      mockRAF();\n      scroller.scrolling({ globalX: 100, globalY: 100 });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/setting/__snapshots__/setting-field.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`setting-field 测试 纯粹的 UnitTest 常规方法 1`] = `\nObject {\n  \"extraProps\": Object {\n    \"defaultValue\": \"NORMAL\",\n    \"display\": \"inline\",\n  },\n  \"name\": \"behavior\",\n  \"setter\": Object {\n    \"componentName\": \"MixedSetter\",\n    \"props\": Object {\n      \"setters\": Array [\n        Object {\n          \"_owner\": null,\n          \"key\": null,\n          \"props\": Object {\n            \"cancelable\": false,\n            \"loose\": false,\n            \"options\": Array [\n              Object {\n                \"title\": \"普通\",\n                \"value\": \"NORMAL\",\n              },\n              Object {\n                \"title\": \"隐藏\",\n                \"value\": \"HIDDEN\",\n              },\n            ],\n          },\n          \"ref\": null,\n        },\n        \"VariableSetter\",\n      ],\n    },\n  },\n  \"title\": \"默认状态\",\n  \"type\": \"field\",\n}\n`;\n\nexports[`setting-field 测试 纯粹的 UnitTest 常规方法 2`] = `\nObject {\n  \"extraProps\": Object {\n    \"defaultValue\": \"NORMAL\",\n    \"display\": \"inline\",\n  },\n  \"name\": \"behavior\",\n  \"setter\": Object {\n    \"componentName\": \"MixedSetter\",\n    \"props\": Object {\n      \"setters\": Array [\n        Object {\n          \"_owner\": null,\n          \"key\": null,\n          \"props\": Object {\n            \"cancelable\": false,\n            \"loose\": false,\n            \"options\": Array [\n              Object {\n                \"title\": \"普通\",\n                \"value\": \"NORMAL\",\n              },\n              Object {\n                \"title\": \"隐藏\",\n                \"value\": \"HIDDEN\",\n              },\n            ],\n          },\n          \"ref\": null,\n        },\n        \"VariableSetter\",\n      ],\n    },\n  },\n  \"title\": \"默认状态\",\n  \"type\": \"field\",\n}\n`;\n"
  },
  {
    "path": "packages/designer/tests/designer/setting/setting-field.test.ts",
    "content": "// @ts-nocheck\nimport '../../fixtures/window';\nimport {\n  Editor,\n  Setters as InnerSetters,\n} from '@alilc/lowcode-editor-core';\nimport {\n  Setters,\n} from '@alilc/lowcode-shell';\nimport { SettingTopEntry } from '../../../src/designer/setting/setting-top-entry';\nimport { SettingField } from '../../../src/designer/setting/setting-field';\nimport { Node } from '../../../src/document/node/node';\nimport { Designer } from '../../../src/designer/designer';\nimport settingSchema from '../../fixtures/schema/setting';\nimport buttonMeta from '../../fixtures/component-metadata/button';\nimport { DocumentModel } from 'designer/src/document';\nimport { delayObxTick } from '../../utils';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\nconst editor = new Editor();\n\ndescribe('setting-field 测试', () => {\n  let designer: Designer;\n  let doc: DocumentModel;\n  let setters: Setters;\n  beforeEach(() => {\n    setters = new InnerSetters();\n    editor.set('setters', setters);\n    designer = new Designer({ editor, shellModelFactory });\n    designer.createComponentMeta(buttonMeta);\n    doc = designer.project.open(settingSchema);\n  });\n  afterEach(() => {\n    designer._componentMetasMap.clear();\n    designer = null;\n    doc.purge();\n    doc = null;\n  });\n\n  describe('纯粹的 UnitTest', () => {\n    let mockNode: Node;\n    let mockTopEntry: SettingTopEntry;\n    beforeEach(() => {\n      mockNode = new Node(designer.currentDocument, {\n        componentName: 'Button',\n        props: {\n          // a: 'str',\n          // b: 222,\n          // obj: {\n          //   x: 1,\n          // },\n          // jse: {\n          //   type: 'JSExpression',\n          //   value: 'state.a',\n          //   mock: 111,\n          // }\n        },\n      });\n      // mockTopEntry = new SettingTopEntry(editor, [mockNode]);\n    });\n    afterEach(() => {\n      mockNode = null;\n      mockTopEntry = null;\n    });\n\n    it('常规方法', () => {\n      // 普通 field\n      const settingEntry = mockNode.settingEntry;\n      const field = settingEntry.get('behavior');\n      expect(field.title).toBe('默认状态');\n      expect(field.expanded).toBeTruthy();\n      field.setExpanded(false);\n      expect(field.expanded).toBeFalsy();\n      expect(field.config).toMatchSnapshot();\n      expect(field.getConfig()).toMatchSnapshot();\n      expect(field.getConfig('extraProps')).toEqual({\n        display: 'inline',\n        defaultValue: 'NORMAL',\n      });\n      expect(field.items).toHaveLength(0);\n      expect(field.getItems()).toHaveLength(0);\n      expect(field.getItems(x => x)).toHaveLength(0);\n\n      expect(field.setter.componentName).toBe('MixedSetter');\n      field.purge();\n      expect(field.items).toHaveLength(0);\n\n      const subField = field.createField({\n        name: 'sub',\n        title: 'sub',\n      });\n      subField.setValue({\n        type: 'JSExpression',\n        value: 'state.a',\n        mock: 'haha',\n      });\n      subField.setHotValue('heihei');\n      expect(subField.getHotValue('heihei'));\n      expect(subField.getValue().mock).toBe('heihei');\n\n      // 不存在的 field\n      const nonExistingField = mockNode.settingEntry.get('non-exsiting');\n      expect(nonExistingField.setter).toBeNull();\n\n      // group 类型的 field\n      const groupField = settingEntry.get('groupkgzzeo41');\n      expect(groupField.items).toEqual([]);\n\n      // 有子节点的 field\n      const objField = settingEntry.get('obj');\n      expect(objField.items).toHaveLength(3);\n      expect(objField.getItems()).toHaveLength(3);\n      expect(objField.getItems(x => x.name === 'a')).toHaveLength(1);\n      objField.purge();\n      expect(objField.items).toHaveLength(0);\n      const objAField = settingEntry.get('obj.a');\n      expect(objAField.setter).toBe('StringSetter');\n    });\n\n    it('setValue / getValue / setHotValue / getHotValue', () => {\n      // 获取已有的 prop\n      const settingEntry = mockNode.settingEntry as SettingTopEntry;\n      const field = settingEntry.get('behavior');\n\n      // 会读取 extraProps.defaultValue\n      expect(field.getHotValue()).toBe('NORMAL');\n\n      field.setValue('HIDDEN');\n      expect(field.getValue()).toBe('HIDDEN');\n      expect(field.getHotValue()).toBe('HIDDEN');\n\n      field.setHotValue('DISABLED');\n      expect(field.getHotValue()).toBe('DISABLED');\n\n      field.setHotValue('NORMAL', { fromSetHotValue: true });\n      expect(field.getHotValue()).toBe('NORMAL');\n\n      field.setValue('HIDDEN', true);\n      expect(field.getHotValue()).toBe('HIDDEN');\n\n      // dirty fix list setter\n      field.setHotValue([{ __sid__: 1 }]);\n\n      // 数组的 field\n      const arrField = settingEntry.get('arr');\n      const subArrField = arrField.createField({\n        name: 0,\n        title: 'sub',\n      });\n      const subArrField02 = arrField.createField({\n        name: 1,\n        title: 'sub',\n      });\n      const subArrField03 = arrField.createField({\n        name: '2',\n        title: 'sub',\n      });\n      subArrField.setValue({name: '1'});\n      expect(subArrField.path).toEqual(['arr', 0]);\n      expect(subArrField02.path).toEqual(['arr', 1]);\n      subArrField02.setValue({name: '2'});\n      expect(subArrField.getValue()).toEqual({name: '1'});\n      expect(arrField.getHotValue()).toEqual([{name: '1'}, {name: '2'}]);\n      subArrField.clearValue();\n      expect(subArrField.getValue()).toBeUndefined();\n      expect(arrField.getHotValue()).toEqual([undefined, {name: '2'}]);\n      subArrField03.setValue({name: '3'});\n      expect(arrField.getHotValue()).toEqual([undefined, {name: '2'}, {name: '3'}]);\n    });\n\n    it('js expression setValue / setHotValue', () => {\n      const settingEntry = mockNode.settingEntry;\n      const field = settingEntry.get('behavior');\n\n      const subField = field.createField({\n        name: 'sub',\n        title: 'sub',\n      });\n      subField.setValue({\n        type: 'JSExpression',\n        value: 'state.a',\n        mock: 'haha',\n      });\n\n      subField.setHotValue({\n        type: 'JSExpression',\n        value: 'state.b',\n      });\n\n      expect(subField.getValue()).toEqual({\n        type: 'JSExpression',\n        value: 'state.b',\n        mock: 'haha',\n      });\n\n      subField.setHotValue('mock02');\n\n      expect(subField.getValue()).toEqual({\n        type: 'JSExpression',\n        value: 'state.b',\n        mock: 'mock02',\n      });\n    });\n\n    it('onEffect', async () => {\n      const settingEntry = mockNode.settingEntry as SettingTopEntry;\n      const field = settingEntry.get('behavior');\n\n      const mockFn = jest.fn();\n\n      field.onEffect(mockFn);\n\n      field.setValue('DISABLED');\n\n      await delayObxTick();\n\n      expect(mockFn).toHaveBeenCalled();\n    });\n\n    it('autorun', async () => {\n      const settingEntry = mockNode.settingEntry as SettingTopEntry;\n      const arrField = settingEntry.get('columns');\n      const subArrField = arrField.createField({\n        name: 0,\n        title: 'sub',\n      });\n      const objSubField = subArrField.createField({\n        name: 'objSub',\n        title: 'objSub',\n      });\n      const mockFnArrField = jest.fn();\n      const mockFnSubArrField = jest.fn();\n      const mockFnObjSubField = jest.fn();\n\n      arrField.setValue([{ objSub: \"subMock0.Index.0\" }]);\n      // 这里需要 setValue 两遍，触发 prop 的 purge 方法，使 purged 为 true，之后的 purge 方法不会正常执行，prop 才能正常缓存，autorun 才能正常执行\n      // TODO: 该机制后续得研究一下，再确定是否要修改\n      arrField.setValue([{ objSub: \"subMock0.Index.0\" }]);\n\n      arrField.onEffect(() => {\n        mockFnArrField(arrField.getValue());\n      });\n      arrField.onEffect(() => {\n        mockFnSubArrField(subArrField.getValue());\n      });\n      arrField.onEffect(() => {\n        mockFnObjSubField(objSubField.getValue());\n      });\n\n      await delayObxTick();\n\n      expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.0');\n      expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: \"subMock0.Index.0\" });\n      expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: \"subMock0.Index.0\" }]);\n\n      arrField.setValue([{ objSub: \"subMock0.Index.1\" }]);\n\n      await delayObxTick();\n\n      expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.1');\n      expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: \"subMock0.Index.1\" });\n      expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: \"subMock0.Index.1\" }]);\n\n      subArrField.setValue({ objSub: \"subMock0.Index.2\" });\n\n      await delayObxTick();\n\n      expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.2');\n      expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: \"subMock0.Index.2\" });\n      expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: \"subMock0.Index.2\" }]);\n\n      objSubField.setValue('subMock0.Index.3');\n\n      await delayObxTick();\n\n      expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.3');\n      expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: \"subMock0.Index.3\" });\n      expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: \"subMock0.Index.3\" }]);\n    })\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/setting/setting-prop-entry.test.ts",
    "content": "import '../../fixtures/window';\nimport {\n  Editor,\n  Setters as InnerSetters,\n} from '@alilc/lowcode-editor-core';\nimport { SettingTopEntry } from '../../../src/designer/setting/setting-top-entry';\nimport { SettingPropEntry } from '../../../src/designer/setting/setting-prop-entry';\nimport { Node } from '../../../src/document/node/node';\nimport { Designer } from '../../../src/designer/designer';\nimport settingSchema from '../../fixtures/schema/setting';\nimport divMeta from '../../fixtures/component-metadata/div';\nimport { DocumentModel } from 'designer/src/document';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\nconst editor = new Editor();\n\ndescribe('setting-prop-entry 测试', () => {\n  let designer: Designer;\n  let doc: DocumentModel;\n  let setters: any;\n  beforeEach(() => {\n    setters = new InnerSetters();\n    editor.set('setters', setters);\n    designer = new Designer({ editor, shellModelFactory });\n    designer.createComponentMeta(divMeta);\n    doc = designer.project.open(settingSchema);\n  });\n  afterEach(() => {\n    designer._componentMetasMap.clear();\n    designer = null;\n    doc.purge();\n    doc = null;\n  });\n\n  describe('纯粹的 UnitTest', () => {\n    let mockNode: Node;\n    let mockTopEntry: SettingTopEntry;\n    beforeEach(() => {\n      mockNode = new Node(designer.currentDocument, {\n        componentName: 'Button',\n        props: {\n          a: 'str',\n          b: 222,\n          obj: {\n            x: 1,\n          },\n          jse: {\n            type: 'JSExpression',\n            value: 'state.a',\n            mock: 111,\n          }\n        },\n      });\n      mockTopEntry = new SettingTopEntry(editor, [mockNode]);\n    });\n    afterEach(() => {\n      mockNode = null;\n      mockTopEntry = null;\n    });\n\n    it('常规方法', () => {\n      // type: group 类型\n      const prop = new SettingPropEntry(mockTopEntry, 'xGroup', 'group');\n      expect(prop.setKey('xxx')).toBeUndefined();\n      expect(prop.remove()).toBeUndefined();\n\n      const prop2 = new SettingPropEntry(mockTopEntry, '#xGroup');\n      expect(prop2.setKey('xxx')).toBeUndefined();\n      expect(prop2.remove()).toBeUndefined();\n\n      expect(prop.getVariableValue()).toBe('');\n    });\n\n    it('setValue / getValue / onValueChange', () => {\n      // 获取已有的 prop\n      const prop1 = mockTopEntry.getProp('a');\n      prop1.extraProps = {\n        getValue: (prop, val) => `prefix ${val}`,\n        // prop 是 shell prop entry\n        setValue: (prop, val) => { prop.setValue(`modified ${val}`, { disableMutator: true }) },\n        defaultValue: 'default',\n      };\n\n      expect(prop1.getDefaultValue()).toBe('default');\n      expect(prop1.getValue()).toBe('prefix str');\n\n      // disableMutator: true\n      prop1.setValue('bbb', false, false, { disableMutator: true });\n      expect(prop1.getValue()).toBe('prefix bbb');\n\n      // disableMutator: false\n      prop1.setValue('bbb');\n      expect(prop1.getValue()).toBe('prefix modified bbb');\n\n      const mockFn3 = jest.fn();\n      const prop2 = mockTopEntry.getProp('obj');\n      const prop3 = prop2.get('x');\n      const offFn = prop3.onValueChange(mockFn3);\n      expect(prop3.getValue()).toBe(1);\n      prop3.setValue(2);\n      expect(mockFn3).toHaveBeenCalled();\n\n      offFn();\n      prop3.setValue(3);\n      mockFn3.mockClear();\n      expect(mockFn3).toHaveBeenCalledTimes(0);\n\n      const prop4 = mockTopEntry.getProp('b');\n      prop4.extraProps = {\n        getValue: () => { throw 'error'; },\n      };\n      expect(prop4.getValue()).toBe(222);\n    });\n\n    it('clearValue', () => {\n      const prop1 = mockTopEntry.getProp('a');\n      prop1.clearValue();\n      expect(prop1.getValue()).toBeUndefined();\n\n      const mockFn = jest.fn();\n      prop1.extraProps = {\n        setValue: mockFn,\n      };\n      prop1.clearValue();\n      expect(mockFn).toHaveBeenCalled();\n    });\n\n    it('getVariableValue/ setUseVariable / isUseVariable / getMockOrValue', () => {\n      const prop1 = mockTopEntry.getProp('jse');\n\n      expect(prop1.isUseVariable()).toBeTruthy();\n      expect(prop1.useVariable).toBeTruthy();\n\n      expect(prop1.getMockOrValue()).toEqual(111);\n      expect(prop1.getVariableValue()).toEqual('state.a');\n\n      prop1.setUseVariable(false);\n      expect(prop1.getValue()).toEqual(111);\n      prop1.setUseVariable(true);\n      expect(prop1.getValue()).toEqual({\n        type: 'JSExpression',\n        value: '',\n        mock: 111,\n      });\n      prop1.setUseVariable(true);\n    });\n  });\n\n  describe('node 构造函数生成 settingEntry', () => {\n    it('常规方法测试', () => {\n      const divNode = doc?.getNode('div');\n\n      const { settingEntry } = divNode!;\n      const behaviorProp = settingEntry.getProp('behavior');\n      expect(behaviorProp.getProps()).toBe(settingEntry);\n      expect(behaviorProp.props).toBe(settingEntry);\n      expect(behaviorProp.getName()).toBe('behavior');\n      expect(behaviorProp.getKey()).toBe('behavior');\n      expect(behaviorProp.isIgnore()).toBeFalsy();\n      behaviorProp.setKey('behavior2');\n      expect(behaviorProp.getKey()).toBe('behavior2');\n      behaviorProp.setKey('behavior');\n\n      expect(behaviorProp.getNode()).toBe(divNode);\n      expect(behaviorProp.getId().startsWith('entry')).toBeTruthy();\n      expect(behaviorProp.designer).toBe(designer);\n      expect(behaviorProp.isSingle).toBeTruthy();\n      expect(behaviorProp.isMultiple).toBeFalsy();\n      expect(behaviorProp.isGroup).toBeFalsy();\n      expect(behaviorProp.isSameComponent).toBeTruthy();\n      expect(typeof settingEntry.getValue).toBe('function');\n      settingEntry.getValue();\n\n      behaviorProp.setExtraPropValue('extraPropA', 'heihei');\n      expect(behaviorProp.getExtraPropValue('extraPropA', 'heihei'));\n    });\n\n    it('setValue / getValue', () => {\n      const divNode = doc?.getNode('div');\n\n      const { settingEntry } = divNode!;\n      const behaviorProp = settingEntry.getProp('behavior');\n      expect(behaviorProp.getValue()).toBe('NORMAL');\n      expect(behaviorProp.getMockOrValue()).toBe('NORMAL');\n\n      behaviorProp.setValue('LARGE');\n      expect(behaviorProp.getValue()).toBe('LARGE');\n      // behaviorProp.setPropValue('behavior', 'SMALL');\n      // expect(behaviorProp.getValue()).toBe('SMALL');\n      behaviorProp.setValue('NORMAL');\n      expect(behaviorProp.getValue()).toBe('NORMAL');\n      behaviorProp.clearValue();\n      behaviorProp.clearPropValue();\n      expect(behaviorProp.getValue()).toBeUndefined();\n\n      behaviorProp.setValue('LARGE');\n      expect(behaviorProp.getValue()).toBe('LARGE');\n      behaviorProp.remove();\n      expect(divNode?.getProp('behavior').getValue()).toBeUndefined();\n    });\n\n    it.skip('type: group 场景测试', () => {});\n\n    it('JSExpression 类型的 prop', () => {\n      designer.createComponentMeta(divMeta);\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div');\n\n      const { settingEntry } = divNode!;\n      const customClassNameProp = settingEntry.getProp('customClassName');\n      expect(customClassNameProp.isUseVariable()).toBeTruthy();\n      expect(customClassNameProp.useVariable).toBeTruthy();\n\n      expect(customClassNameProp.getValue()).toEqual({\n        type: 'JSExpression',\n        value: 'getFromSomewhere()',\n      });\n      expect(customClassNameProp.getMockOrValue()).toBeUndefined();\n      expect(customClassNameProp.getVariableValue()).toBe('getFromSomewhere()');\n      customClassNameProp.setVariableValue('xxx');\n      expect(customClassNameProp.getVariableValue()).toBe('xxx');\n\n      const customClassName2Prop = settingEntry.getProp('customClassName2');\n      expect(customClassName2Prop.getMockOrValue()).toEqual({\n        hi: 'mock',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/designer/setting/setting-top-entry.test.ts",
    "content": "import '../../fixtures/window';\nimport { Editor, Setters } from '@alilc/lowcode-editor-core';\nimport { Node } from '../../../src/document/node/node';\nimport { Designer } from '../../../src/designer/designer';\nimport settingSchema from '../../fixtures/schema/setting';\nimport divMeta from '../../fixtures/component-metadata/div';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\nconst editor = new Editor();\n\ndescribe('setting-top-entry 测试', () => {\n  let designer: Designer;\n  beforeEach(() => {\n    editor.set('setters', new Setters())\n    designer = new Designer({ editor, shellModelFactory });\n  });\n  afterEach(() => {\n    designer._componentMetasMap.clear();\n    designer = null;\n  });\n\n  describe('node 构造函数生成 settingEntry', () => {\n    it('常规方法测试', () => {\n      designer.createComponentMeta(divMeta);\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div');\n\n      const { settingEntry } = divNode!;\n      expect(settingEntry.getPropValue('behavior')).toBe('NORMAL');\n      expect(settingEntry.getProp('behavior').getValue()).toBe('NORMAL');\n      settingEntry.setPropValue('behavior', 'LARGE');\n      expect(settingEntry.getPropValue('behavior')).toBe('LARGE');\n      expect(settingEntry.get('behavior').getValue()).toBe('LARGE');\n      settingEntry.getProp('behavior').setValue('SMALL');\n      expect(settingEntry.getPropValue('behavior')).toBe('SMALL');\n      settingEntry.clearPropValue('behavior');\n      expect(settingEntry.getPropValue('behavior')).toBeUndefined();\n\n      expect(settingEntry.getPropValue('fieldId')).toBe('div_k1ow3h1o');\n      settingEntry.setPropValue('fieldId', 'div_k1ow3h1o_new');\n      expect(settingEntry.getPropValue('fieldId')).toBe('div_k1ow3h1o_new');\n\n      expect(settingEntry.getExtraPropValue('extraPropA')).toBe('haha');\n      settingEntry.setExtraPropValue('extraPropA', 'haha2');\n      expect(settingEntry.getExtraPropValue('extraPropA')).toBe('haha2');\n\n      settingEntry.mergeProps({\n        newPropA: 'haha',\n      });\n      expect(settingEntry.getPropValue('newPropA')).toBe('haha');\n      settingEntry.setProps({\n        newPropB: 'haha',\n      });\n      expect(settingEntry.getPropValue('newPropB')).toBe('haha');\n      settingEntry.setValue({\n        newPropC: 'haha',\n      });\n      expect(settingEntry.getPropValue('newPropC')).toBe('haha');\n\n      expect(settingEntry.getPage()).toBe(currentDocument);\n      expect(settingEntry.getNode()).toBe(divNode);\n      expect(settingEntry.node).toBe(divNode);\n      expect(settingEntry.getId()).toBe('div');\n      expect(settingEntry.first).toBe(divNode);\n      expect(settingEntry.designer).toBe(designer);\n      expect(settingEntry.isSingle).toBeTruthy();\n      expect(settingEntry.isMultiple).toBeFalsy();\n      expect(settingEntry.isSameComponent).toBeTruthy();\n\n      expect(typeof settingEntry.getValue).toBe('function');\n      settingEntry.getValue();\n    });\n\n    it('onMetadataChange', () => {\n      designer.createComponentMeta(divMeta);\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div') as Node;\n\n      const { settingEntry } = divNode!;\n      const mockFn = jest.fn();\n      settingEntry.componentMeta.onMetadataChange(mockFn);\n      settingEntry.componentMeta.refreshMetadata();\n      expect(mockFn).toHaveBeenCalled();\n    });\n\n    it.skip('setupItems - customView', () => {\n      designer.createComponentMeta(divMeta);\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div') as Node;\n\n      const { settingEntry } = divNode;\n      // 模拟将第一个配置变成 react funcional component\n      settingEntry.componentMeta.getMetadata().combined[0].items[0] = props => props.xx;\n      settingEntry.setupItems();\n    });\n\n    it('清理方法测试', () => {\n      designer.createComponentMeta(divMeta);\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div');\n\n      const { settingEntry } = divNode!;\n      expect(settingEntry.items).toHaveLength(3);\n      settingEntry.purge();\n      expect(settingEntry.items).toHaveLength(0);\n    });\n\n    it('vision 兼容测试', () => {\n      designer.createComponentMeta(divMeta);\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div');\n\n      // console.log(divNode?.getPropValue('behavior'));\n      const { settingEntry } = divNode!;\n\n      expect(typeof settingEntry.getChildren).toBe('function');\n      expect(typeof settingEntry.getDOMNode).toBe('function');\n      expect(typeof settingEntry.getStatus).toBe('function');\n      expect(typeof settingEntry.setStatus).toBe('function');\n      settingEntry.getStatus();\n      settingEntry.setStatus();\n      settingEntry.getChildren();\n      settingEntry.getDOMNode();\n    });\n\n    it('没有 node', () => {\n      const create1 = designer.createSettingEntry.bind(designer);\n      const create2 = designer.createSettingEntry.bind(designer, []);\n      expect(create1).toThrowError('nodes should not be empty');\n      expect(create2).toThrowError('nodes should not be empty');\n    });\n  });\n\n  describe('designer.createSettingEntry 生成 settingEntry（多 node 场景）', () => {\n    it('相同类型的 node', () => {\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div');\n      const divNode2 = currentDocument?.getNode('div2');\n      const settingEntry = designer.createSettingEntry([divNode, divNode2]);\n\n      expect(settingEntry.isMultiple).toBeTruthy();\n      expect(settingEntry.isSameComponent).toBeTruthy();\n      expect(settingEntry.isSingle).toBeFalsy();\n\n      expect(settingEntry.getPropValue('behavior')).toBe('NORMAL');\n      expect(settingEntry.getProp('behavior').getValue()).toBe('NORMAL');\n      settingEntry.setPropValue('behavior', 'LARGE');\n      expect(settingEntry.getPropValue('behavior')).toBe('LARGE');\n      expect(settingEntry.get('behavior').getValue()).toBe('LARGE');\n      // 多个 node 都被成功设值\n      expect(divNode?.getPropValue('behavior')).toBe('LARGE');\n      expect(divNode2?.getPropValue('behavior')).toBe('LARGE');\n\n      settingEntry.getProp('behavior').setValue('SMALL');\n      expect(settingEntry.getPropValue('behavior')).toBe('SMALL');\n      // 多个 node 都被成功设值\n      expect(divNode?.getPropValue('behavior')).toBe('SMALL');\n      expect(divNode2?.getPropValue('behavior')).toBe('SMALL');\n\n      settingEntry.clearPropValue('behavior');\n      expect(settingEntry.getPropValue('behavior')).toBeUndefined();\n      // 多个 node 都被成功设值\n      expect(divNode?.getPropValue('behavior')).toBeUndefined();\n      expect(divNode2?.getPropValue('behavior')).toBeUndefined();\n\n      expect(settingEntry.getPropValue('fieldId')).toBe('div_k1ow3h1o');\n      settingEntry.setPropValue('fieldId', 'div_k1ow3h1o_new');\n      expect(settingEntry.getPropValue('fieldId')).toBe('div_k1ow3h1o_new');\n\n      expect(settingEntry.getExtraPropValue('extraPropA')).toBe('haha');\n      settingEntry.setExtraPropValue('extraPropA', 'haha2');\n      expect(settingEntry.getExtraPropValue('extraPropA')).toBe('haha2');\n    });\n\n    it('不同类型的 node', () => {\n      designer.project.open(settingSchema);\n      const { currentDocument } = designer.project;\n      const divNode = currentDocument?.getNode('div');\n      const testNode = currentDocument?.getNode('test');\n      const settingEntry = designer.createSettingEntry([divNode, testNode]);\n\n      expect(settingEntry.isMultiple).toBeTruthy();\n      expect(settingEntry.isSameComponent).toBeFalsy();\n      expect(settingEntry.isSingle).toBeFalsy();\n\n      // 不同类型的 node 场景下，理论上从页面上已没有修改属性的方法调用，所以此处不再断言各设值方法\n      // 思考：假如以后面向其他场景，比如用户用 API 强行调用，是否需要做健壮性保护？\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`document-model 测试 各种方法测试 1`] = `\nObject {\n  \"componentsMap\": Array [\n    Object {\n      \"componentName\": \"PageHeader\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"RootHeader\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"TextField\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"Column\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"SelectField\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"ColumnsLayout\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"CardContent\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"Card\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"Button\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"Div\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"Form\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"RootContent\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"RootFooter\",\n      \"devMode\": \"lowCode\",\n    },\n    Object {\n      \"componentName\": \"Page\",\n      \"devMode\": \"lowCode\",\n    },\n  ],\n  \"componentsTree\": Array [\n    Object {\n      \"children\": Array [\n        Object {\n          \"children\": Array [\n            Object {\n              \"componentName\": \"PageHeader\",\n              \"condition\": true,\n              \"conditionGroup\": \"\",\n              \"hidden\": false,\n              \"id\": \"node_k1ow3cbd\",\n              \"isLocked\": false,\n              \"props\": Object {\n                \"__slot__action\": false,\n                \"__slot__content\": false,\n                \"__slot__crumb\": false,\n                \"__slot__extraContent\": false,\n                \"__slot__logo\": false,\n                \"__slot__tab\": false,\n                \"__style__\": Object {},\n                \"action\": \"\",\n                \"content\": \"\",\n                \"crumb\": \"\",\n                \"extraContent\": \"\",\n                \"fieldId\": \"pageHeader_k1ow3h1i\",\n                \"logo\": \"\",\n                \"subTitle\": false,\n                \"tab\": \"\",\n                \"title\": Object {\n                  \"value\": Array [\n                    Object {\n                      \"componentName\": \"Text\",\n                      \"condition\": true,\n                      \"id\": \"node_k1ow3cbf\",\n                      \"props\": Object {\n                        \"__style__\": Object {},\n                        \"behavior\": \"NORMAL\",\n                        \"content\": Object {\n                          \"en-US\": \"Title\",\n                          \"type\": \"i18n\",\n                          \"use\": \"zh-CN\",\n                          \"zh-CN\": \"个人信息\",\n                        },\n                        \"fieldId\": \"text_k1ow3h1j\",\n                        \"maxLine\": 0,\n                        \"showTitle\": false,\n                      },\n                    },\n                  ],\n                },\n              },\n              \"title\": \"\",\n            },\n          ],\n          \"componentName\": \"RootHeader\",\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"hidden\": false,\n          \"id\": \"node_k1ow3cba\",\n          \"isLocked\": false,\n          \"props\": Object {},\n          \"title\": \"\",\n        },\n        Object {\n          \"children\": Array [\n            Object {\n              \"children\": Array [\n                Object {\n                  \"children\": Array [\n                    Object {\n                      \"children\": Array [\n                        Object {\n                          \"children\": Array [\n                            Object {\n                              \"children\": Array [\n                                Object {\n                                  \"componentName\": \"TextField\",\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"hidden\": false,\n                                  \"id\": \"node_k1ow3cbz\",\n                                  \"isLocked\": false,\n                                  \"props\": Object {\n                                    \"__category__\": \"form\",\n                                    \"__style__\": Object {},\n                                    \"__useMediator\": \"value\",\n                                    \"addonAfter\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"addonBefore\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"autoFocus\": false,\n                                    \"autoHeight\": false,\n                                    \"behavior\": \"NORMAL\",\n                                    \"cutString\": false,\n                                    \"fieldId\": \"textField_k1ow3h1w\",\n                                    \"fieldName\": \"name\",\n                                    \"hasClear\": false,\n                                    \"hasLimitHint\": false,\n                                    \"htmlType\": \"input\",\n                                    \"label\": Object {\n                                      \"en-US\": \"TextField\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"姓名\",\n                                    },\n                                    \"labelAlign\": \"top\",\n                                    \"labelColOffset\": 0,\n                                    \"labelColSpan\": 4,\n                                    \"labelTextAlign\": \"right\",\n                                    \"labelTipsIcon\": \"\",\n                                    \"labelTipsText\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"labelTipsTypes\": \"none\",\n                                    \"placeholder\": Object {\n                                      \"en-US\": \"please input\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"请输入\",\n                                    },\n                                    \"rows\": 4,\n                                    \"size\": \"medium\",\n                                    \"state\": \"\",\n                                    \"tips\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"trim\": false,\n                                    \"validation\": Array [\n                                      Object {\n                                        \"type\": \"required\",\n                                      },\n                                    ],\n                                    \"value\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"wrapperColOffset\": 0,\n                                    \"wrapperColSpan\": 0,\n                                  },\n                                  \"title\": \"\",\n                                },\n                                Object {\n                                  \"componentName\": \"TextField\",\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"hidden\": false,\n                                  \"id\": \"node_k1ow3cc1\",\n                                  \"isLocked\": false,\n                                  \"props\": Object {\n                                    \"__category__\": \"form\",\n                                    \"__style__\": Object {},\n                                    \"__useMediator\": \"value\",\n                                    \"addonAfter\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"addonBefore\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"autoFocus\": false,\n                                    \"autoHeight\": false,\n                                    \"behavior\": \"NORMAL\",\n                                    \"cutString\": false,\n                                    \"fieldId\": \"textField_k1ow3h1y\",\n                                    \"fieldName\": \"englishName\",\n                                    \"hasClear\": false,\n                                    \"hasLimitHint\": false,\n                                    \"htmlType\": \"input\",\n                                    \"label\": Object {\n                                      \"en-US\": \"TextField\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"英文名\",\n                                    },\n                                    \"labelAlign\": \"top\",\n                                    \"labelColOffset\": 0,\n                                    \"labelColSpan\": 4,\n                                    \"labelTextAlign\": \"right\",\n                                    \"labelTipsIcon\": \"\",\n                                    \"labelTipsText\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"labelTipsTypes\": \"none\",\n                                    \"placeholder\": Object {\n                                      \"en-US\": \"please input\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"请输入\",\n                                    },\n                                    \"rows\": 4,\n                                    \"size\": \"medium\",\n                                    \"state\": \"\",\n                                    \"tips\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"trim\": false,\n                                    \"validation\": Array [],\n                                    \"value\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"wrapperColOffset\": 0,\n                                    \"wrapperColSpan\": 0,\n                                  },\n                                  \"title\": \"\",\n                                },\n                                Object {\n                                  \"componentName\": \"TextField\",\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"hidden\": false,\n                                  \"id\": \"node_k1ow3cc3\",\n                                  \"isLocked\": false,\n                                  \"props\": Object {\n                                    \"__category__\": \"form\",\n                                    \"__style__\": Object {},\n                                    \"__useMediator\": \"value\",\n                                    \"addonAfter\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"addonBefore\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"autoFocus\": false,\n                                    \"autoHeight\": false,\n                                    \"behavior\": \"NORMAL\",\n                                    \"cutString\": false,\n                                    \"fieldId\": \"textField_k1ow3h20\",\n                                    \"fieldName\": \"jobTitle\",\n                                    \"hasClear\": false,\n                                    \"hasLimitHint\": false,\n                                    \"htmlType\": \"input\",\n                                    \"label\": Object {\n                                      \"en-US\": \"TextField\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"职位\",\n                                    },\n                                    \"labelAlign\": \"top\",\n                                    \"labelColOffset\": 0,\n                                    \"labelColSpan\": 4,\n                                    \"labelTextAlign\": \"right\",\n                                    \"labelTipsIcon\": \"\",\n                                    \"labelTipsText\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"labelTipsTypes\": \"none\",\n                                    \"placeholder\": Object {\n                                      \"en-US\": \"please input\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"请输入\",\n                                    },\n                                    \"rows\": 4,\n                                    \"size\": \"medium\",\n                                    \"state\": \"\",\n                                    \"tips\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"trim\": false,\n                                    \"validation\": Array [],\n                                    \"value\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"wrapperColOffset\": 0,\n                                    \"wrapperColSpan\": 0,\n                                  },\n                                  \"title\": \"\",\n                                },\n                              ],\n                              \"componentName\": \"Column\",\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"hidden\": false,\n                              \"id\": \"node_k1ow3cbx\",\n                              \"isLocked\": false,\n                              \"props\": Object {\n                                \"__style__\": Object {},\n                                \"colSpan\": \"\",\n                                \"fieldId\": \"column_k1p1bnjm\",\n                              },\n                              \"title\": \"\",\n                            },\n                            Object {\n                              \"children\": Array [\n                                Object {\n                                  \"componentName\": \"TextField\",\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"hidden\": false,\n                                  \"id\": \"node_k1ow3cc2\",\n                                  \"isLocked\": false,\n                                  \"props\": Object {\n                                    \"__category__\": \"form\",\n                                    \"__style__\": Object {},\n                                    \"__useMediator\": \"value\",\n                                    \"addonAfter\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"addonBefore\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"autoFocus\": false,\n                                    \"autoHeight\": false,\n                                    \"behavior\": \"NORMAL\",\n                                    \"cutString\": false,\n                                    \"fieldId\": \"textField_k1ow3h1z\",\n                                    \"fieldName\": \"nickName\",\n                                    \"hasClear\": false,\n                                    \"hasLimitHint\": false,\n                                    \"htmlType\": \"input\",\n                                    \"label\": Object {\n                                      \"en-US\": \"TextField\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"花名\",\n                                    },\n                                    \"labelAlign\": \"top\",\n                                    \"labelColOffset\": 0,\n                                    \"labelColSpan\": 4,\n                                    \"labelTextAlign\": \"right\",\n                                    \"labelTipsIcon\": \"\",\n                                    \"labelTipsText\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"labelTipsTypes\": \"none\",\n                                    \"placeholder\": Object {\n                                      \"en-US\": \"please input\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"请输入\",\n                                    },\n                                    \"rows\": 4,\n                                    \"size\": \"medium\",\n                                    \"state\": \"\",\n                                    \"tips\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"trim\": false,\n                                    \"validation\": Array [],\n                                    \"value\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"wrapperColOffset\": 0,\n                                    \"wrapperColSpan\": 0,\n                                  },\n                                  \"title\": \"\",\n                                },\n                                Object {\n                                  \"componentName\": \"SelectField\",\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"hidden\": false,\n                                  \"id\": \"node_k1ow3cc0\",\n                                  \"isLocked\": false,\n                                  \"props\": Object {\n                                    \"__category__\": \"form\",\n                                    \"__style__\": Object {},\n                                    \"__useMediator\": \"value\",\n                                    \"autoWidth\": true,\n                                    \"behavior\": \"NORMAL\",\n                                    \"dataSource\": Array [\n                                      Object {\n                                        \"__sid__\": \"serial_k1owc4t1\",\n                                        \"defaultChecked\": false,\n                                        \"sid\": \"opt_k1owc4t2\",\n                                        \"text\": Object {\n                                          \"__sid__\": \"param_k1owc4tb\",\n                                          \"en-US\": \"Option 1\",\n                                          \"type\": \"i18n\",\n                                          \"zh-CN\": \"男\",\n                                        },\n                                        \"value\": \"M\",\n                                      },\n                                      Object {\n                                        \"__sid__\": \"serial_k1owc4t2\",\n                                        \"defaultChecked\": false,\n                                        \"sid\": \"opt_k1owc4t3\",\n                                        \"text\": Object {\n                                          \"__sid__\": \"param_k1owc4tf\",\n                                          \"en-US\": \"Option 2\",\n                                          \"type\": \"i18n\",\n                                          \"zh-CN\": \"女\",\n                                        },\n                                        \"value\": \"F\",\n                                      },\n                                    ],\n                                    \"fieldId\": \"select_k1ow3h1x\",\n                                    \"fieldName\": \"gender\",\n                                    \"filterLocal\": true,\n                                    \"hasArrow\": true,\n                                    \"hasBorder\": true,\n                                    \"hasClear\": false,\n                                    \"hasSelectAll\": false,\n                                    \"label\": Object {\n                                      \"en-US\": \"SelectField\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"性别\",\n                                    },\n                                    \"labelAlign\": \"top\",\n                                    \"labelColOffset\": 0,\n                                    \"labelColSpan\": 4,\n                                    \"labelTextAlign\": \"right\",\n                                    \"labelTipsIcon\": \"\",\n                                    \"labelTipsText\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"labelTipsTypes\": \"none\",\n                                    \"mode\": \"single\",\n                                    \"notFoundContent\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                    },\n                                    \"placeholder\": Object {\n                                      \"en-US\": \"please select\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"请选择\",\n                                    },\n                                    \"searchDelay\": 300,\n                                    \"showSearch\": false,\n                                    \"size\": \"medium\",\n                                    \"tips\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"validation\": Array [\n                                      Object {\n                                        \"type\": \"required\",\n                                      },\n                                    ],\n                                    \"value\": \"\",\n                                    \"wrapperColOffset\": 0,\n                                    \"wrapperColSpan\": 0,\n                                  },\n                                  \"title\": \"\",\n                                },\n                              ],\n                              \"componentName\": \"Column\",\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"hidden\": false,\n                              \"id\": \"node_k1ow3cby\",\n                              \"isLocked\": false,\n                              \"props\": Object {\n                                \"__style__\": Object {},\n                                \"colSpan\": \"\",\n                                \"fieldId\": \"column_k1p1bnjn\",\n                              },\n                              \"title\": \"\",\n                            },\n                          ],\n                          \"componentName\": \"ColumnsLayout\",\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"hidden\": false,\n                          \"id\": \"node_k1ow3cbw\",\n                          \"isLocked\": false,\n                          \"props\": Object {\n                            \"__style__\": Object {},\n                            \"columnGap\": \"20\",\n                            \"fieldId\": \"columns_k1ow3h1v\",\n                            \"layout\": \"6:6\",\n                            \"rowGap\": 0,\n                          },\n                          \"title\": \"\",\n                        },\n                      ],\n                      \"componentName\": \"CardContent\",\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"hidden\": false,\n                      \"id\": \"node_k1ow3cbk\",\n                      \"isLocked\": false,\n                      \"props\": Object {},\n                      \"title\": \"\",\n                    },\n                  ],\n                  \"componentName\": \"Card\",\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"hidden\": false,\n                  \"id\": \"node_k1ow3cbj\",\n                  \"isLocked\": false,\n                  \"props\": Object {\n                    \"__slot__extra\": false,\n                    \"__slot__subTitle\": false,\n                    \"__slot__title\": false,\n                    \"__style__\": \":root {\n  margin-bottom: 12px;\n}\",\n                    \"className\": \"card_kgaqfbm5\",\n                    \"contentHeight\": \"\",\n                    \"dividerNoInset\": false,\n                    \"extra\": Object {\n                      \"type\": \"i18n\",\n                      \"use\": \"zh-CN\",\n                      \"zh-CN\": \"\",\n                    },\n                    \"fieldId\": \"card_k1ow3h1l\",\n                    \"showHeadDivider\": true,\n                    \"showTitleBullet\": true,\n                    \"subTitle\": Object {\n                      \"en-US\": \"\",\n                      \"type\": \"i18n\",\n                      \"use\": \"zh-CN\",\n                      \"zh-CN\": \"\",\n                    },\n                    \"title\": Object {\n                      \"en-US\": \"Title\",\n                      \"type\": \"i18n\",\n                      \"use\": \"zh-CN\",\n                      \"zh-CN\": \"基本信息\",\n                    },\n                  },\n                  \"title\": \"\",\n                },\n                Object {\n                  \"children\": Array [\n                    Object {\n                      \"children\": Array [\n                        Object {\n                          \"componentName\": \"TextField\",\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"hidden\": false,\n                          \"id\": \"node_k1ow3cc4\",\n                          \"isLocked\": false,\n                          \"props\": Object {\n                            \"__category__\": \"form\",\n                            \"__style__\": Object {},\n                            \"__useMediator\": \"value\",\n                            \"addonAfter\": Object {\n                              \"type\": \"i18n\",\n                              \"use\": \"zh-CN\",\n                              \"zh-CN\": \"\",\n                            },\n                            \"addonBefore\": Object {\n                              \"type\": \"i18n\",\n                              \"use\": \"zh-CN\",\n                              \"zh-CN\": \"\",\n                            },\n                            \"autoFocus\": false,\n                            \"autoHeight\": false,\n                            \"behavior\": \"NORMAL\",\n                            \"cutString\": false,\n                            \"fieldId\": \"textField_k1ow3h21\",\n                            \"fieldName\": \"department\",\n                            \"hasClear\": false,\n                            \"hasLimitHint\": false,\n                            \"htmlType\": \"input\",\n                            \"label\": Object {\n                              \"en-US\": \"TextField\",\n                              \"type\": \"i18n\",\n                              \"use\": \"zh-CN\",\n                              \"zh-CN\": \"所属部门\",\n                            },\n                            \"labelAlign\": \"top\",\n                            \"labelColOffset\": 0,\n                            \"labelColSpan\": 4,\n                            \"labelTextAlign\": \"right\",\n                            \"labelTipsIcon\": \"\",\n                            \"labelTipsText\": Object {\n                              \"en-US\": \"\",\n                              \"type\": \"i18n\",\n                              \"use\": \"zh-CN\",\n                              \"zh-CN\": \"\",\n                            },\n                            \"labelTipsTypes\": \"none\",\n                            \"placeholder\": Object {\n                              \"en-US\": \"please input\",\n                              \"type\": \"i18n\",\n                              \"use\": \"zh-CN\",\n                              \"zh-CN\": \"请输入\",\n                            },\n                            \"rows\": 4,\n                            \"size\": \"medium\",\n                            \"state\": \"\",\n                            \"tips\": Object {\n                              \"en-US\": \"\",\n                              \"type\": \"i18n\",\n                              \"zh-CN\": \"\",\n                            },\n                            \"trim\": false,\n                            \"validation\": Array [],\n                            \"value\": Object {\n                              \"type\": \"i18n\",\n                              \"use\": \"zh-CN\",\n                              \"zh-CN\": \"\",\n                            },\n                            \"wrapperColOffset\": 0,\n                            \"wrapperColSpan\": 0,\n                          },\n                          \"title\": \"\",\n                        },\n                        Object {\n                          \"children\": Array [\n                            Object {\n                              \"children\": Array [\n                                Object {\n                                  \"componentName\": \"TextField\",\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"hidden\": false,\n                                  \"id\": \"node_k1ow3cc8\",\n                                  \"isLocked\": false,\n                                  \"props\": Object {\n                                    \"__category__\": \"form\",\n                                    \"__style__\": Object {},\n                                    \"__useMediator\": \"value\",\n                                    \"addonAfter\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"addonBefore\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"autoFocus\": false,\n                                    \"autoHeight\": false,\n                                    \"behavior\": \"NORMAL\",\n                                    \"cutString\": false,\n                                    \"fieldId\": \"textField_k1ow3h23\",\n                                    \"fieldName\": \"leader\",\n                                    \"hasClear\": false,\n                                    \"hasLimitHint\": false,\n                                    \"htmlType\": \"input\",\n                                    \"label\": Object {\n                                      \"en-US\": \"TextField\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"主管\",\n                                    },\n                                    \"labelAlign\": \"top\",\n                                    \"labelColOffset\": 0,\n                                    \"labelColSpan\": 4,\n                                    \"labelTextAlign\": \"right\",\n                                    \"labelTipsIcon\": \"\",\n                                    \"labelTipsText\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"labelTipsTypes\": \"none\",\n                                    \"placeholder\": Object {\n                                      \"en-US\": \"please input\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"请输入\",\n                                    },\n                                    \"rows\": 4,\n                                    \"size\": \"medium\",\n                                    \"state\": \"\",\n                                    \"tips\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"trim\": false,\n                                    \"validation\": Array [],\n                                    \"value\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"wrapperColOffset\": 0,\n                                    \"wrapperColSpan\": 0,\n                                  },\n                                  \"title\": \"\",\n                                },\n                              ],\n                              \"componentName\": \"Column\",\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"hidden\": false,\n                              \"id\": \"node_k1ow3cc6\",\n                              \"isLocked\": false,\n                              \"props\": Object {\n                                \"__style__\": Object {},\n                                \"colSpan\": \"\",\n                                \"fieldId\": \"column_k1p1bnjo\",\n                              },\n                              \"title\": \"\",\n                            },\n                            Object {\n                              \"children\": Array [\n                                Object {\n                                  \"componentName\": \"TextField\",\n                                  \"condition\": true,\n                                  \"conditionGroup\": \"\",\n                                  \"hidden\": false,\n                                  \"id\": \"node_k1ow3cc9\",\n                                  \"isLocked\": false,\n                                  \"props\": Object {\n                                    \"__category__\": \"form\",\n                                    \"__style__\": Object {},\n                                    \"__useMediator\": \"value\",\n                                    \"addonAfter\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"addonBefore\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"autoFocus\": false,\n                                    \"autoHeight\": false,\n                                    \"behavior\": \"NORMAL\",\n                                    \"cutString\": false,\n                                    \"fieldId\": \"textField_k1ow3h24\",\n                                    \"fieldName\": \"hrg\",\n                                    \"hasClear\": false,\n                                    \"hasLimitHint\": false,\n                                    \"htmlType\": \"input\",\n                                    \"label\": Object {\n                                      \"en-US\": \"TextField\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"HRG\",\n                                    },\n                                    \"labelAlign\": \"top\",\n                                    \"labelColOffset\": 0,\n                                    \"labelColSpan\": 4,\n                                    \"labelTextAlign\": \"right\",\n                                    \"labelTipsIcon\": \"\",\n                                    \"labelTipsText\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"labelTipsTypes\": \"none\",\n                                    \"placeholder\": Object {\n                                      \"en-US\": \"please input\",\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"请输入\",\n                                    },\n                                    \"rows\": 4,\n                                    \"size\": \"medium\",\n                                    \"state\": \"\",\n                                    \"tips\": Object {\n                                      \"en-US\": \"\",\n                                      \"type\": \"i18n\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"trim\": false,\n                                    \"validation\": Array [],\n                                    \"value\": Object {\n                                      \"type\": \"i18n\",\n                                      \"use\": \"zh-CN\",\n                                      \"zh-CN\": \"\",\n                                    },\n                                    \"wrapperColOffset\": 0,\n                                    \"wrapperColSpan\": 0,\n                                  },\n                                  \"title\": \"\",\n                                },\n                              ],\n                              \"componentName\": \"Column\",\n                              \"condition\": true,\n                              \"conditionGroup\": \"\",\n                              \"hidden\": false,\n                              \"id\": \"node_k1ow3cc7\",\n                              \"isLocked\": false,\n                              \"props\": Object {\n                                \"__style__\": Object {},\n                                \"colSpan\": \"\",\n                                \"fieldId\": \"column_k1p1bnjp\",\n                              },\n                              \"title\": \"\",\n                            },\n                          ],\n                          \"componentName\": \"ColumnsLayout\",\n                          \"condition\": true,\n                          \"conditionGroup\": \"\",\n                          \"hidden\": false,\n                          \"id\": \"node_k1ow3cc5\",\n                          \"isLocked\": false,\n                          \"props\": Object {\n                            \"__style__\": Object {},\n                            \"columnGap\": \"20\",\n                            \"fieldId\": \"columns_k1ow3h22\",\n                            \"layout\": \"6:6\",\n                            \"rowGap\": 0,\n                          },\n                          \"title\": \"\",\n                        },\n                      ],\n                      \"componentName\": \"CardContent\",\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"hidden\": false,\n                      \"id\": \"node_k1ow3cbm\",\n                      \"isLocked\": false,\n                      \"props\": Object {},\n                      \"title\": \"\",\n                    },\n                  ],\n                  \"componentName\": \"Card\",\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"hidden\": false,\n                  \"id\": \"node_k1ow3cbl\",\n                  \"isLocked\": false,\n                  \"props\": Object {\n                    \"__slot__extra\": false,\n                    \"__slot__subTitle\": false,\n                    \"__slot__title\": false,\n                    \"__style__\": \":root {\n  margin-bottom: 12px;\n}\",\n                    \"className\": \"card_kgaqfbm6\",\n                    \"contentHeight\": \"\",\n                    \"dividerNoInset\": false,\n                    \"extra\": Object {\n                      \"type\": \"i18n\",\n                      \"use\": \"zh-CN\",\n                      \"zh-CN\": \"\",\n                    },\n                    \"fieldId\": \"card_k1ow3h1m\",\n                    \"showHeadDivider\": true,\n                    \"showTitleBullet\": true,\n                    \"subTitle\": Object {\n                      \"en-US\": \"\",\n                      \"type\": \"i18n\",\n                      \"use\": \"zh-CN\",\n                      \"zh-CN\": \"\",\n                    },\n                    \"title\": Object {\n                      \"en-US\": \"Title\",\n                      \"type\": \"i18n\",\n                      \"use\": \"zh-CN\",\n                      \"zh-CN\": \"部门信息\",\n                    },\n                  },\n                  \"title\": \"\",\n                },\n                Object {\n                  \"children\": Array [\n                    Object {\n                      \"componentName\": \"Button\",\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"hidden\": false,\n                      \"id\": \"node_k1ow3cbn\",\n                      \"isLocked\": false,\n                      \"props\": Object {\n                        \"__style__\": \":root {\n  margin-right: 16px;\n  width: 80px\n}\",\n                        \"baseIcon\": \"\",\n                        \"behavior\": \"NORMAL\",\n                        \"className\": \"button_kgaqfbm7\",\n                        \"content\": Object {\n                          \"en-US\": \"Button\",\n                          \"type\": \"i18n\",\n                          \"use\": \"zh-CN\",\n                          \"zh-CN\": \"提交\",\n                        },\n                        \"fieldId\": \"button_k1ow3h1n\",\n                        \"loading\": false,\n                        \"onClick\": Object {\n                          \"events\": Array [\n                            Object {\n                              \"id\": \"submit\",\n                              \"name\": \"submit\",\n                              \"params\": Object {},\n                              \"type\": \"actionRef\",\n                              \"uuid\": \"1570966253282_0\",\n                            },\n                          ],\n                          \"rawType\": \"events\",\n                          \"type\": \"JSExpression\",\n                          \"value\": \"this.utils.legaoBuiltin.execEventFlow.bind(this, [this.submit])\",\n                        },\n                        \"otherIcon\": \"\",\n                        \"size\": \"medium\",\n                        \"triggerEventsWhenLoading\": false,\n                        \"type\": \"primary\",\n                      },\n                      \"title\": \"\",\n                    },\n                    Object {\n                      \"componentName\": \"Button\",\n                      \"condition\": true,\n                      \"conditionGroup\": \"\",\n                      \"hidden\": false,\n                      \"id\": \"node_k1ow3cbp\",\n                      \"isLocked\": false,\n                      \"props\": Object {\n                        \"__style__\": \":root {\n  width: 80px;\n}\",\n                        \"baseIcon\": \"\",\n                        \"behavior\": \"NORMAL\",\n                        \"className\": \"button_kgaqfbm8\",\n                        \"content\": Object {\n                          \"en-US\": \"Button\",\n                          \"type\": \"i18n\",\n                          \"use\": \"zh-CN\",\n                          \"zh-CN\": \"取消\",\n                        },\n                        \"fieldId\": \"button_k1ow3h1p\",\n                        \"greeting\": Object {\n                          \"value\": Array [\n                            Object {\n                              \"componentName\": \"Text\",\n                              \"props\": Object {},\n                            },\n                          ],\n                        },\n                        \"loading\": false,\n                        \"otherIcon\": \"\",\n                        \"size\": \"medium\",\n                        \"triggerEventsWhenLoading\": false,\n                        \"type\": \"normal\",\n                      },\n                      \"title\": \"\",\n                    },\n                  ],\n                  \"componentName\": \"Div\",\n                  \"condition\": true,\n                  \"conditionGroup\": \"\",\n                  \"hidden\": false,\n                  \"id\": \"node_k1ow3cbo\",\n                  \"isLocked\": false,\n                  \"props\": Object {\n                    \"__style__\": \":root {\n  display: flex;\n  align-items: flex-start;\n  justify-content: center;\n  background: #fff;\n  padding: 20px 0;\n}\",\n                    \"behavior\": \"NORMAL\",\n                    \"className\": \"div_kgaqfbm9\",\n                    \"customClassName\": \"\",\n                    \"events\": Object {},\n                    \"fieldId\": \"div_k1ow3h1o\",\n                    \"useFieldIdAsDomId\": false,\n                  },\n                  \"title\": \"\",\n                },\n              ],\n              \"componentName\": \"Form\",\n              \"condition\": true,\n              \"conditionGroup\": \"\",\n              \"extraPropA\": \"extraPropA\",\n              \"hidden\": false,\n              \"id\": \"form\",\n              \"isLocked\": false,\n              \"props\": Object {\n                \"__style__\": Object {},\n                \"autoUnmount\": true,\n                \"autoValidate\": true,\n                \"behavior\": \"NORMAL\",\n                \"dataSource\": Object {\n                  \"type\": \"variable\",\n                  \"variable\": \"state.formData\",\n                },\n                \"fieldId\": \"form\",\n                \"fieldOptions\": Object {},\n                \"labelAlign\": \"top\",\n                \"obj\": Object {\n                  \"a\": 1,\n                  \"b\": false,\n                  \"c\": \"string\",\n                },\n                \"scrollToFirstError\": true,\n                \"size\": \"medium\",\n                \"slotA\": \"\",\n              },\n              \"title\": \"\",\n            },\n          ],\n          \"componentName\": \"RootContent\",\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"hidden\": false,\n          \"id\": \"node_k1ow3cbb\",\n          \"isLocked\": false,\n          \"props\": Object {\n            \"contentBgColor\": \"transparent\",\n            \"contentMargin\": \"20\",\n            \"contentPadding\": \"0\",\n          },\n          \"title\": \"\",\n        },\n        Object {\n          \"componentName\": \"RootFooter\",\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"hidden\": false,\n          \"id\": \"node_k1ow3cbc\",\n          \"isLocked\": false,\n          \"props\": Object {},\n          \"title\": \"\",\n        },\n      ],\n      \"componentName\": \"Page\",\n      \"condition\": true,\n      \"conditionGroup\": \"\",\n      \"css\": \"body{background-color:#f2f3f5}.card_kgaqfbm5 {\n  margin-bottom: 12px;\n}.card_kgaqfbm6 {\n  margin-bottom: 12px;\n}.button_kgaqfbm7 {\n  margin-right: 16px;\n  width: 80px\n}.button_kgaqfbm8 {\n  width: 80px;\n}.div_kgaqfbm9 {\n  display: flex;\n  align-items: flex-start;\n  justify-content: center;\n  background: #fff;\n  padding: 20px 0;\n}\",\n      \"dataSource\": Object {\n        \"globalConfig\": Object {\n          \"fit\": Object {\n            \"compiled\": \"\",\n            \"error\": Object {},\n            \"source\": \"\",\n            \"type\": \"js\",\n          },\n        },\n        \"list\": Array [],\n        \"offline\": Array [],\n        \"online\": Array [],\n        \"sync\": true,\n      },\n      \"hidden\": false,\n      \"i18n\": Object {\n        \"en-US\": Object {\n          \"i18n-jwg27yo3\": \"China\",\n          \"i18n-jwg27yo4\": \"Hello\",\n        },\n        \"zh-CN\": Object {\n          \"i18n-jwg27yo3\": \"中国\",\n          \"i18n-jwg27yo4\": \"你好\",\n        },\n      },\n      \"id\": \"page\",\n      \"isLocked\": false,\n      \"lifeCycles\": Object {\n        \"constructor\": Object {\n          \"compiled\": \"function constructor() {\nvar module = { exports: {} };\nvar _this = this;\nthis.__initMethods__(module.exports, module);\nObject.keys(module.exports).forEach(function(item) {\n  if(typeof module.exports[item] === 'function'){\n    _this[item] = module.exports[item];\n  }\n});\n\n}\",\n          \"source\": \"function constructor() {\nvar module = { exports: {} };\nvar _this = this;\nthis.__initMethods__(module.exports, module);\nObject.keys(module.exports).forEach(function(item) {\n  if(typeof module.exports[item] === 'function'){\n    _this[item] = module.exports[item];\n  }\n});\n\n}\",\n          \"type\": \"js\",\n        },\n      },\n      \"methods\": Object {\n        \"__initMethods__\": Object {\n          \"compiled\": \"function (exports, module) { /*set actions code here*/ }\",\n          \"source\": \"function (exports, module) { /*set actions code here*/ }\",\n          \"type\": \"js\",\n        },\n      },\n      \"props\": Object {\n        \"className\": \"page_kgaqfbm4\",\n        \"containerStyle\": Object {},\n        \"extensions\": Object {\n          \"启用页头\": true,\n        },\n        \"pageStyle\": Object {\n          \"backgroundColor\": \"#f2f3f5\",\n        },\n        \"templateVersion\": \"1.0.0\",\n      },\n      \"title\": \"hey, i' a page!\",\n    },\n  ],\n  \"utils\": undefined,\n}\n`;\n\nexports[`document-model 测试 各种方法测试 2`] = `null`;\n"
  },
  {
    "path": "packages/designer/tests/document/document-model/document-model.test.ts",
    "content": "import '../../fixtures/window';\nimport { DocumentModel, isDocumentModel, isPageSchema } from '../../../src/document/document-model';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../../src/project/project';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form';\nimport divMeta from '../../fixtures/component-metadata/div';\nimport formMeta from '../../fixtures/component-metadata/form';\nimport otherMeta from '../../fixtures/component-metadata/other';\nimport pageMeta from '../../fixtures/component-metadata/page';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\ndescribe('document-model 测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n\n  beforeEach(() => {\n    editor = new Editor();\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n  });\n\n  it('empty schema', () => {\n    const doc = new DocumentModel(project);\n    expect(doc.rootNode?.id).toBe('root');\n    expect(doc.currentRoot).toBe(doc.rootNode);\n    expect(doc.root).toBe(doc.rootNode);\n    expect(doc.modalNode).toBeUndefined();\n    expect(doc.isBlank()).toBeTruthy();\n    expect(doc.schema).toEqual({\n      componentName: 'Page',\n      condition: true,\n      conditionGroup: '',\n      hidden: false,\n      isLocked: false,\n      loop: undefined,\n      title: '',\n      id: 'root',\n      fileName: '',\n      props: {},\n    });\n  });\n\n  it('各种方法测试', () => {\n    const doc = new DocumentModel(project, formSchema);\n    const mockNode = { id: 1 };\n    doc.addWillPurge(mockNode);\n    expect(doc.willPurgeSpace).toHaveLength(1);\n    doc.removeWillPurge(mockNode);\n    expect(doc.willPurgeSpace).toHaveLength(0);\n\n    expect(doc.toData()).toMatchSnapshot();\n\n    // 测试插入已存在的 id，id 将会被重置\n    const formParentNode = doc.getNode('form').parent;\n    doc.insertNode(formParentNode, { id: 'form', componentName: 'Form' });\n    expect(formParentNode.children.get(formParentNode.children.size - 1).id).not.toBe('form');\n\n    doc.internalRemoveAndPurgeNode({ id: 'mockId' });\n\n    // internalSetDropLocation\n    doc.dropLocation = { a: 1 };\n    expect(doc.dropLocation).toEqual({ a: 1 });\n\n    // wrapWith\n    // none-selected\n    doc.wrapWith({ componentName: 'Wrap' });\n    doc.selection.select('form');\n    doc.wrapWith({ componentName: 'Wrap' });\n    expect(doc.getNode('form').parent.componentName).toBe('Wrap');\n    expect(doc.wrapWith({ componentName: 'Leaf' })).toBeNull();\n\n    // fileName\n    expect(doc.fileName).toBeTruthy();\n    doc.fileName = 'fileName';\n    expect(doc.fileName).toBe('fileName');\n\n    expect(doc.getNodeSchema(doc.getNode('form'))).toMatchSnapshot();\n\n    // TODO:\n    // expect(doc.simulatorProps).toMatchSnapshot();\n\n    const mockSimulator = {\n      isSimulator: true,\n      getComponent() {\n        return 'haha';\n      },\n      setSuspense() {},\n    };\n    doc.project.mountSimulator(mockSimulator);\n    expect(doc.simulator).toEqual(mockSimulator);\n    expect(doc.getComponent('Div')).toBe('haha');\n\n    expect(doc.opened).toBeFalsy();\n    expect(doc.isModified).toBeTruthy();\n    expect(doc.suspensed).toBeTruthy();\n\n    doc.open();\n    expect(doc.opened).toBeTruthy();\n    expect(doc.actived).toBeTruthy();\n    expect(doc.isModified).toBeTruthy();\n    expect(doc.suspensed).toBeFalsy();\n\n    doc.suspense();\n    doc.activate();\n    doc.close();\n    doc.remove();\n\n    const offReady = doc.onReady(() => {});\n    offReady();\n\n    expect(doc.history).toBe(doc.getHistory());\n  });\n\n  it('focusNode - using drillDown', () => {\n    const doc = new DocumentModel(project, formSchema);\n    expect(doc.focusNode.id).toBe('page');\n\n    doc.drillDown(doc.getNode('node_k1ow3cbb'));\n    expect(doc.focusNode.id).toBe('node_k1ow3cbb');\n  });\n\n  it('focusNode - using drillDown & import', () => {\n    const doc = new DocumentModel(project, formSchema);\n    expect(doc.focusNode.id).toBe('page');\n\n    doc.drillDown(doc.getNode('node_k1ow3cbb'));\n    doc.import(formSchema);\n    expect(doc.focusNode.id).toBe('node_k1ow3cbb');\n  });\n\n  it('focusNode - using focusNodeSelector', () => {\n    const doc = new DocumentModel(project, formSchema);\n    editor.set('focusNodeSelector', (rootNode) => {\n      return rootNode.children.get(1);\n    });\n    expect(doc.focusNode.id).toBe('node_k1ow3cbb');\n  });\n\n  it('getNodeCount', () => {\n    const doc = new DocumentModel(project);\n    // using default schema, only one node\n    expect(doc.getNodeCount()).toBe(1);\n  });\n\n  it('getNodeSchema', () => {\n    const doc = new DocumentModel(project, formSchema);\n    expect(doc.getNodeSchema('page').id).toBe('page');\n  });\n\n  it('export - with __isTopFixed__', () => {\n    formSchema.children[1].props.__isTopFixed__ = true;\n    const doc = new DocumentModel(project, formSchema);\n\n    const schema = doc.export();\n    expect(schema.children).toHaveLength(3);\n    expect(schema.children[0].componentName).toBe('RootContent');\n    expect(schema.children[1].componentName).toBe('RootHeader');\n    expect(schema.children[2].componentName).toBe('RootFooter');\n  });\n\n  describe('createNode', () => {\n    it('same id && componentName', () => {\n      const doc = new DocumentModel(project, formSchema);\n      const node = doc.createNode({\n        componentName: 'RootFooter',\n        id: 'node_k1ow3cbc',\n        props: {},\n        condition: true,\n      });\n      expect(node.parent).toBeNull();\n    });\n\n    it('same id && different componentName', () => {\n      const doc = new DocumentModel(project, formSchema);\n      const originalNode = doc.getNode('node_k1ow3cbc');\n      const node = doc.createNode({\n        componentName: 'RootFooter2',\n        id: 'node_k1ow3cbc',\n        props: {},\n        condition: true,\n      });\n      // expect(originalNode.parent).toBeNull();\n      expect(node.id).not.toBe('node_k1ow3cbc');\n    });\n  });\n\n  it('setSuspense', () => {\n    const doc = new DocumentModel(project, formSchema);\n    expect(doc.opened).toBeFalsy();\n    doc.setSuspense(false);\n  });\n\n  it('registerAddon / getAddonData / exportAddonData', () => {\n    const doc = new DocumentModel(project);\n    expect(doc.getAddonData('a')).toBeUndefined();\n\n    doc.registerAddon('a', () => 'addon a');\n    doc.registerAddon('a', () => 'modified addon a');\n    doc.registerAddon('b', () => 'addon b');\n    doc.registerAddon('c', () => null);\n\n    ['id', 'layout', 'params'].forEach((name) => {\n      expect(() => doc.registerAddon(name, () => {})).toThrow();\n    });\n\n    expect(doc.getAddonData('a')).toBe('modified addon a');\n    expect(doc.getAddonData('b')).toBe('addon b');\n\n    expect(doc.exportAddonData()).toEqual({\n      a: 'modified addon a',\n      b: 'addon b',\n    });\n  });\n\n  it('checkNesting / checkDropTarget / checkNestingUp / checkNestingDown', () => {\n    designer.createComponentMeta(pageMeta);\n    designer.createComponentMeta(formMeta);\n    designer.createComponentMeta(otherMeta);\n    const doc = new DocumentModel(project, formSchema);\n\n    expect(\n      doc.checkDropTarget(doc.getNode('page'), { type: 'node', nodes: [doc.getNode('form')] }),\n    ).toBeTruthy();\n    expect(\n      doc.checkDropTarget(doc.getNode('page'), {\n        type: 'nodedata',\n        data: { componentName: 'Form' },\n      }),\n    ).toBeTruthy();\n\n    expect(\n      doc.checkNesting(doc.getNode('page'), { type: 'node', nodes: [doc.getNode('form')] }),\n    ).toBeTruthy();\n    expect(\n      doc.checkNesting(doc.getNode('page'), {\n        type: 'nodedata',\n        data: { componentName: 'Form' },\n      }),\n    ).toBeTruthy();\n    expect(\n      doc.checkNesting(doc.getNode('page'), doc.getNode('form'))\n    ).toBeTruthy();\n    expect(\n      doc.checkNesting(doc.getNode('page'), null)\n    ).toBeTruthy();\n    expect(\n      doc.checkNesting(doc.getNode('page'), {\n        type: 'nodedata',\n        data: { componentName: 'Other' },\n      })\n    ).toBeFalsy();\n\n    expect(\n      doc.checkNestingUp(doc.getNode('page'), { componentName: 'Other' })\n    ).toBeFalsy();\n\n    expect(\n      doc.checkNestingDown(doc.getNode('page'), { componentName: 'Other' })\n    ).toBeTruthy();\n\n    expect(doc.checkNestingUp(doc.getNode('page'), null)).toBeTruthy();\n  });\n\n  it('getComponentsMap', () => {\n    designer.createComponentMeta(divMeta);\n    designer.createComponentMeta(otherMeta);\n    const doc = new DocumentModel(project, formSchema);\n    const comps = doc.getComponentsMap(['Other']);\n    expect(comps.find(comp => comp.componentName === 'Div')).toEqual(\n      { componentName: 'Div', package: '@ali/vc-div' }\n    );\n    expect(comps.find(comp => comp.componentName === 'Other')).toEqual(\n      { componentName: 'Other', package: '@ali/vc-other' }\n    );\n    expect(comps.find(comp => comp.componentName === 'Page')).toEqual(\n      { componentName: 'Page', devMode: 'lowCode' }\n    );\n\n    const comps2 = doc.getComponentsMap(['Div']);\n  });\n\n  it('acceptRootNodeVisitor / getRootNodeVisitor', () => {\n    designer.createComponentMeta(divMeta);\n    designer.createComponentMeta(otherMeta);\n    const doc = new DocumentModel(project, formSchema);\n    const ret = doc.acceptRootNodeVisitor('getPageId', (root) => {\n      return 'page';\n    });\n    expect(ret).toBe('page');\n    expect(doc.getRootNodeVisitor('getPageId')).toBe('page');\n\n    // expect(doc.getComponentsMap(['Other'])).toEqual([\n    //   { componentName: 'Div', package: '@ali/vc-div' },\n    //   { componentName: 'Other', package: '@ali/vc-other' },\n    // ]);\n  });\n\n  it('deprecated methods', () => {\n    const doc = new DocumentModel(project, formSchema);\n    doc.refresh();\n    doc.onRefresh();\n  });\n});\n\nit('isDocumentModel', () => {\n  expect(isDocumentModel({ rootNode: {} })).toBeTruthy();\n});\n\nit('isPageSchema', () => {\n  expect(isPageSchema({ componentName: 'Page' })).toBeTruthy();\n});\n"
  },
  {
    "path": "packages/designer/tests/document/history/__snapshots__/history.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`History data function & records 1`] = `\"{\\\\\"data\\\\\":1,\\\\\"children\\\\\":[{\\\\\"data\\\\\":2,\\\\\"children\\\\\":[]}]}\"`;\n\nexports[`History data function & records 2`] = `\"{\\\\\"data\\\\\":3,\\\\\"children\\\\\":[{\\\\\"data\\\\\":2,\\\\\"children\\\\\":[]}]}\"`;\n\nexports[`History data function & records 3`] = `\"{\\\\\"data\\\\\":5,\\\\\"children\\\\\":[{\\\\\"data\\\\\":2,\\\\\"children\\\\\":[]}]}\"`;\n\nexports[`History data function & records 4`] = `\"{\\\\\"data\\\\\":7,\\\\\"children\\\\\":[{\\\\\"data\\\\\":2,\\\\\"children\\\\\":[]}]}\"`;\n"
  },
  {
    "path": "packages/designer/tests/document/history/history.test.ts",
    "content": "import '../../fixtures/window';\nimport { mobx, makeAutoObservable, globalContext, Editor } from '@alilc/lowcode-editor-core';\nimport { History } from '../../../src/document/history';\nimport { delay } from '../../utils/misc';\nimport { Workspace } from '@alilc/lowcode-workspace';\n\nclass Node {\n  data: number;\n  children: Node[] = [];\n\n  constructor(data: number) {\n    makeAutoObservable(this);\n    this.data = data;\n  }\n\n  addNode(node: Node) {\n    this.children.push(node);\n  }\n\n  toObject() {\n    return {\n      data: this.data,\n      children: this.children.map((c) => c.toObject()),\n    };\n  }\n}\n\nlet tree: Node = null;\nbeforeEach(() => {\n  tree = new Node(1);\n  tree.addNode(new Node(2));\n});\n\nafterEach(() => {\n  tree = null;\n});\n\ndescribe('History', () => {\n  beforeAll(() => {\n    const editor = new Editor();\n    globalContext.register(editor, Editor);\n    globalContext.register(editor, 'editor');\n    globalContext.register(new Workspace(), 'workspace');\n  });\n\n  it('data function & records', async () => {\n    const mockRedoFn = jest.fn();\n    const mockDataFn = jest.fn();\n    const history = new History<Node>(() => {\n      const data = tree.toObject();\n      mockDataFn(data);\n      return data;\n    }, mockRedoFn);\n\n    expect(mockDataFn).toHaveBeenCalledTimes(1);\n    expect(mockDataFn).toHaveBeenCalledWith({ data: 1, children: [{ data: 2, children: [] }] });\n    expect(history.hotData).toMatchSnapshot();\n    // @ts-ignore\n    expect(history.session.cursor).toBe(0);\n    // @ts-ignore\n    expect(history.records).toHaveLength(1);\n\n    tree.data = 3;\n    expect(mockDataFn).toHaveBeenCalledTimes(2);\n    expect(mockDataFn).toHaveBeenCalledWith({ data: 3, children: [{ data: 2, children: [] }] });\n    expect(history.hotData).toMatchSnapshot();\n    // @ts-ignore\n    expect(history.session.cursor).toBe(0);\n    // @ts-ignore\n    expect(history.records).toHaveLength(1);\n\n    // modify data after timeGap\n    await delay(1200);\n    tree.data = 5;\n    expect(mockDataFn).toHaveBeenCalledTimes(3);\n    expect(mockDataFn).toHaveBeenCalledWith({ data: 5, children: [{ data: 2, children: [] }] });\n    expect(history.hotData).toMatchSnapshot();\n    // @ts-ignore\n    expect(history.session.cursor).toBe(1);\n    // @ts-ignore\n    expect(history.records).toHaveLength(2);\n\n    history.setSerialization({\n      serialize(data: Node): string {\n        return JSON.stringify(data);\n      },\n      unserialize(data: string) {\n        return JSON.parse(data);\n      },\n    });\n\n    // modify data after timeGap\n    await delay(1200);\n    tree.data = 7;\n    expect(mockDataFn).toHaveBeenCalledTimes(4);\n    expect(mockDataFn).toHaveBeenCalledWith({ data: 7, children: [{ data: 2, children: [] }] });\n    expect(history.hotData).toMatchSnapshot();\n  });\n\n  it('isSavePoint & savePoint', async () => {\n    const history = new History<Node>(\n      () => {\n        const data = tree.toObject();\n        return data;\n      },\n      () => {},\n    );\n\n    expect(history.isSavePoint()).toBeFalsy();\n    expect(history.isModified()).toBeFalsy();\n\n    await delay(1200);\n    tree.data = 3;\n    expect(history.isSavePoint()).toBeTruthy();\n\n    history.savePoint();\n    expect(history.isSavePoint()).toBeFalsy();\n  });\n\n  it('go & forward & back & onCursor', async () => {\n    const mockRedoFn = jest.fn();\n    const mockCursorFn = jest.fn();\n    const mockStateFn = jest.fn();\n    const history = new History<Node>(\n      () => {\n        const data = tree.toObject();\n        return data;\n      },\n      (data) => {\n        mockRedoFn(data);\n      },\n    );\n\n    // undoable ❌ & redoable ❌ & modified ❌\n    expect(history.getState()).toBe(0);\n\n    await delay(1200);\n    tree.data = 3;\n\n    await delay(1200);\n    tree.data = 5;\n\n    await delay(1200);\n    tree.data = 7;\n\n    const dataCursor0 = { data: 1, children: [{ data: 2, children: [] }] };\n    const dataCursor1 = { data: 3, children: [{ data: 2, children: [] }] };\n    const dataCursor2 = { data: 5, children: [{ data: 2, children: [] }] };\n    const dataCursor3 = { data: 7, children: [{ data: 2, children: [] }] };\n\n    // redoable ❌\n    expect(history.getState()).toBe(7 - 2);\n\n    const off1 = history.onCursor(mockCursorFn);\n    const off2 = history.onStateChange(mockStateFn);\n\n    // @ts-ignore\n    expect(history.records).toHaveLength(4);\n    // @ts-ignore\n    expect(history.session.cursor).toBe(3);\n\n    // step 1\n    history.back();\n    expect(mockCursorFn).toHaveBeenNthCalledWith(\n      1,\n      JSON.stringify(dataCursor2),\n    );\n    expect(mockStateFn).toHaveBeenNthCalledWith(1, 7);\n    expect(mockRedoFn).toHaveBeenNthCalledWith(1, dataCursor2);\n\n    // step 2\n    history.back();\n    expect(mockCursorFn).toHaveBeenNthCalledWith(\n      2,\n      JSON.stringify(dataCursor1),\n    );\n    expect(mockStateFn).toHaveBeenNthCalledWith(2, 7);\n    expect(mockRedoFn).toHaveBeenNthCalledWith(2, dataCursor1);\n\n    // step 3\n    history.back();\n    expect(mockCursorFn).toHaveBeenNthCalledWith(\n      3,\n      JSON.stringify(dataCursor0),\n    );\n    expect(mockStateFn).toHaveBeenNthCalledWith(3, 7 - 4 - 1);\n    expect(mockRedoFn).toHaveBeenNthCalledWith(3, dataCursor0);\n\n    // step 4\n    history.forward();\n    expect(mockCursorFn).toHaveBeenNthCalledWith(\n      4,\n      JSON.stringify(dataCursor1),\n    );\n    expect(mockStateFn).toHaveBeenNthCalledWith(4, 7);\n    expect(mockRedoFn).toHaveBeenNthCalledWith(4, dataCursor1);\n\n    // step 5\n    history.forward();\n    expect(mockCursorFn).toHaveBeenNthCalledWith(\n      5,\n      JSON.stringify(dataCursor2),\n    );\n    expect(mockStateFn).toHaveBeenNthCalledWith(5, 7);\n    expect(mockRedoFn).toHaveBeenNthCalledWith(5, dataCursor2);\n\n    // step 6\n    history.go(3);\n    expect(mockCursorFn).toHaveBeenNthCalledWith(\n      6,\n      JSON.stringify(dataCursor3),\n    );\n    expect(mockStateFn).toHaveBeenNthCalledWith(6, 7 - 2);\n    expect(mockRedoFn).toHaveBeenNthCalledWith(6, dataCursor3);\n\n    // step 7\n    history.go(0);\n    expect(mockCursorFn).toHaveBeenNthCalledWith(\n      7,\n      JSON.stringify(dataCursor0),\n    );\n    expect(mockStateFn).toHaveBeenNthCalledWith(7, 7 - 4 - 1);\n    expect(mockRedoFn).toHaveBeenNthCalledWith(7, dataCursor0);\n\n    off1();\n    off2();\n    mockStateFn.mockClear();\n    mockCursorFn.mockClear();\n    history.go(1);\n    expect(mockStateFn).not.toHaveBeenCalled();\n    expect(mockCursorFn).not.toHaveBeenCalled();\n  });\n\n  it('go() - edge case of cursor', async () => {\n    const mockRedoFn = jest.fn();\n    const mockCursorFn = jest.fn();\n    const mockStateFn = jest.fn();\n    const history = new History<Node>(\n      () => {\n        const data = tree.toObject();\n        return data;\n      },\n      (data) => {\n        mockRedoFn(data);\n      },\n    );\n\n    await delay(1200);\n    tree.data = 3;\n\n    await delay(1200);\n    tree.data = 5;\n\n    history.go(-1);\n    // @ts-ignore\n    expect(history.session.cursor).toBe(0);\n\n    history.go(3);\n    // @ts-ignore\n    expect(history.session.cursor).toBe(2);\n  });\n\n  it('destroy()', async () => {\n    const history = new History<Node>(\n      () => {\n        const data = tree.toObject();\n        return data;\n      },\n      (data) => {\n        mockRedoFn(data);\n      },\n    );\n\n    history.destroy();\n    // @ts-ignore\n    expect(history.records).toHaveLength(0);\n  });\n\n  it('sleep & wakeup', async () => {\n    const mockRedoFn = jest.fn();\n    const history = new History<Node>(\n      () => {\n        const data = tree.toObject();\n        return data;\n      },\n      (data) => {\n        mockRedoFn(data);\n      },\n    );\n\n    // @ts-ignore\n    history.sleep();\n\n    await delay(1200);\n    tree.data = 3;\n    // no record has been pushed into records because of history is asleep.\n    // @ts-ignore\n    expect(history.records).toHaveLength(1);\n\n    // @ts-ignore\n    history.wakeup();\n    tree.data = 4;\n    // @ts-ignore\n    expect(history.records).toHaveLength(2);\n  });\n});\n\ndescribe('History - errors', () => {\n  beforeAll(() => {\n    globalContext.replace(Editor, null);\n  });\n\n  it('no editor', () => {\n    const history = new History<Node>(\n      () => {\n        const data = tree.toObject();\n        return data;\n      },\n      (data) => {\n      },\n    );\n\n    history.back();\n    history.forward();\n  });\n\n  it('no session', () => {\n    const history = new History<Node>(\n      () => {\n        const data = tree.toObject();\n        return data;\n      },\n      (data) => {\n      },\n    );\n\n    // @ts-ignore\n    history.session = undefined;\n    history.back();\n    history.forward();\n    history.savePoint();\n  });\n});"
  },
  {
    "path": "packages/designer/tests/document/history/session.test.ts",
    "content": "import '../../fixtures/window';\nimport { Session } from '../../../src/document/history';\nimport { delay } from '../../utils/misc';\n\ndescribe('Session', () => {\n  it('constructor', () => {\n    const session = new Session(1, { a: 1 });\n    expect(session.cursor).toBe(1);\n    expect(session.data).toEqual({ a: 1 });\n    // @ts-ignore\n    expect(session.timeGap).toBe(1000);\n    expect(session.isActive()).toBeTruthy();\n  });\n\n  it('log()', () => {\n    const session = new Session(1, { a: 1 });\n\n    session.log({ a: 2 });\n    session.log({ a: 3 });\n    expect(session.data).toEqual({ a: 3 });\n  });\n\n  it('end()', () => {\n    const session = new Session(1, { a: 1 });\n\n    session.end();\n    expect(session.isActive()).toBeFalsy();\n    session.log({ a: 2 });\n    // log is not possible if current session is inactive\n    expect(session.data).toEqual({ a: 1 });\n  });\n\n\n  it('timeGap', async () => {\n    const session = new Session(1, { a: 1 });\n\n    expect(session.isActive()).toBeTruthy();\n    await delay(1200);\n    expect(session.isActive()).toBeFalsy();\n    session.log({ a: 2 });\n    // log is not possible if current session is inactive\n    expect(session.data).toEqual({ a: 1 });\n  });\n\n  it('custom timeGap', async () => {\n    const session = new Session(1, { a: 1 }, 2000);\n\n    expect(session.isActive()).toBeTruthy();\n    await delay(1200);\n    expect(session.isActive()).toBeTruthy();\n    await delay(1000);\n    expect(session.isActive()).toBeFalsy();\n    session.log({ a: 2 });\n    // log is not possible if current session is inactive\n    expect(session.data).toEqual({ a: 1 });\n  });\n});"
  },
  {
    "path": "packages/designer/tests/document/node/modal-nodes-manager.test.ts",
    "content": "import '../../fixtures/window';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../../src/project/project';\nimport { DocumentModel } from '../../../src/document/document-model';\nimport { Node } from '../../../src/document/node/node';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form-with-modal';\nimport dlgMetadata from '../../fixtures/component-metadata/dialog';\nimport { getModalNodes } from '../../../src/document/node/modal-nodes-manager';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\nlet editor: Editor;\nlet designer: Designer;\nlet project: Project;\nlet doc: DocumentModel;\n\nbeforeEach(() => {\n  editor = new Editor();\n  designer = new Designer({ editor, shellModelFactory });\n  designer.createComponentMeta(dlgMetadata);\n  project = designer.project;\n  doc = new DocumentModel(project, formSchema);\n});\n\nafterEach(() => {\n  project.unload();\n  designer.purge();\n  editor = null;\n  designer = null;\n  project = null;\n});\n\ndescribe('ModalNodesManager 方法测试', () => {\n  it('getModalNodes / getVisibleModalNode', () => {\n    const mgr = doc.modalNodesManager;\n    const nodes = mgr.getModalNodes();\n    expect(nodes).toHaveLength(1);\n    expect(nodes[0].componentName).toBe('Dialog');\n    expect(mgr.getVisibleModalNode()).toBeFalsy();\n  });\n\n  it('setVisible / setInvisible / onVisibleChange', () => {\n    const mgr = doc.modalNodesManager;\n    const nodes = mgr.getModalNodes();\n\n    const mockFn = jest.fn();\n    const off = mgr.onVisibleChange(mockFn);\n\n    mgr.setVisible(nodes[0]);\n    expect(mockFn).toHaveBeenCalledTimes(2);\n\n    mgr.setInvisible(nodes[0]);\n    expect(mockFn).toHaveBeenCalledTimes(3);\n\n    off();\n  });\n\n  it('addNode / removeNode', () => {\n    const mgr = doc.modalNodesManager!;\n    const nodes = mgr.getModalNodes();\n\n    const nodesMockFn = jest.fn();\n    const visibleMockFn = jest.fn();\n    const off = mgr.onModalNodesChange(nodesMockFn);\n    const offVisible = mgr.onVisibleChange(visibleMockFn);\n\n    const newNode = new Node(doc, { componentName: 'Dialog' });\n    mgr.addNode(newNode);\n    expect(visibleMockFn).toHaveBeenCalledTimes(2);\n    expect(nodesMockFn).toHaveBeenCalledTimes(1);\n\n    mgr.setVisible(newNode);\n    mgr.removeNode(newNode);\n\n    expect(visibleMockFn).toHaveBeenCalledTimes(6);\n    expect(nodesMockFn).toHaveBeenCalledTimes(2);\n\n    off();\n    offVisible();\n    visibleMockFn.mockClear();\n    nodesMockFn.mockClear();\n\n    mgr.addNode(newNode);\n    expect(visibleMockFn).not.toHaveBeenCalled();\n    expect(nodesMockFn).not.toHaveBeenCalled();\n\n    const newNode2 = new Node(doc, { componentName: 'Dialog' });\n    mgr.addNode(newNode2);\n    mgr.setInvisible(newNode2);\n    mgr.removeNode(newNode2);\n\n    const newNode3 = new Node(doc, { componentName: 'Dialog' });\n    mgr.removeNode(newNode3);\n\n    const newNode4 = new Node(doc, { componentName: 'Non-Modal' });\n    mgr.removeNode(newNode4);\n\n    const newNode5 = doc.createNode({ componentName: 'Non-Modal' });\n    newNode5.remove(); // trigger node destroy\n  });\n});\n\ndescribe('其他方法', () => {\n  it('getModalNodes - null', () => {\n    expect(getModalNodes()).toEqual([]);\n  });\n\n  it('getModalNodes - no children', () => {\n    const node = doc.createNode({ componentName: 'Leaf', children: 'haha' });\n    expect(getModalNodes(node)).toEqual([]);\n  });\n});"
  },
  {
    "path": "packages/designer/tests/document/node/node-children.test.ts",
    "content": "import '../../fixtures/window';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../../src/project/project';\nimport { DocumentModel } from '../../../src/document/document-model';\nimport {\n  Node,\n} from '../../../src/document/node/node';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form';\nimport divMetadata from '../../fixtures/component-metadata/div';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\n\ndescribe('NodeChildren 方法测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n\n  beforeEach(() => {\n    editor = new Editor();\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    doc = new DocumentModel(project, formSchema);\n  });\n\n  afterEach(() => {\n    project.unload();\n    designer.purge();\n    editor = null;\n    designer = null;\n    project = null;\n  });\n\n  it('isEmpty / notEmpty', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const secondBtn = doc.getNode('node_k1ow3cbp')!;\n    const { children } = firstBtn.parent!;\n\n    expect(children.isEmpty()).toBeFalsy();\n    expect(children.notEmpty()).toBeTruthy();\n    expect(firstBtn.children.notEmpty()).toBeFalsy();\n    expect(firstBtn.children.isEmpty()).toBeTruthy();\n  });\n\n  it('export', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    expect(children.export().length).toBe(2);\n  });\n\n  it('export - Leaf', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    firstBtn.parent!.insertAfter({ componentName: 'Leaf', children: 'haha' });\n    const { children } = firstBtn.parent!;\n\n    expect(children.export().length).toBe(3);\n    expect(children.export()[2]).toBe('haha');\n  });\n\n  it('import', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    children.import(children.export());\n\n    expect(children.export().length).toBe(2);\n  });\n\n  it('delete', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const leafNode = doc.createNode({ componentName: 'Leaf', children: 'haha' });\n    firstBtn.parent!.insertAfter(leafNode);\n    const { children } = firstBtn.parent!;\n\n    children.delete(leafNode);\n    expect(children.export().length).toBe(2);\n  });\n\n  it('delete - 插入已有的节点', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    firstBtn.parent!.insertBefore(firstBtn, firstBtn);\n    const { children } = firstBtn.parent!;\n\n    expect(children.export().length).toBe(2);\n  });\n\n  it('purge / for of', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n    children.purge();\n\n    for (const child of children) {\n      expect(child.isPurged).toBeTruthy();\n    }\n\n    // purge when children is purged\n    children.purge();\n  });\n\n  it('splice', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n    children.splice(0, 1);\n\n    expect(children.size).toBe(1);\n    expect(children.length).toBe(1);\n\n    children.splice(0, 0, doc.createNode({ componentName: 'Button' }));\n    expect(children.size).toBe(2);\n    expect(children.length).toBe(2);\n  });\n\n  it('map', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    const newMap = children.map((item) => item);\n\n    newMap?.forEach((item) => {\n      expect(item.componentName).toBe('Button');\n    });\n  });\n\n  it('forEach', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    children.forEach((item) => {\n      expect(item.componentName).toBe('Button');\n    });\n  });\n\n  it('some', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    children.some((item) => {\n      return expect(item.componentName).toBe('Button');\n    });\n  });\n\n  it('every', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    children.every((item) => {\n      return expect(item.componentName).toBe('Button');\n    });\n  });\n\n  it('filter', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    children\n      .filter((item) => item.componentName === 'Button')\n      .forEach((item) => {\n        expect(item.componentName).toBe('Button');\n      });\n  });\n\n  it('find', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    const found = children.find((item) => item.componentName === 'Button');\n\n    expect(found?.componentName).toBe('Button');\n  });\n\n  it('concat', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    const ret = children.concat([doc.createNode({ componentName: 'Button' })]);\n\n    expect(ret.length).toBe(3);\n  });\n\n  it('reduce', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    let ret = 0;\n    ret = children.reduce((count, node) => {\n      count = count + 1;\n      return count;\n    }, 0);\n\n    expect(ret).toBe(2);\n  });\n\n  it('mergeChildren', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    const changeMockFn = jest.fn();\n    const offChange = children.onChange(changeMockFn);\n    const rmMockFn = jest.fn((item) => {\n      if (item.index === 1) return true;\n      return false;\n    });\n    const addMockFn = jest.fn((children) => {\n      return [{ componentName: 'Button' }, { componentName: 'Button' }];\n    });\n    const sortMockFn = jest.fn((a, b) => {\n      return a > b ? 1 : -1;\n    });\n    children.mergeChildren(rmMockFn, addMockFn, sortMockFn);\n\n    expect(children.size).toBe(3);\n    expect(changeMockFn).toHaveBeenCalled();\n    offChange();\n\n    // no remover && adder && sorter\n    children.mergeChildren();\n  });\n\n  it('insert / onInsert', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    const mockFn = jest.fn();\n    const off = children.onInsert(mockFn);\n\n    children.insert(new Node(doc, { componentName: 'Button' }));\n    expect(mockFn).toHaveBeenCalledTimes(1);\n    off();\n    children.insert(new Node(doc, { componentName: 'Button' }));\n    expect(mockFn).toHaveBeenCalledTimes(1);\n  });\n\n  it('reportModified', () => {\n    const divMeta = designer.createComponentMeta(divMetadata);\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const { children } = firstBtn.parent!;\n\n    const modifiedMockFn = jest.fn();\n    divMeta.getMetadata = () => {\n      return { configure: { advanced: { callbacks: { onSubtreeModified: modifiedMockFn } } } };\n    };\n\n    children.reportModified(null);\n    children.reportModified(doc.rootNode);\n\n    children.reportModified(firstBtn, firstBtn.parent);\n    expect(modifiedMockFn).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/node.add.test.ts",
    "content": "import set from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport '../../fixtures/window';\nimport { Project, IProject } from '../../../src/project/project';\nimport { Node, INode } from '../../../src/document/node/node';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form';\nimport { getIdsFromSchema, getNodeFromSchemaById } from '../../utils';\n\nconst mockCreateSettingEntry = jest.fn();\njest.mock('../../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      return {\n        getComponentMeta() {\n          return {\n            getMetadata() {\n              return { configure: { advanced: null } };\n            },\n            get advanced() {\n              return {};\n            },\n          };\n        },\n        transformProps(props) { return props; },\n        createSettingEntry: mockCreateSettingEntry,\n        postEvent() {},\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({});\n});\n\ndescribe('schema 生成节点模型测试', () => {\n  describe('block ❌ | component ❌ | slot ❌', () => {\n    let project: IProject;\n    beforeEach(() => {\n      project = new Project(designer, {\n        componentsTree: [\n          formSchema,\n        ],\n      });\n      project.open();\n    });\n    afterEach(() => {\n      project.unload();\n    });\n    it('基本的节点模型初始化，模型导出', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const nodesMap = currentDocument?.nodesMap;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      expect(nodesMap?.size).toBe(expectedNodeCnt);\n      ids.forEach(id => {\n        expect(nodesMap?.get(id)?.componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);\n      });\n\n      const pageNode = currentDocument?.getNode('page');\n      expect(pageNode?.getComponentName()).toBe('Page');\n      expect(pageNode?.getIcon()).toBeUndefined();\n\n      const exportSchema = currentDocument?.export(1);\n      expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);\n      nodesMap.forEach(node => {\n        // 触发 getter\n        node.settingEntry;\n      });\n      expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);\n    });\n\n    it('基本的节点模型初始化，节点深度', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const getNode = currentDocument?.getNode.bind(currentDocument);\n\n      const pageNode = getNode?.('page');\n      const rootHeaderNode = getNode?.('node_k1ow3cba');\n      const rootContentNode = getNode?.('node_k1ow3cbb');\n      const rootFooterNode = getNode?.('node_k1ow3cbc');\n      const formNode = getNode?.('form');\n      const cardNode = getNode?.('node_k1ow3cbj');\n      const cardContentNode = getNode?.('node_k1ow3cbk');\n      const columnsLayoutNode = getNode?.('node_k1ow3cbw');\n      const columnNode = getNode?.('node_k1ow3cbx');\n      const textFieldNode = getNode?.('node_k1ow3cbz');\n\n      expect(pageNode?.zLevel).toBe(0);\n      expect(rootHeaderNode?.zLevel).toBe(1);\n      expect(rootContentNode?.zLevel).toBe(1);\n      expect(rootFooterNode?.zLevel).toBe(1);\n      expect(formNode?.zLevel).toBe(2);\n      expect(cardNode?.zLevel).toBe(3);\n      expect(cardContentNode?.zLevel).toBe(4);\n      expect(columnsLayoutNode?.zLevel).toBe(5);\n      expect(columnNode?.zLevel).toBe(6);\n      expect(textFieldNode?.zLevel).toBe(7);\n\n      expect(textFieldNode?.getZLevelTop(7)).toEqual(textFieldNode);\n      expect(textFieldNode?.getZLevelTop(6)).toEqual(columnNode);\n      expect(textFieldNode?.getZLevelTop(5)).toEqual(columnsLayoutNode);\n      expect(textFieldNode?.getZLevelTop(4)).toEqual(cardContentNode);\n      expect(textFieldNode?.getZLevelTop(3)).toEqual(cardNode);\n      expect(textFieldNode?.getZLevelTop(2)).toEqual(formNode);\n      expect(textFieldNode?.getZLevelTop(1)).toEqual(rootContentNode);\n      expect(textFieldNode?.getZLevelTop(0)).toEqual(pageNode);\n\n      // 异常情况\n      expect(textFieldNode?.getZLevelTop(8)).toBeNull();\n      expect(textFieldNode?.getZLevelTop(-1)).toBeNull();\n    });\n\n    it('基本的节点模型初始化，节点父子、兄弟相关方法', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const getNode = currentDocument.getNode.bind(currentDocument);\n\n      const pageNode = getNode('page');\n      const rootHeaderNode = getNode('node_k1ow3cba');\n      const rootContentNode = getNode('node_k1ow3cbb');\n      const rootFooterNode = getNode('node_k1ow3cbc');\n      const formNode = getNode('form');\n      const cardNode = getNode('node_k1ow3cbj');\n      const cardContentNode = getNode('node_k1ow3cbk');\n      const columnsLayoutNode = getNode('node_k1ow3cbw');\n      const columnNode = getNode('node_k1ow3cbx');\n      const textFieldNode = getNode('node_k1ow3cbz');\n\n      expect(pageNode?.index).toBe(-1);\n      expect(pageNode?.children?.toString()).toBe('[object Array]');\n      expect(pageNode?.children?.get(1)).toBe(rootContentNode);\n      expect(pageNode?.getChildren()?.get(1)).toBe(rootContentNode);\n      expect(pageNode?.getNode()).toBe(pageNode);\n\n      expect(rootFooterNode?.index).toBe(2);\n\n      expect(textFieldNode?.getParent()).toBe(columnNode);\n      expect(columnNode?.getParent()).toBe(columnsLayoutNode);\n      expect(columnsLayoutNode?.getParent()).toBe(cardContentNode);\n      expect(cardContentNode?.getParent()).toBe(cardNode);\n      expect(cardNode?.getParent()).toBe(formNode);\n      expect(formNode?.getParent()).toBe(rootContentNode);\n      expect(rootContentNode?.getParent()).toBe(pageNode);\n      expect(rootContentNode?.prevSibling).toBe(rootHeaderNode);\n      expect(rootContentNode?.nextSibling).toBe(rootFooterNode);\n\n      expect(pageNode?.isRoot()).toBe(true);\n      expect(pageNode?.contains(textFieldNode)).toBe(true);\n      expect(textFieldNode?.getRoot()).toBe(pageNode);\n      expect(columnNode?.getRoot()).toBe(pageNode);\n      expect(columnsLayoutNode?.getRoot()).toBe(pageNode);\n      expect(cardContentNode?.getRoot()).toBe(pageNode);\n      expect(cardNode?.getRoot()).toBe(pageNode);\n      expect(formNode?.getRoot()).toBe(pageNode);\n      expect(rootContentNode?.getRoot()).toBe(pageNode);\n    });\n\n    it('基本的节点模型初始化，节点新建、删除等事件', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const getNode = currentDocument?.getNode.bind(currentDocument);\n      const createNode = currentDocument?.createNode.bind(currentDocument);\n\n      const pageNode = getNode?.('page');\n      const nodeCreateHandler = jest.fn();\n      const offCreate = currentDocument?.onNodeCreate(nodeCreateHandler);\n\n      const node = createNode?.({\n        componentName: 'TextInput',\n        props: {\n          propA: 'haha',\n        },\n      });\n      pageNode && node && currentDocument?.insertNode(pageNode, node);\n\n      expect(nodeCreateHandler).toHaveBeenCalledTimes(1);\n      expect(nodeCreateHandler.mock.calls[0][0]).toBe(node);\n      expect(nodeCreateHandler.mock.calls[0][0].componentName).toBe('TextInput');\n      expect(nodeCreateHandler.mock.calls[0][0].getPropValue('propA')).toBe('haha');\n\n      const nodeDestroyHandler = jest.fn();\n      const offDestroy = currentDocument?.onNodeDestroy(nodeDestroyHandler);\n      node?.remove();\n      expect(nodeDestroyHandler).toHaveBeenCalledTimes(1);\n      expect(nodeDestroyHandler.mock.calls[0][0]).toBe(node);\n      expect(nodeDestroyHandler.mock.calls[0][0].componentName).toBe('TextInput');\n      expect(nodeDestroyHandler.mock.calls[0][0].getPropValue('propA')).toBe('haha');\n\n      offCreate();\n      offDestroy();\n    });\n\n    it.skip('基本的节点模型初始化，节点插入等方法', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const getNode = currentDocument.getNode.bind(currentDocument);\n\n      const formNode = getNode('form');\n      const node1 = currentDocument.createNode({\n        componentName: 'TextInput',\n        props: {\n          propA: 'haha',\n        },\n      });\n      const node2 = currentDocument.createNode({\n        componentName: 'TextInput',\n        props: {\n          propA: 'heihei',\n        },\n      });\n      const node3 = currentDocument.createNode({\n        componentName: 'TextInput',\n        props: {\n          propA: 'heihei2',\n        },\n      });\n      const node4 = currentDocument.createNode({\n        componentName: 'TextInput',\n        props: {\n          propA: 'heihei3',\n        },\n      });\n\n      formNode?.insertBefore(node2);\n      // formNode?.insertBefore(node1, node2);\n      // formNode?.insertAfter(node3);\n      // formNode?.insertAfter(node4, node3);\n\n      expect(formNode?.children?.get(0)).toBe(node1);\n      expect(formNode?.children?.get(1)).toBe(node2);\n      // expect(formNode?.children?.get(5)).toBe(node3);\n      // expect(formNode?.children?.get(6)).toBe(node4);\n    });\n\n    it('基本的节点模型初始化，节点其他方法', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const getNode = currentDocument.getNode.bind(currentDocument);\n\n      const pageNode = getNode('page');\n      expect(pageNode?.isPage()).toBe(true);\n      expect(pageNode?.isComponent()).toBe(false);\n      expect(pageNode?.isSlot()).toBe(false);\n      expect(pageNode?.title).toBe('hey, i\\' a page!');\n    });\n\n    describe('节点新增（insertNode）', () => {\n      let project: Project;\n      beforeEach(() => {\n        project = new Project(designer, {\n          componentsTree: [\n            formSchema,\n          ],\n        });\n        project.open();\n      });\n      it('场景一：插入 NodeSchema，不指定 index', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const { nodesMap } = currentDocument;\n        const formNode = nodesMap.get('form') as Node;\n        const formNode2 = currentDocument?.getNode('form');\n        expect(formNode).toEqual(formNode2);\n        currentDocument?.insertNode(formNode, {\n          componentName: 'TextInput',\n          id: 'nodeschema-id1',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n        });\n        expect(nodesMap.size).toBe(ids.length + 1);\n        expect(formNode.children?.length).toBe(4);\n        const insertedNode = formNode.children.get(formNode.children.length - 1);\n        expect(insertedNode.componentName).toBe('TextInput');\n        expect(insertedNode.propsData).toEqual({\n          propA: 'haha',\n          propB: 3,\n        });\n        // TODO: 把 checkId 的 commit pick 过来\n        // expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');\n      });\n\n      it('场景一：插入 NodeSchema，指定 index: 0', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form');\n        formNode && currentDocument?.insertNode(formNode, {\n          componentName: 'TextInput',\n          id: 'nodeschema-id1',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n        }, 0);\n        expect(nodesMap?.size).toBe(ids.length + 1);\n        expect(formNode?.children?.length).toBe(4);\n        const insertedNode = formNode?.children?.get(0);\n        expect(insertedNode?.componentName).toBe('TextInput');\n        expect(insertedNode?.propsData).toEqual({\n          propA: 'haha',\n          propB: 3,\n        });\n        // TODO: 把 checkId 的 commit pick 过来\n        // expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');\n      });\n\n      it('场景一：插入 NodeSchema，指定 index: 1', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form');\n        formNode && currentDocument?.insertNode(formNode, {\n          componentName: 'TextInput',\n          id: 'nodeschema-id1',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n        }, 1);\n        expect(nodesMap?.size).toBe(ids.length + 1);\n        expect(formNode?.children?.length).toBe(4);\n        const insertedNode = formNode?.children?.get(1);\n        expect(insertedNode?.componentName).toBe('TextInput');\n        expect(insertedNode?.propsData).toEqual({\n          propA: 'haha',\n          propB: 3,\n        });\n        // TODO: 把 checkId 的 commit pick 过来\n        // expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput');\n      });\n\n      it('场景一：插入 NodeSchema，有 children', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form') as INode;\n        currentDocument?.insertNode(formNode, {\n          componentName: 'ParentNode',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n          children: [\n            {\n              componentName: 'SubNode',\n              props: {\n                propA: 'haha',\n                propB: 3,\n              },\n            },\n            {\n              componentName: 'SubNode2',\n              props: {\n                propA: 'haha',\n                propB: 3,\n              },\n            },\n          ],\n        });\n        expect(nodesMap?.size).toBe(ids.length + 3);\n        expect(formNode.children?.length).toBe(4);\n        expect(formNode.children?.get(3)?.componentName).toBe('ParentNode');\n        expect(formNode.children?.get(3)?.children?.get(0)?.componentName).toBe('SubNode');\n        expect(formNode.children?.get(3)?.children?.get(1)?.componentName).toBe('SubNode2');\n      });\n\n      it.skip('场景一：插入 NodeSchema，id 与现有 schema 里的 id 重复', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form');\n        formNode && currentDocument?.insertNode(formNode, {\n          componentName: 'TextInput',\n          id: 'nodeschema-id1',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n        });\n        expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput');\n        expect(nodesMap?.size).toBe(ids.length + 1);\n      });\n\n      it.skip('场景一：插入 NodeSchema，id 与现有 schema 里的 id 重复，但关闭了 id 检测器', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form');\n        formNode && currentDocument?.insertNode(formNode, {\n          componentName: 'TextInput',\n          id: 'nodeschema-id1',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n        });\n        expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput');\n        expect(nodesMap?.size).toBe(ids.length + 1);\n      });\n\n      it('场景二：插入 Node 实例', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form');\n        const inputNode = currentDocument?.createNode({\n          componentName: 'TextInput',\n          id: 'nodeschema-id2',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n        });\n        formNode && currentDocument?.insertNode(formNode, inputNode);\n        expect(formNode?.children?.get(3)?.componentName).toBe('TextInput');\n        expect(nodesMap?.size).toBe(ids.length + 1);\n      });\n\n      it('场景三：插入 JSExpression', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form') as Node;\n        currentDocument?.insertNode(formNode, {\n          type: 'JSExpression',\n          value: 'just a expression',\n        });\n        expect(nodesMap?.size).toBe(ids.length + 1);\n        expect(formNode.children?.get(3)?.componentName).toBe('Leaf');\n        // expect(formNode.children?.get(3)?.children).toEqual({\n        //   type: 'JSExpression',\n        //   value: 'just a expression'\n        // });\n      });\n      it('场景四：插入 string', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form') as Node;\n        currentDocument?.insertNode(formNode, 'just a string');\n        expect(nodesMap?.size).toBe(ids.length + 1);\n        expect(formNode.children?.get(3)?.componentName).toBe('Leaf');\n        // expect(formNode.children?.get(3)?.children).toBe('just a string');\n      });\n    });\n\n    describe('节点新增（insertNodes）', () => {\n      let project: Project;\n      beforeEach(() => {\n        project = new Project(designer, {\n          componentsTree: [\n            formSchema,\n          ],\n        });\n        project.open();\n      });\n      it('场景一：插入 NodeSchema，指定 index', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form') as Node;\n        const formNode2 = currentDocument?.getNode('form');\n        expect(formNode).toEqual(formNode2);\n        currentDocument?.insertNodes(formNode, [\n          {\n            componentName: 'TextInput',\n            props: {\n              propA: 'haha2',\n              propB: 3,\n            },\n          },\n          {\n            componentName: 'TextInput2',\n            props: {\n              propA: 'haha',\n              propB: 3,\n            },\n          },\n        ], 1);\n        expect(nodesMap?.size).toBe(ids.length + 2);\n        expect(formNode.children?.length).toBe(5);\n        const insertedNode1 = formNode.children?.get(1);\n        const insertedNode2 = formNode.children?.get(2);\n        expect(insertedNode1?.componentName).toBe('TextInput');\n        expect(insertedNode1?.propsData).toEqual({\n          propA: 'haha2',\n          propB: 3,\n        });\n        expect(insertedNode2?.componentName).toBe('TextInput2');\n        expect(insertedNode2?.propsData).toEqual({\n          propA: 'haha',\n          propB: 3,\n        });\n      });\n\n      it.only('场景二：插入 Node 实例，指定 index', () => {\n        expect(project).toBeTruthy();\n        const ids = getIdsFromSchema(formSchema);\n        const { currentDocument } = project;\n        const nodesMap = currentDocument?.nodesMap;\n        const formNode = nodesMap?.get('form') as INode;\n        const formNode2 = currentDocument?.getNode('form');\n        expect(formNode).toEqual(formNode2);\n        const createdNode1 = currentDocument?.createNode({\n          componentName: 'TextInput',\n          props: {\n            propA: 'haha2',\n            propB: 3,\n          },\n        });\n        const createdNode2 = currentDocument?.createNode({\n          componentName: 'TextInput2',\n          props: {\n            propA: 'haha',\n            propB: 3,\n          },\n        });\n        currentDocument?.insertNodes(formNode, [createdNode1, createdNode2], 1);\n        expect(nodesMap?.size).toBe(ids.length + 2);\n        expect(formNode.children?.length).toBe(5);\n        const insertedNode1 = formNode.children?.get(1);\n        const insertedNode2 = formNode.children?.get(2);\n        expect(insertedNode1?.componentName).toBe('TextInput');\n        expect(insertedNode1?.propsData).toEqual({\n          propA: 'haha2',\n          propB: 3,\n        });\n        expect(insertedNode2?.componentName).toBe('TextInput2');\n        expect(insertedNode2?.propsData).toEqual({\n          propA: 'haha',\n          propB: 3,\n        });\n      });\n    });\n  });\n\n  describe('block ❌ | component ❌ | slot ✅', () => {\n    it('基本的 slot 创建', () => {\n      const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title.type', 'JSSlot');\n      const project = new Project(designer, {\n        componentsTree: [\n          formSchemaWithSlot,\n        ],\n      });\n      project.open();\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const nodesMap = currentDocument?.nodesMap;\n      const ids = getIdsFromSchema(formSchema);\n      // 目前每个 slot 会新增（1 + children.length）个节点\n      const expectedNodeCnt = ids.length + 2;\n      expect(nodesMap?.size).toBe(expectedNodeCnt);\n      // PageHeader\n      expect(nodesMap?.get('node_k1ow3cbd')?.slots).toHaveLength(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/node.dragdrop.test.ts",
    "content": "import '../../fixtures/window';\nimport { Project } from '../../../src/project/project';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form';\nimport { getIdsFromSchema, getNodeFromSchemaById } from '../../utils';\n\nconst mockCreateSettingEntry = jest.fn();\njest.mock('../../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      return {\n        getComponentMeta() {\n          return {\n            getMetadata() {\n              return { configure: { advanced: null } };\n            },\n          };\n        },\n        transformProps(props) { return props; },\n        createSettingEntry: mockCreateSettingEntry,\n        postEvent() {},\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({});\n});\n\ndescribe.skip('节点拖拽测试', () => {\n  describe('block ❌ | component ❌ | slot ❌', () => {\n    it('修改普通属性，string | number', () => {\n      const project = new Project(designer, {\n        componentsTree: [\n          formSchema,\n        ],\n      });\n      project.open();\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      expect(nodesMap.size).toBe(expectedNodeCnt);\n      ids.forEach(id => {\n        expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);\n      });\n\n      const exportSchema = currentDocument?.export(1);\n      expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);\n      expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/node.modify.test.ts",
    "content": "import '../../fixtures/window';\nimport { Project } from '../../../src/project/project';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form';\nimport { getIdsFromSchema, getNodeFromSchemaById } from '../../utils';\n\nconst mockCreateSettingEntry = jest.fn();\njest.mock('../../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      return {\n        getComponentMeta() {\n          return {\n            getMetadata() {\n              return { configure: { advanced: null } };\n            },\n            get advanced() {\n              return {};\n            },\n          };\n        },\n        transformProps(props) { return props; },\n        createSettingEntry: mockCreateSettingEntry,\n        postEvent() {},\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({});\n});\n\ndescribe('schema 生成节点模型测试', () => {\n  describe('block ❌ | component ❌ | slot ❌', () => {\n    let project: Project;\n    beforeEach(() => {\n      project = new Project(designer, {\n        componentsTree: [\n          formSchema,\n        ],\n      });\n      project.open();\n    });\n    it('读取普通属性，string | number | object', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      const formNode = currentDocument?.getNode('form');\n      /*\n        props: {\n          size: 'medium',\n          labelAlign: 'top',\n          autoValidate: true,\n          scrollToFirstError: true,\n          autoUnmount: true,\n          behavior: 'NORMAL',\n          dataSource: {\n            type: 'variable',\n            variable: 'state.formData',\n          },\n          obj: {\n            a: 1,\n            b: false,\n            c: 'string',\n          },\n          __style__: {},\n          fieldId: 'form',\n          fieldOptions: {},\n        },\n        id: 'form',\n        condition: true,\n      */\n      const sizeProp = formNode?.getProp('size');\n      const sizeProp2 = formNode?.getProps().getProp('size');\n      expect(sizeProp).toBe(sizeProp2);\n      expect(sizeProp?.getAsString()).toBe('medium');\n      expect(sizeProp?.getValue()).toBe('medium');\n\n      const autoValidateProp = formNode?.getProp('autoValidate');\n      expect(autoValidateProp?.getValue()).toBe(true);\n\n      const objProp = formNode?.getProp('obj');\n      expect(objProp?.getValue()).toEqual({\n        a: 1,\n        b: false,\n        c: 'string',\n      });\n      const objAProp = formNode?.getProp('obj.a');\n      const objBProp = formNode?.getProp('obj.b');\n      const objCProp = formNode?.getProp('obj.c');\n      expect(objAProp?.getValue()).toBe(1);\n      expect(objBProp?.getValue()).toBe(false);\n      expect(objCProp?.getValue()).toBe('string');\n\n      const idProp = formNode?.getExtraProp('extraPropA');\n      expect(idProp?.getValue()).toBe('extraPropA');\n    });\n\n    it('修改普通属性，string | number | object，使用 Node 实例接口', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      const formNode = currentDocument?.getNode('form');\n      /*\n        props: {\n          size: 'medium',\n          labelAlign: 'top',\n          autoValidate: true,\n          scrollToFirstError: true,\n          autoUnmount: true,\n          behavior: 'NORMAL',\n          dataSource: {\n            type: 'variable',\n            variable: 'state.formData',\n          },\n          obj: {\n            a: 1,\n            b: false,\n            c: 'string',\n          },\n          __style__: {},\n          fieldId: 'form',\n          fieldOptions: {},\n        },\n        id: 'form',\n        condition: true,\n      */\n      formNode?.setPropValue('size', 'large');\n      const sizeProp = formNode?.getProp('size');\n      expect(sizeProp?.getAsString()).toBe('large');\n      expect(sizeProp?.getValue()).toBe('large');\n\n      formNode?.setPropValue('autoValidate', false);\n      const autoValidateProp = formNode?.getProp('autoValidate');\n      expect(autoValidateProp?.getValue()).toBe(false);\n\n      formNode?.setPropValue('obj', {\n        a: 2,\n        b: true,\n        c: 'another string',\n      });\n      const objProp = formNode?.getProp('obj');\n      expect(objProp?.getValue()).toEqual({\n        a: 2,\n        b: true,\n        c: 'another string',\n      });\n      formNode?.setPropValue('obj.a', 3);\n      formNode?.setPropValue('obj.b', false);\n      formNode?.setPropValue('obj.c', 'string');\n      const objAProp = formNode?.getProp('obj.a');\n      const objBProp = formNode?.getProp('obj.b');\n      const objCProp = formNode?.getProp('obj.c');\n      expect(objAProp?.getValue()).toBe(3);\n      expect(objBProp?.getValue()).toBe(false);\n      expect(objCProp?.getValue()).toBe('string');\n      expect(objProp?.getValue()).toEqual({\n        a: 3,\n        b: false,\n        c: 'string',\n      });\n    });\n\n    it('修改普通属性，string | number | object，使用 Props 实例接口', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      const formNode = currentDocument?.getNode('form');\n      /*\n        props: {\n          size: 'medium',\n          labelAlign: 'top',\n          autoValidate: true,\n          scrollToFirstError: true,\n          autoUnmount: true,\n          behavior: 'NORMAL',\n          dataSource: {\n            type: 'variable',\n            variable: 'state.formData',\n          },\n          obj: {\n            a: 1,\n            b: false,\n            c: 'string',\n          },\n          __style__: {},\n          fieldId: 'form',\n          fieldOptions: {},\n        },\n        id: 'form',\n        condition: true,\n      */\n      const props = formNode?.getProps();\n      props?.setPropValue('size', 'large');\n      const sizeProp = formNode?.getProp('size');\n      expect(sizeProp?.getAsString()).toBe('large');\n      expect(sizeProp?.getValue()).toBe('large');\n\n      props?.setPropValue('autoValidate', false);\n      const autoValidateProp = formNode?.getProp('autoValidate');\n      expect(autoValidateProp?.getValue()).toBe(false);\n\n      props?.setPropValue('obj', {\n        a: 2,\n        b: true,\n        c: 'another string',\n      });\n      const objProp = formNode?.getProp('obj');\n      expect(objProp?.getValue()).toEqual({\n        a: 2,\n        b: true,\n        c: 'another string',\n      });\n      props?.setPropValue('obj.a', 3);\n      props?.setPropValue('obj.b', false);\n      props?.setPropValue('obj.c', 'string');\n      const objAProp = formNode?.getProp('obj.a');\n      const objBProp = formNode?.getProp('obj.b');\n      const objCProp = formNode?.getProp('obj.c');\n      expect(objAProp?.getValue()).toBe(3);\n      expect(objBProp?.getValue()).toBe(false);\n      expect(objCProp?.getValue()).toBe('string');\n      expect(objProp?.getValue()).toEqual({\n        a: 3,\n        b: false,\n        c: 'string',\n      });\n    });\n\n    it('修改普通属性，string | number | object，使用 Prop 实例接口', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      const formNode = currentDocument?.getNode('form');\n      /*\n        props: {\n          size: 'medium',\n          labelAlign: 'top',\n          autoValidate: true,\n          scrollToFirstError: true,\n          autoUnmount: true,\n          behavior: 'NORMAL',\n          dataSource: {\n            type: 'variable',\n            variable: 'state.formData',\n          },\n          obj: {\n            a: 1,\n            b: false,\n            c: 'string',\n          },\n          __style__: {},\n          fieldId: 'form',\n          fieldOptions: {},\n        },\n        id: 'form',\n        condition: true,\n      */\n      const sizeProp = formNode?.getProp('size');\n     sizeProp?.setValue('large');\n     expect(sizeProp?.getAsString()).toBe('large');\n     expect(sizeProp?.getValue()).toBe('large');\n\n     const autoValidateProp = formNode?.getProp('autoValidate');\n     autoValidateProp?.setValue(false);\n     expect(autoValidateProp?.getValue()).toBe(false);\n\n\n     const objProp = formNode?.getProp('obj');\n     objProp?.setValue({\n       a: 2,\n       b: true,\n       c: 'another string',\n     });\n     expect(objProp?.getValue()).toEqual({\n       a: 2,\n       b: true,\n       c: 'another string',\n     });\n     const objAProp = formNode?.getProp('obj.a');\n     const objBProp = formNode?.getProp('obj.b');\n     const objCProp = formNode?.getProp('obj.c');\n     objAProp?.setValue(3);\n     objBProp?.setValue(false);\n     objCProp?.setValue('string');\n     expect(objAProp?.getValue()).toBe(3);\n     expect(objBProp?.getValue()).toBe(false);\n     expect(objCProp?.getValue()).toBe('string');\n     expect(objProp?.getValue()).toEqual({\n       a: 3,\n       b: false,\n       c: 'string',\n     });\n    });\n  });\n\n  describe('block ❌ | component ❌ | slot ✅', () => {\n    let project: Project;\n    beforeEach(() => {\n      project = new Project(designer, {\n        componentsTree: [\n          formSchema,\n        ],\n      });\n      project.open();\n    });\n    it('修改 slot 属性，初始存在 slot 属性名，正常生成节点模型', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      const formNode = currentDocument?.getNode('form');\n\n      formNode?.setPropValue('slotA', {\n        type: 'JSSlot',\n        value: [{\n          componentName: 'TextInput1',\n          props: {\n            txt: 'haha',\n            num: 1,\n            bool: true,\n          },\n        }, {\n          componentName: 'TextInput2',\n          props: {\n            txt: 'heihei',\n            num: 2,\n            bool: false,\n          },\n        }],\n      });\n\n      expect(nodesMap.size).toBe(ids.length + 3);\n      expect(formNode?.slots).toHaveLength(1);\n      expect(formNode?.slots[0].children).toHaveLength(2);\n      const firstChildNode = formNode?.slots[0].children?.get(0);\n      const secondChildNode = formNode?.slots[0].children?.get(1);\n      expect(firstChildNode?.componentName).toBe('TextInput1');\n      expect(firstChildNode?.getPropValue('txt')).toBe('haha');\n      expect(firstChildNode?.getPropValue('num')).toBe(1);\n      expect(firstChildNode?.getPropValue('bool')).toBe(true);\n      expect(secondChildNode?.componentName).toBe('TextInput2');\n      expect(secondChildNode?.getPropValue('txt')).toBe('heihei');\n      expect(secondChildNode?.getPropValue('num')).toBe(2);\n      expect(secondChildNode?.getPropValue('bool')).toBe(false);\n    });\n\n    it('修改 slot 属性，初始存在 slot 属性名，关闭 slot', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      const formNode = currentDocument?.getNode('form');\n\n      formNode?.setPropValue('slotA', {\n        type: 'JSSlot',\n        value: [{\n          componentName: 'TextInput1',\n          props: {\n            txt: 'haha',\n            num: 1,\n            bool: true,\n          },\n        }, {\n          componentName: 'TextInput2',\n          props: {\n            txt: 'heihei',\n            num: 2,\n            bool: false,\n          },\n        }],\n      });\n\n      expect(nodesMap.size).toBe(ids.length + 3);\n      expect(formNode?.slots).toHaveLength(1);\n\n      formNode?.setPropValue('slotA', '');\n\n      expect(nodesMap.size).toBe(ids.length);\n      expect(formNode?.slots).toHaveLength(0);\n    });\n\n    it('修改 slot 属性，初始存在 slot 属性名，同名覆盖 slot', () => {\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      const formNode = currentDocument?.getNode('form');\n\n      formNode?.setPropValue('slotA', {\n        type: 'JSSlot',\n        name: 'slotA',\n        value: [{\n          componentName: 'TextInput1',\n          props: {\n            txt: 'haha',\n            num: 1,\n            bool: true,\n          },\n        }, {\n          componentName: 'TextInput2',\n          props: {\n            txt: 'heihei',\n            num: 2,\n            bool: false,\n          },\n        }],\n      });\n\n      expect(nodesMap.size).toBe(ids.length + 3);\n      expect(formNode?.slots).toHaveLength(1);\n      expect(formNode?.slots[0].children).toHaveLength(2);\n\n      let firstChildNode = formNode?.slots[0].children?.get(0);\n      expect(firstChildNode?.componentName).toBe('TextInput1');\n      expect(firstChildNode?.getPropValue('txt')).toBe('haha');\n      expect(firstChildNode?.getPropValue('num')).toBe(1);\n      expect(firstChildNode?.getPropValue('bool')).toBe(true);\n\n      formNode?.setPropValue('slotA', {\n        type: 'JSSlot',\n        name: 'slotA',\n        value: [{\n          componentName: 'TextInput3',\n          props: {\n            txt: 'xixi',\n            num: 3,\n            bool: false,\n          },\n        }],\n      });\n\n      expect(nodesMap.size).toBe(ids.length + 2);\n      expect(formNode?.slots).toHaveLength(1);\n      expect(formNode?.slots[0].children).toHaveLength(1);\n      firstChildNode = formNode?.slots[0].children?.get(0);\n      expect(firstChildNode?.componentName).toBe('TextInput3');\n      expect(firstChildNode?.getPropValue('txt')).toBe('xixi');\n      expect(firstChildNode?.getPropValue('num')).toBe(3);\n      expect(firstChildNode?.getPropValue('bool')).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/node.remove.test.ts",
    "content": "import set from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport '../../fixtures/window';\nimport { Project } from '../../../src/project/project';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form';\nimport { getIdsFromSchema } from '../../utils';\n\nconst mockCreateSettingEntry = jest.fn();\njest.mock('../../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      return {\n        getComponentMeta() {\n          return {\n            getMetadata() {\n              return { configure: { advanced: null } };\n            },\n            get advanced() {\n              return {};\n            },\n          };\n        },\n        transformProps(props) { return props; },\n        createSettingEntry: mockCreateSettingEntry,\n        postEvent() {},\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({});\n});\n\ndescribe('节点模型删除测试', () => {\n  it('删除叶子节点', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap } = currentDocument;\n    const ids = getIdsFromSchema(formSchema);\n    const originalNodeCnt = ids.length;\n    expect(nodesMap.size).toBe(originalNodeCnt);\n\n    currentDocument?.removeNode('node_k1ow3cbn');\n    // Button#1\n    expect(nodesMap.size).toBe(originalNodeCnt - 1);\n\n    currentDocument?.removeNode(nodesMap.get('node_k1ow3cbp'));\n    // Button#2\n    expect(nodesMap.size).toBe(originalNodeCnt - 2);\n\n    currentDocument?.removeNode('unexisting_node');\n    expect(nodesMap.size).toBe(originalNodeCnt - 2);\n  });\n\n  it('删除叶子节点，带有 slot', () => {\n    const formSchemaWithSlot = set(cloneDeep(formSchema),\n      'children[1].children[0].children[2].children[1].props.greeting.type', 'JSSlot');\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchemaWithSlot,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap } = currentDocument;\n    const ids = getIdsFromSchema(formSchema);\n    const originalNodeCnt = ids.length + 2;\n    expect(nodesMap.size).toBe(originalNodeCnt);\n\n    currentDocument?.removeNode('node_k1ow3cbp');\n    // Button + Slot + Text\n    expect(nodesMap.size).toBe(originalNodeCnt - 3);\n  });\n\n  it('删除分支节点', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap } = currentDocument;\n    const ids = getIdsFromSchema(formSchema);\n    const originalNodeCnt = ids.length;\n    expect(nodesMap.size).toBe(originalNodeCnt);\n\n    currentDocument?.removeNode('node_k1ow3cbo');\n    // Div + 2 * Button\n    expect(nodesMap.size).toBe(originalNodeCnt - 3);\n  });\n\n  it('删除分支节点，带有 slot', () => {\n    const formSchemaWithSlot = set(cloneDeep(formSchema),\n      'children[1].children[0].children[2].children[1].props.greeting.type', 'JSSlot');\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchemaWithSlot,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap } = currentDocument;\n    const ids = getIdsFromSchema(formSchema);\n    const originalNodeCnt = ids.length + 2;\n    expect(nodesMap.size).toBe(originalNodeCnt);\n\n    currentDocument?.removeNode('node_k1ow3cbo');\n    // Div + 2 * Button + Slot + Text\n    expect(nodesMap.size).toBe(originalNodeCnt - 5);\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/node.test.ts",
    "content": "// @ts-nocheck\nimport '../../fixtures/window';\nimport { set } from '../../utils';\nimport {\n  Editor,\n  globalContext,\n  Setters as InnerSetters,\n} from '@alilc/lowcode-editor-core';\nimport { Project } from '../../../src/project/project';\nimport { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace';\nimport { DocumentModel } from '../../../src/document/document-model';\nimport {\n  isRootNode,\n  Node,\n  comparePosition,\n  contains,\n  PositionNO,\n} from '../../../src/document/node/node';\nimport { Designer } from '../../../src/designer/designer';\nimport formSchema from '../../fixtures/schema/form';\nimport divMetadata from '../../fixtures/component-metadata/div';\nimport dialogMetadata from '../../fixtures/component-metadata/dialog';\nimport btnMetadata from '../../fixtures/component-metadata/button';\nimport formMetadata from '../../fixtures/component-metadata/form';\nimport pageMetadata from '../../fixtures/component-metadata/page';\nimport rootHeaderMetadata from '../../fixtures/component-metadata/root-header';\nimport rootContentMetadata from '../../fixtures/component-metadata/root-content';\nimport rootFooterMetadata from '../../fixtures/component-metadata/root-footer';\nimport { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';\nimport { isNode } from '@alilc/lowcode-utils';\nimport { Setters } from '@alilc/lowcode-shell';\n\ndescribe('Node 方法测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n\n  beforeEach(() => {\n    editor = new Editor();\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    doc = new DocumentModel(project, formSchema);\n    editor.set('setters', new Setters(new InnerSetters()));\n    !globalContext.has(Editor) && globalContext.register(editor, Editor);\n    !globalContext.has('workspace') && globalContext.register(new InnerWorkspace(), 'workspace');\n  });\n\n  afterEach(() => {\n    project.unload();\n    designer.purge();\n    editor = null;\n    designer = null;\n    project = null;\n  });\n\n  // Case 1: When children is null\n  test('initialChildren returns result of initialChildren function when children is null ', () => {\n    const node = new Node(doc, { componentName: 'Button', props: { a: 1 } });\n    const result = node.initialChildren(null);\n    // 预期结果是一个空数组\n    expect(result).toEqual([]);\n  });\n\n  // Case 2: When children is undefined\n  test('initialChildren returns result of initialChildren function when children is null ', () => {\n    const node = new Node(doc, { componentName: 'Button', props: { a: 1 } });\n    const result = node.initialChildren(undefined);\n    // 预期结果是一个空数组\n    expect(result).toEqual([]);\n  });\n\n  // Case 3: When children is array\n  test('initialChildren returns result of initialChildren function when children is null ', () => {\n    const node = new Node(doc, { componentName: 'Button', props: { a: 1 } });\n    const childrenArray = [{ id: 1, name: 'Child 1' }, { id: 2, name: 'Child 2' }];\n    const result = node.initialChildren(childrenArray);\n    // 预期结果是一个数组\n    expect(result).toEqual(childrenArray);\n  });\n\n  // Case 4: When children is not null and not an array\n  test('initialChildren returns result of initialChildren function when children is null ', () => {\n    const node = new Node(doc, { componentName: 'Button', props: { a: 1 } });\n    const childObject = { id: 1, name: 'Child 1' };\n    const result = node.initialChildren(childObject);\n    // 预期结果是一个数组\n    expect(result).toEqual([childObject]);\n  });\n\n  // Case 5: When children 0\n  test('initialChildren returns result of initialChildren function when children is null ', () => {\n    const node = new Node(doc, { componentName: 'Button', props: { a: 1 } });\n    const childObject = 0;\n    const result = node.initialChildren(childObject);\n    // 预期结果是一个数组\n    expect(result).toEqual([0]);\n  });\n\n  // Case 6: When children false\n  test('initialChildren returns result of initialChildren function when children is null ', () => {\n    const node = new Node(doc, { componentName: 'Button', props: { a: 1 } });\n    const childObject = false;\n    const result = node.initialChildren(childObject);\n    // 预期结果是一个数组\n    expect(result).toEqual([false]);\n  });\n\n\n  it('condition group', () => { });\n\n  it('getExtraProp / setExtraProp', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    expect(firstBtn.getExtraProp('non-existing', false)).toBeNull();\n\n    firstBtn.setExtraProp('xxx', '1111');\n    expect(firstBtn.getExtraProp('xxx', false).getValue()).toBe('1111');\n  });\n\n  it('import(leaf)', () => {\n    const form = doc.getNode('node_k1ow3cbo');\n    form.insert({ componentName: 'Leaf', children: '111' });\n\n    const leaf = form.getChildren().get(2);\n    expect(leaf.getPropValue('children')).toBe('111');\n\n    leaf.import({ componentName: 'Leaf', children: '222' });\n    expect(leaf.getPropValue('children')).toBe('222');\n\n    leaf.import({ componentName: 'Leaf', children: { type: 'JSExpression', value: 'state.x' } });\n    expect(leaf.getPropValue('children')).toEqual({ type: 'JSExpression', value: 'state.x' });\n  });\n\n  it('hasCondition', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    firstBtn.getExtraProp('condition')?.setValue(undefined);\n    expect(firstBtn.hasCondition()).toBeFalsy();\n\n    firstBtn.getExtraProp('condition')?.setValue(null);\n    expect(firstBtn.hasCondition()).toBeFalsy();\n\n    firstBtn.getExtraProp('condition')?.setValue(true);\n    expect(firstBtn.hasCondition()).toBeFalsy();\n\n    firstBtn.getExtraProp('condition')?.setValue('');\n    expect(firstBtn.hasCondition()).toBeFalsy();\n\n    firstBtn.getExtraProp('condition')?.setValue(1);\n    expect(firstBtn.hasCondition()).toBeTruthy();\n\n    firstBtn.getExtraProp('condition')?.setValue(false);\n    expect(firstBtn.hasCondition()).toBeTruthy();\n  });\n\n  it('hasLoop', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    expect(firstBtn.hasLoop()).toBeFalsy();\n\n    // 这里必须用 add，因为 hasLoop 实现的跳过了 stash\n    firstBtn.props.add([1, 2], '___loop___');\n    expect(firstBtn.hasLoop()).toBeTruthy();\n\n    firstBtn.getExtraProp('loop')?.setValue({ type: 'JSExpression', value: 'state.a' });\n    expect(firstBtn.hasLoop()).toBeTruthy();\n\n    firstBtn.getExtraProp('loop')?.setValue(1);\n    expect(firstBtn.hasLoop()).toBeFalsy();\n  });\n\n  describe('getSuitablePlace', () => {\n    it('root，子节点中有容器节点', () => {\n      designer.createComponentMeta(pageMetadata);\n      designer.createComponentMeta(rootHeaderMetadata);\n      designer.createComponentMeta(rootContentMetadata);\n      designer.createComponentMeta(rootFooterMetadata);\n\n      const rootHeaderMeta = designer.getComponentMeta('RootHeader');\n      set(rootHeaderMeta, 'prototype.options.canDropIn', true);\n\n      let o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1);\n      expect(o).toEqual({\n        container: doc.getNode('node_k1ow3cba'),\n        ref: 1,\n      });\n\n      set(rootHeaderMeta, 'prototype.options.canDropIn', () => true);\n      o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1);\n      expect(o).toEqual({\n        container: doc.getNode('node_k1ow3cba'),\n        ref: 1,\n      });\n    });\n\n    it('root，直接子节点中无容器节点，自身支持放入子节点', () => {\n      designer.createComponentMeta(pageMetadata);\n\n      let o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1);\n\n      const pageMeta = designer.getComponentMeta('Page');\n      set(pageMeta, 'prototype.options.canDropIn', () => true);\n\n      expect(o).toEqual({\n        container: doc.rootNode,\n        ref: 1,\n      });\n\n      set(pageMeta, 'prototype.options.canDropIn', undefined);\n      o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1);\n      expect(o).toEqual({\n        container: doc.rootNode,\n        ref: 1,\n      });\n\n      set(pageMeta, 'prototype.options.canDropIn', true);\n      o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1);\n      expect(o).toEqual({\n        container: doc.rootNode,\n        ref: 1,\n      });\n    });\n\n    it('root，子节点中无容器节点，自己也不支持放入子节点', () => {\n      designer.createComponentMeta(pageMetadata);\n\n      let pageMeta = designer.getComponentMeta('Page');\n\n      pageMeta = set(pageMeta, 'prototype.options.canDropIn', () => false);\n      let o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1);\n      expect(o).toBeNull();\n\n      set(pageMeta, 'prototype.options.canDropIn', false);\n      o = doc.rootNode?.getSuitablePlace(doc.getNode('form'), 1);\n      expect(o).toBeNull();\n    });\n\n    it('放入模态节点', () => {\n      designer.createComponentMeta(pageMetadata);\n      designer.createComponentMeta(dialogMetadata);\n\n      const dialog = doc.createNode({ componentName: 'Dialog' });\n\n      const o = doc.rootNode?.getSuitablePlace(dialog, 1);\n      expect(o.container).toBe(doc.rootNode);\n      expect(o.ref).toBe(1);\n    });\n\n    it('包含 focusNode', () => {\n      const o = doc.rootNode?.getSuitablePlace(doc.rootNode);\n      expect(o.container).toBe(doc.rootNode);\n    });\n\n    it.skip('非 root 节点，不能放入子节点', () => {\n      designer.createComponentMeta(formMetadata);\n      designer.createComponentMeta(pageMetadata);\n\n      // form 子节点以及自身都不能放入子节点\n      const formMeta = designer.getComponentMeta('Form');\n      set(formMeta, 'prototype.options.canDropIn', false);\n\n      const pageMeta = designer.getComponentMeta('Page');\n      set(pageMeta, 'prototype.options.canDropIn', () => true);\n\n      const o = doc.getNode('form')!.getSuitablePlace(doc.getNode('node_k1ow3cbj'), { index: 1 });\n      expect(o).toEqual({\n        container: doc.rootNode,\n        ref: { index: 1 },\n      });\n    });\n\n    it('非 root 节点，能放入子节点', () => {\n      designer.createComponentMeta(formMetadata);\n      designer.createComponentMeta(pageMetadata);\n\n      // form 子节点以及自身都不能放入子节点\n      const formMeta = designer.getComponentMeta('Form');\n      set(formMeta, 'prototype.options.canDropIn', true);\n\n      const o = doc.getNode('form')!.getSuitablePlace(doc.getNode('node_k1ow3cbj'), 1);\n      expect(o).toEqual({\n        container: doc.getNode('form'),\n        ref: 1,\n      });\n    });\n\n    it('null', () => {\n      expect(\n        doc.rootNode?.getSuitablePlace.call({\n          contains: () => false,\n          isContainer: () => false,\n          isRoot: () => false,\n        }),\n      ).toBeNull();\n    });\n  });\n\n  it('removeChild / replaceWith / replaceChild', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const form = doc.getNode('node_k1ow3cbo');\n\n    // 不符合条件的节点直接返回\n    expect(firstBtn.replaceChild(form, { componentName: 'Button', props: { x: 1 } })).toBe(form);\n\n    firstBtn.select();\n    firstBtn.parent?.replaceChild(firstBtn, { componentName: 'Button', props: { x: 1 } });\n\n    expect(firstBtn.parent?.getChildren()?.size).toBe(2);\n    expect(firstBtn.parent?.getChildren()?.get(0)?.getPropValue('x')).toBe(1);\n\n    const secondBtn = doc.getNode('node_k1ow3cbp')!;\n    secondBtn.replaceWith({ componentName: 'Button', props: { y: 1 } });\n    expect(firstBtn.parent?.getChildren()?.size).toBe(2);\n    expect(firstBtn.parent?.getChildren()?.get(1)?.getPropValue('y')).toBe(1);\n  });\n\n  it('schema', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const schema = firstBtn.schema;\n    schema.props.size = 'large';\n    firstBtn.schema = schema;\n\n    expect(firstBtn.getPropValue('size')).toBe('large');\n  });\n\n  describe('插入相关方法', () => {\n    it('insertBefore / onChildrenChange', () => {\n      const firstBtn = doc.getNode('node_k1ow3cbn')!;\n      const secondBtn = doc.getNode('node_k1ow3cbp')!;\n      const btnParent = firstBtn.parent!;\n      const mockFn = jest.fn();\n      const off = btnParent.onChildrenChange(mockFn);\n\n      // Node 实例\n      btnParent.insertBefore(new Node(doc, { componentName: 'Button', props: { a: 1 } }), firstBtn);\n      expect(btnParent.children.get(0)?.getProps().export().props).toEqual({ a: 1 });\n      expect(mockFn).toHaveBeenCalledTimes(1);\n\n      // TODO: 暂时不支持，后面补上\n      // // NodeSchema\n      // btnParent.insertBefore({ componentName: 'Button', props: { b: 1 } }, firstBtn);\n      // expect(btnParent.children.get(0)?.getProps().export().props).toEqual({ b: 1 });\n      // expect(mockFn).toHaveBeenCalledTimes(2);\n\n      // // getComponentName\n      // btnParent.insertBefore({ getComponentName: () => 'Button', props: { c: 1 } }, firstBtn);\n      // expect(btnParent.children.get(0)?.getProps().export().props).toEqual({ c: 1 });\n      // expect(mockFn).toHaveBeenCalledTimes(3);\n    });\n\n    it('insertAfter / onChildrenChange', () => {\n      const firstBtn = doc.getNode('node_k1ow3cbn')!;\n      const secondBtn = doc.getNode('node_k1ow3cbp')!;\n      const btnParent = firstBtn.parent!;\n      const mockFn = jest.fn();\n      const off = btnParent.onChildrenChange(mockFn);\n\n      // Node 实例\n      btnParent.insertAfter(new Node(doc, { componentName: 'Button', props: { a: 1 } }), firstBtn);\n      expect(btnParent.children.get(1)?.getProps().export().props).toEqual({ a: 1 });\n      expect(mockFn).toHaveBeenCalledTimes(1);\n\n      // NodeSchema\n      btnParent.insertAfter({ componentName: 'Button', props: { b: 1 } }, firstBtn);\n      expect(btnParent.children.get(1)?.getProps().export().props).toEqual({ b: 1 });\n      expect(mockFn).toHaveBeenCalledTimes(2);\n\n      // getComponentName\n      btnParent.insertAfter({ getComponentName: () => 'Button' }, firstBtn);\n      expect(btnParent.children.get(1)?.getProps().export().props).toEqual({});\n      expect(mockFn).toHaveBeenCalledTimes(3);\n    });\n  });\n\n  it('setVisible / getVisible / onVisibleChange', () => {\n    const mockFn = jest.fn();\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const off = firstBtn.onVisibleChange(mockFn);\n    firstBtn.setVisible(true);\n    expect(firstBtn.getVisible()).toBeTruthy();\n    expect(mockFn).toHaveBeenCalledTimes(1);\n    expect(mockFn).toHaveBeenCalledWith(true);\n\n    firstBtn.setVisible(false);\n\n    expect(firstBtn.getVisible()).toBeFalsy();\n    expect(mockFn).toHaveBeenCalledTimes(2);\n    expect(mockFn).toHaveBeenCalledWith(false);\n\n    off();\n    mockFn.mockClear();\n    firstBtn.setVisible(true);\n    expect(mockFn).not.toHaveBeenCalled();\n  });\n\n  it('RGL / getRGL', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    firstBtn.isRGLContainer = true;\n    expect(firstBtn.isRGLContainer).toBeTruthy();\n\n    const rgl = firstBtn.getRGL();\n    expect(rgl.isContainerNode).toBeFalsy();\n    expect(rgl.isEmptyNode).toBeTruthy();\n    expect(rgl.isRGLContainerNode).toBeTruthy();\n    expect(rgl.isRGLNode).toBeFalsy();\n    expect(rgl.isRGL).toBeTruthy();\n  });\n\n  it('onPropChange', () => {\n    const mockFn = jest.fn();\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const off = firstBtn.onPropChange(mockFn);\n\n    firstBtn.setPropValue('x', 1);\n    expect(mockFn).toHaveBeenCalledTimes(1);\n    firstBtn.setPropValue('x', 2);\n    expect(mockFn).toHaveBeenCalledTimes(2);\n\n    off();\n    mockFn.mockClear();\n    firstBtn.setPropValue('x', 3);\n    expect(mockFn).not.toHaveBeenCalled();\n  });\n\n  it('addSlot / unlinkSlot / removeSlot', () => { });\n\n  it('setProps', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const secondBtn = doc.getNode('node_k1ow3cbp')!;\n\n    firstBtn.setProps(secondBtn.getProps());\n    expect(firstBtn.getProps()).toBe(secondBtn.getProps());\n  });\n\n  it('advanced initials / autoruns', async () => {\n    designer.createComponentMeta(pageMetadata);\n\n    const pageMeta = designer.getComponentMeta('Page');\n    const autorunMockFn = jest.fn();\n    set(pageMeta, '_transformedMetadata.configure.advanced.autoruns', [\n      { name: 'a', autorun: autorunMockFn },\n    ]);\n    const initialChildrenMockFn = jest.fn();\n    set(pageMeta, '_transformedMetadata.configure.advanced.initialChildren', initialChildrenMockFn);\n    doc.createNode({ componentName: 'Page', props: { a: 1 } });\n\n    expect(autorunMockFn).toHaveBeenCalled();\n    expect(initialChildrenMockFn).toHaveBeenCalled();\n\n    set(pageMeta, '_transformedMetadata.configure.advanced.initialChildren', {});\n    doc.createNode({ componentName: 'Page', props: { a: 1 } });\n    expect(autorunMockFn).toHaveBeenCalledTimes(2);\n  });\n\n  it('isValidComponent', () => {\n    designer.createComponentMeta(divMetadata);\n    expect(doc.getNode('node_k1ow3cbo')?.isValidComponent()).toBeTruthy();\n    expect(doc.getNode('form')?.isValidComponent()).toBeFalsy();\n  });\n\n  it('title', () => {\n    designer.createComponentMeta(btnMetadata);\n    const btn = doc.getNode('node_k1ow3cbn');\n    // 从 componentMeta 中获取到 title 值\n    expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' });\n    // 从 extraProp 中获取值\n    btn.setExtraProp('title', 'hello button');\n    expect(btn.title).toBe('hello button');\n\n    // btn.props.deleteKey('___title___');\n    // 从 componentMeta descriptor 指向的 key 获取 title\n    // btn.setPropValue('xTitle', 'title from descriptor')\n    // expect(btn.title).toBe('title from descriptor');\n  });\n\n  it('isEmpty / getIndex / getIcon', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    // expect(firstBtn.children).toBeNull();\n    expect(firstBtn.isEmpty()).toBeTruthy();\n    expect(firstBtn.index).toBe(0);\n    expect(firstBtn.getIndex()).toBe(0);\n    expect(typeof firstBtn.getIcon()).toBe('function');\n    expect(doc.getNode('page')!.index).toBe(-1);\n  });\n\n  it('schema / toData / export', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    expect(firstBtn.toData().componentName).toBe('Button');\n  });\n\n  it('internalSetParent / internalSetWillPurge', () => {\n    const firstChild = doc.rootNode?.getChildren()?.get(0);\n    firstChild?.internalSetParent(doc.rootNode);\n\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    firstBtn.internalSetWillPurge();\n    // expect(firstBtn.parent).();\n\n    expect(firstBtn.hasSlots()).toBeFalsy();\n  });\n\n  it('prevSibling / nextSibling', () => {\n    // no parent\n    const page = doc.getNode('page');\n    expect(page?.nextSibling).toBeNull();\n    expect(page?.prevSibling).toBeNull();\n\n    // normal\n    const firstBtn = doc.getNode('node_k1ow3cbn');\n    const secondBtn = doc.getNode('node_k1ow3cbp');\n    expect(firstBtn?.nextSibling).toBe(secondBtn);\n    expect(secondBtn?.prevSibling).toBe(firstBtn);\n    expect(secondBtn?.nextSibling).toBeNull();\n\n    // index < 0\n    firstBtn?.parent?.removeChild(firstBtn);\n    expect(firstBtn?.nextSibling).toBeNull();\n    expect(firstBtn?.prevSibling).toBeNull();\n  });\n\n  it('toString', () => {\n    expect(doc.rootNode.toString()).toBe('page');\n  });\n\n  it('lock', () => {\n    const form = doc.getNode('node_k1ow3cbo');\n    expect(form.isLocked).toBeFalsy();\n    form.lock(true);\n    expect(form.isLocked).toBeTruthy();\n    form.lock(false);\n    expect(form.isLocked).toBeFalsy();\n    form.lock();\n    expect(form.isLocked).toBeTruthy();\n  });\n\n  it('didDropIn / didDropOut', () => {\n    const form = doc.getNode('node_k1ow3cbo');\n    designer.createComponentMeta(divMetadata);\n    designer.createComponentMeta(formMetadata);\n    const callbacks = form.componentMeta.advanced.callbacks;\n    const fn1 = callbacks.onNodeAdd = jest.fn();\n    const fn2 = callbacks.onNodeRemove = jest.fn();\n    const textField = doc.getNode('node_k1ow3cc9');\n    form.didDropIn(textField);\n    expect(fn1).toHaveBeenCalledWith(textField.internalToShellNode(), form.internalToShellNode());\n\n    form.didDropOut(textField);\n    expect(fn2).toHaveBeenCalledWith(textField.internalToShellNode(), form.internalToShellNode());\n  });\n\n  it('hover', () => {\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    firstBtn.hover(true);\n    expect(doc.designer.detecting.current).toBe(firstBtn);\n    firstBtn.hover(false);\n    expect(doc.designer.detecting.current).toBeNull();\n    firstBtn.hover();\n    expect(doc.designer.detecting.current).toBe(firstBtn);\n  });\n\n  it('getRect', () => {\n    const root = doc.rootNode!;\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    expect(root.getRect()).toBeNull();\n    expect(firstBtn.getRect()).toBeNull();\n\n    doc.project.mountSimulator({\n      computeRect: () => ({ x: 2, y: 2 }),\n      viewport: {\n        contentBounds: { x: 1, y: 1 },\n      },\n    });\n\n    expect(root.getRect()).toEqual({ x: 1, y: 1 });\n    expect(firstBtn.getRect()).toEqual({ x: 2, y: 2 });\n  });\n\n  it('isRootNode / isRoot / isNode', () => {\n    expect(isRootNode(doc.rootNode)).toBeTruthy();\n    expect(isNode(doc.rootNode)).toBeTruthy();\n  });\n\n  it('contains / comparePosition', () => {\n    const page = doc.getNode('page')!;\n    const content = doc.getNode('node_k1ow3cbb')!;\n    const firstBtn = doc.getNode('node_k1ow3cbn')!;\n    const secondBtn = doc.getNode('node_k1ow3cbp')!;\n    const firstCard = doc.getNode('node_k1ow3cbj')!;\n    expect(contains(firstBtn, firstBtn)).toBeTruthy();\n    expect(contains(firstBtn, secondBtn)).toBeFalsy();\n    expect(contains(firstBtn, page)).toBeFalsy();\n    expect(contains(firstBtn, content)).toBeFalsy();\n    expect(contains(firstCard, firstBtn)).toBeFalsy();\n\n    expect(comparePosition(firstBtn, secondBtn)).toBe(PositionNO.BeforeOrAfter);\n    expect(firstBtn.comparePosition(firstBtn)).toBe(PositionNO.TheSame);\n    expect(comparePosition(firstBtn, firstBtn)).toBe(PositionNO.TheSame);\n    expect(comparePosition(firstBtn, firstBtn.parent)).toBe(PositionNO.ContainedBy);\n    expect(comparePosition(firstBtn.parent, firstBtn)).toBe(PositionNO.Contains);\n    expect(comparePosition(firstCard, firstBtn)).toBe(PositionNO.BeforeOrAfter);\n    expect(comparePosition(firstBtn, firstCard)).toBe(PositionNO.BeforeOrAfter);\n  });\n\n  it('getZLevelTop', () => { });\n  it('propsData', () => {\n    expect(new Node(doc, { componentName: 'Leaf' }).propsData).toBeNull();\n    expect(new Node(doc, { componentName: 'Fragment' }).propsData).toBeNull();\n  });\n\n  describe('deprecated methods', () => {\n    it('setStatus / getStatus', () => {\n      const root = doc.rootNode!;\n      root.setStatus('xxx', true);\n\n      root.setStatus('locking', true);\n      root.setStatus('pseudo', true);\n      root.setStatus('inPlaceEditing', true);\n\n      expect(root.getStatus('locking')).toBeTruthy();\n      expect(root.getStatus('pseudo')).toBeTruthy();\n      expect(root.getStatus('inPlaceEditing')).toBeTruthy();\n      expect(root.getStatus()).toEqual({\n        locking: true,\n        pseudo: true,\n        inPlaceEditing: true,\n      });\n    });\n\n    it('getPage', () => {\n      expect(doc.rootNode?.getPage()).toBe(doc);\n    });\n\n    it('getDOMNode', () => {\n      const root = doc.rootNode!;\n      const firstBtn = doc.getNode('node_k1ow3cbn')!;\n\n      doc.project.mountSimulator({\n        findDOMNodes: () => [{ x: 1, y: 1 }],\n        getComponentInstances: (node) => {\n          if (node.componentName === 'Page') {\n            return [];\n          }\n          return [{}];\n        },\n      });\n\n      expect(root.getDOMNode()).toBeUndefined();\n      expect(firstBtn.getDOMNode()).toEqual({ x: 1, y: 1 });\n    });\n\n    it('registerAddon / getAddonData', () => {\n      const page = doc.getNode('page')!;\n      page.registerAddon('a', () => 'prop a');\n      expect(page.getAddonData('a')).toBe('prop a');\n      expect(page.getAddonData('b')).toBeUndefined();\n\n      expect(page.export().a).toBe('prop a');\n    });\n\n    it('getPrototype / setPrototype', () => {\n      const page = doc.getNode('page')!;\n      page.setPrototype({ a: 1 });\n      expect(page.getPrototype()).toEqual({ a: 1 });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/props/__snapshots__/value-to-source.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`valueToSource 1`] = `\"1\"`;\n\nexports[`valueToSource 2`] = `\"true\"`;\n\nexports[`valueToSource 3`] = `\"[]\"`;\n\nexports[`valueToSource 4`] = `\n\"[{\n  \\\\\"a\\\\\": 1\n}]\"\n`;\n\nexports[`valueToSource 5`] = `\n\"{\n  \\\\\"a\\\\\": 1\n}\"\n`;\n\nexports[`valueToSource 6`] = `\"null\"`;\n\nexports[`valueToSource 7`] = `\"() => {}\"`;\n\nexports[`valueToSource 8`] = `\"new Map()\"`;\n\nexports[`valueToSource 9`] = `\"new Set()\"`;\n\nexports[`valueToSource 10`] = `\"/haha/\"`;\n\nexports[`valueToSource 11`] = `\"\\\\\"hahah\\\\\"\"`;\n\nexports[`valueToSource 12`] = `\"Symbol(\\\\\"haha\\\\\")\"`;\n\nexports[`valueToSource 13`] = `\"undefined\"`;\n\nexports[`valueToSource 14`] = `\"new Date(\\\\\"2020-12-11T10:03:18.520Z\\\\\")\"`;\n"
  },
  {
    "path": "packages/designer/tests/document/node/props/prop.test.ts",
    "content": "import '../../../fixtures/window';\nimport { Editor, engineConfig } from '@alilc/lowcode-editor-core';\nimport { Designer } from '../../../../src/designer/designer';\nimport { DocumentModel } from '../../../../src/document/document-model';\nimport { Prop, isProp, isValidArrayIndex } from '../../../../src/document/node/props/prop';\nimport { GlobalEvent, IPublicEnumTransformStage } from '@alilc/lowcode-types';\nimport { shellModelFactory } from '../../../../../engine/src/modules/shell-model-factory';\n\nconst slotNodeImportMockFn = jest.fn();\nconst slotNodeRemoveMockFn = jest.fn();\nconst mockOwner = {\n  componentName: 'Div',\n  addSlot() {},\n  document: {\n    createNode(schema) {\n      return {\n        ...schema,\n        addSlot() {},\n        internalSetSlotFor() {},\n        import: slotNodeImportMockFn,\n        export() {\n          return schema;\n        },\n        remove: slotNodeRemoveMockFn,\n      };\n    },\n    designer: {\n      editor: {\n        eventBus: {\n          emit: jest.fn(),\n        },\n      },\n    },\n  },\n  isInited: true,\n  emitPropChange: jest.fn(),\n  delete() {},\n};\n\nconst mockPropsInst = {\n  owner: mockOwner,\n  delete() {},\n};\n\nmockPropsInst.props = mockPropsInst;\n\ndescribe('Prop 类测试', () => {\n  describe('基础类型', () => {\n    let boolProp: Prop;\n    let strProp: Prop;\n    let numProp: Prop;\n    let nullProp: Prop;\n    let expProp: Prop;\n    let slotProp: Prop;\n    beforeEach(() => {\n      boolProp = new Prop(mockPropsInst, true, 'boolProp');\n      strProp = new Prop(mockPropsInst, 'haha', 'strProp');\n      numProp = new Prop(mockPropsInst, 1, 'numProp');\n      nullProp = new Prop(mockPropsInst, null, 'nullProp');\n      expProp = new Prop(mockPropsInst, { type: 'JSExpression', value: 'state.haha' }, 'expProp');\n      slotProp = new Prop(\n        mockPropsInst,\n        {\n          type: 'JSSlot',\n          title: '测试 slot',\n          name: 'testSlot',\n          params: { a: 1 },\n          value: [{ componentName: 'Button' }],\n        },\n        'slotProp',\n      );\n      slotNodeImportMockFn.mockClear();\n      slotNodeRemoveMockFn.mockClear();\n    });\n    afterEach(() => {\n      boolProp.purge();\n      strProp.purge();\n      numProp.purge();\n      nullProp.purge();\n      expProp.purge();\n      slotProp.purge();\n    });\n\n    it('consturctor / getProps / getNode', () => {\n      expect(boolProp.parent).toBe(mockPropsInst);\n      expect(boolProp.getProps()).toBe(mockPropsInst);\n      expect(boolProp.getNode()).toBe(mockOwner);\n    });\n\n    it('misc', () => {\n      expect(boolProp.get('x', false)).toBeNull();\n      expect(boolProp.maps).toBeNull();\n      expect(boolProp.add()).toBeNull();\n\n      strProp.unset();\n      strProp.add(2, true);\n      strProp.set(0);\n\n      expect(numProp.set()).toBeNull();\n      expect(numProp.has()).toBeFalsy();\n      expect(numProp.path).toEqual(['numProp']);\n    });\n\n    it('getValue / getAsString / setValue', () => {\n      expect(strProp.getValue()).toBe('haha');\n      strProp.setValue('heihei');\n      strProp.setValue('heihei');\n      expect(strProp.getValue()).toBe('heihei');\n      expect(strProp.getAsString()).toBe('heihei');\n\n      strProp.unset();\n      expect(strProp.getValue()).toBeUndefined();\n    });\n\n    it('code', () => {\n      expect(expProp.code).toBe('state.haha');\n      expect(boolProp.code).toBe('true');\n      expect(strProp.code).toBe('\"haha\"');\n\n      expProp.code = 'state.heihei';\n      expect(expProp.code).toBe('state.heihei');\n      expect(expProp.getValue()).toEqual({\n        type: 'JSExpression',\n        value: 'state.heihei',\n      });\n\n      boolProp.code = 'false';\n      expect(boolProp.code).toBe('false');\n      expect(boolProp.getValue()).toBe(false);\n\n      strProp.code = '\"heihei\"';\n      expect(strProp.code).toBe('\"heihei\"');\n      expect(strProp.getValue()).toBe('heihei');\n\n      // TODO: 不确定为什么会有这个分支\n      strProp.code = 'state.a';\n      expect(strProp.code).toBe('state.a');\n      expect(strProp.getValue()).toEqual({\n        type: 'JSExpression',\n        value: 'state.a',\n        mock: 'heihei',\n      });\n    });\n\n    it('export', () => {\n      expect(boolProp.export(IPublicEnumTransformStage.Save)).toBe(true);\n      expect(strProp.export(IPublicEnumTransformStage.Save)).toBe('haha');\n      expect(numProp.export(IPublicEnumTransformStage.Save)).toBe(1);\n      expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(null);\n      expect(nullProp.export(IPublicEnumTransformStage.Serilize)).toBe(null);\n      expect(expProp.export(IPublicEnumTransformStage.Save)).toEqual({\n        type: 'JSExpression',\n        value: 'state.haha',\n      });\n\n      strProp.unset();\n      expect(strProp.getValue()).toBeUndefined();\n      expect(strProp.isUnset()).toBeTruthy();\n      expect(strProp.export(IPublicEnumTransformStage.Save)).toBeUndefined();\n\n      expect(\n        new Prop(mockPropsInst, false, '___condition___').export(IPublicEnumTransformStage.Render),\n      ).toBeTruthy();\n      engineConfig.set('enableCondition', true);\n      expect(\n        new Prop(mockPropsInst, false, '___condition___').export(IPublicEnumTransformStage.Render),\n      ).toBeFalsy();\n      expect(slotProp.export(IPublicEnumTransformStage.Render)).toEqual({\n        type: 'JSSlot',\n        params: { a: 1 },\n        value: {\n          componentName: 'Slot',\n          title: '测试 slot',\n          name: 'testSlot',\n          params: { a: 1 },\n          children: [{ componentName: 'Button' }],\n        },\n      });\n      expect(slotProp.export(IPublicEnumTransformStage.Save)).toEqual({\n        type: 'JSSlot',\n        params: { a: 1 },\n        value: [{ componentName: 'Button' }],\n        title: '测试 slot',\n        name: 'testSlot',\n      });\n    });\n\n    it('compare', () => {\n      const newProp = new Prop(mockPropsInst, 'haha');\n      const newProp2 = new Prop(mockPropsInst, { a: 1 });\n      expect(strProp.compare(newProp)).toBe(0);\n      expect(strProp.compare(expProp)).toBe(2);\n\n      newProp.unset();\n      expect(strProp.compare(newProp)).toBe(2);\n      strProp.unset();\n      expect(strProp.compare(newProp)).toBe(0);\n      expect(strProp.compare(newProp2)).toBe(2);\n    });\n\n    it('isVirtual', () => {\n      expect(new Prop(mockPropsInst, 111, '!virtualProp')).toBeTruthy();\n    });\n\n    it('purge', () => {\n      boolProp.purge();\n      expect(boolProp.purged).toBeTruthy();\n      boolProp.purge();\n    });\n\n    it('slot', () => {\n      // 更新 slot\n      slotProp.setValue({\n        type: 'JSSlot',\n        value: [\n          {\n            componentName: 'Form',\n          },\n        ],\n      });\n      expect(slotNodeImportMockFn).toBeCalled();\n\n      // 节点类型转换\n      slotProp.setValue(true);\n      expect(slotNodeRemoveMockFn).toBeCalled();\n    });\n\n    it('迭代器 / map / forEach', () => {\n      const mockFn = jest.fn();\n      for (const item of strProp) {\n        mockFn();\n      }\n      expect(mockFn).not.toHaveBeenCalled();\n      mockFn.mockClear();\n\n      strProp.forEach((item) => {\n        mockFn();\n      });\n      expect(mockFn).not.toHaveBeenCalled();\n      mockFn.mockClear();\n\n      strProp.map((item) => {\n        return mockFn();\n      });\n      expect(mockFn).not.toHaveBeenCalled();\n      mockFn.mockClear();\n    });\n  });\n\n  describe('复杂类型', () => {\n    describe('items(map 类型)', () => {\n      let prop: Prop;\n      beforeEach(() => {\n        prop = new Prop(mockPropsInst, {\n          a: 1,\n          b: 'str',\n          c: true,\n          d: {\n            type: 'JSExpression',\n            value: 'state.a',\n          },\n          emptyArr: [],\n          emptyObj: {},\n          z: {\n            z1: 1,\n            z2: 'str',\n          },\n        });\n      });\n      afterEach(() => {\n        prop.purge();\n      });\n\n      it('items / get', async () => {\n        expect(prop.size).toBe(7);\n\n        expect(prop.get('a').getValue()).toBe(1);\n        expect(prop.get('b').getValue()).toBe('str');\n        expect(prop.get('c').getValue()).toBe(true);\n        expect(prop.get('d').getValue()).toEqual({ type: 'JSExpression', value: 'state.a' });\n        expect(prop.get('z').getValue()).toEqual({\n          z1: 1,\n          z2: 'str',\n        });\n\n        expect(prop.getPropValue('a')).toBe(1);\n        prop.setPropValue('a', 2);\n        expect(prop.getPropValue('a')).toBe(2);\n        prop.clearPropValue('a');\n        expect(prop.get('a')?.isUnset()).toBeTruthy();\n\n        expect(prop.get('z.z1')?.getValue()).toBe(1);\n        expect(prop.get('z.z2')?.getValue()).toBe('str');\n\n        const newlyCreatedProp = prop.get('l', true);\n        const newlyCreatedNestedProp = prop.get('m.m1', true);\n        newlyCreatedProp.setValue('newlyCreatedProp');\n        newlyCreatedNestedProp?.setValue('newlyCreatedNestedProp');\n\n        expect(prop.get('l').getValue()).toBe('newlyCreatedProp');\n        expect(prop.get('m.m1').getValue()).toBe('newlyCreatedNestedProp');\n\n        const newlyCreatedNestedProp2 = prop.get('m.m2', true);\n        // .m2 的值为 undefined，导出时将会被移除\n        expect(prop.get('m').getValue()).toEqual({ m1: 'newlyCreatedNestedProp' });\n\n        // 对于空值的 list / map 类型，_items 应该为 null\n        expect(prop.get('emptyArr')._items).toBeNull();\n        expect(prop.get('emptyObj')._items).toBeNull();\n      });\n\n      it('export', () => {\n        expect(prop.export()).toEqual({\n          a: 1,\n          b: 'str',\n          c: true,\n          d: {\n            type: 'JSExpression',\n            value: 'state.a',\n          },\n          emptyArr: [],\n          emptyObj: {},\n          z: {\n            z1: 1,\n            z2: 'str',\n          },\n        });\n      });\n\n      it('compare', () => {\n        const prop1 = new Prop(mockPropsInst, { a: 1 });\n        const prop2 = new Prop(mockPropsInst, { b: 1 });\n        expect(prop1.compare(prop2)).toBe(1);\n      });\n\n      it('has / add / delete / deleteKey / remove', () => {\n        expect(prop.has('a')).toBeTruthy();\n        expect(prop.has('b')).toBeTruthy();\n        expect(prop.has('c')).toBeTruthy();\n        expect(prop.has('d')).toBeTruthy();\n        expect(prop.has('z')).toBeTruthy();\n        expect(prop.has('y')).toBeFalsy();\n\n        // 触发一下内部 maps 构造\n        prop.items;\n        expect(prop.has('z')).toBeTruthy();\n\n        expect(prop.add(1)).toBeNull();\n\n        prop.deleteKey('c');\n        expect(prop.get('c', false)).toBeNull();\n        prop.delete(prop.get('b'));\n        expect(prop.get('b', false)).toBeNull();\n\n        prop.get('d')?.remove();\n        expect(prop.get('d', false)).toBeNull();\n      });\n\n      it('set', () => {\n        prop.set('e', 1);\n        expect(prop.get('e', false)?.getValue()).toBe(1);\n        prop.set('a', 5);\n        expect(prop.get('a', false)?.getValue()).toBe(5);\n      });\n\n      it('迭代器 / map / forEach', () => {\n        const mockFn = jest.fn();\n        for (const item of prop) {\n          mockFn();\n        }\n        expect(mockFn).toHaveBeenCalledTimes(7);\n        mockFn.mockClear();\n\n        prop.forEach((item) => {\n          mockFn();\n        });\n        expect(mockFn).toHaveBeenCalledTimes(7);\n        mockFn.mockClear();\n\n        prop.map((item) => {\n          return mockFn();\n        });\n        expect(mockFn).toHaveBeenCalledTimes(7);\n        mockFn.mockClear();\n      });\n\n      it('dispose', () => {\n        prop.items;\n        prop.dispose();\n\n        expect(prop._items).toBeNull();\n      });\n    });\n\n    describe('items(list 类型)', () => {\n      let prop: Prop;\n      beforeEach(() => {\n        prop = new Prop(mockPropsInst, [1, true, 'haha']);\n      });\n      afterEach(() => {\n        prop.purge();\n      });\n\n      it('items / get', () => {\n        expect(prop.size).toBe(3);\n\n        expect(prop.get(0).getValue()).toBe(1);\n        expect(prop.get(1).getValue()).toBe(true);\n        expect(prop.get(2).getValue()).toBe('haha');\n\n        expect(prop.getAsString()).toBe('');\n\n        prop.unset();\n        prop.set(0, true);\n        expect(prop.set('x', 'invalid')).toBeNull();\n        expect(prop.get(0).getValue()).toBeTruthy();\n\n        // map / list 级联测试\n        prop.get('loopArgs.0', true).setValue('newItem');;\n        expect(prop.get('loopArgs.0').getValue()).toBe('newItem');\n      });\n\n      it('export', () => {\n        expect(prop.export()).toEqual([1, true, 'haha']);\n        // 触发构造\n        prop.items;\n        expect(prop.export()).toEqual([1, true, 'haha']);\n      });\n\n      it('compare', () => {\n        const prop1 = new Prop(mockPropsInst, [1]);\n        const prop2 = new Prop(mockPropsInst, [2]);\n        const prop3 = new Prop(mockPropsInst, [1, 2]);\n        expect(prop1.compare(prop2)).toBe(1);\n        expect(prop1.compare(prop3)).toBe(2);\n      });\n\n      it('set', () => {\n        prop.set(0, 1);\n        expect(prop.get(0, false)?.getValue()).toBe(1);\n        // illegal\n        // expect(prop.set(5, 1)).toBeNull();\n      });\n\n      it('should return undefined when all items are undefined', () => {\n        prop = new Prop(mockPropsInst, [undefined, undefined], '___loopArgs___');\n        expect(prop.getValue()).toEqual([undefined, undefined]);\n      });\n\n      it('迭代器 / map / forEach', () => {\n        const listProp = new Prop(mockPropsInst, [1, 2]);\n        const mockFn = jest.fn();\n        for (const item of listProp) {\n          mockFn();\n        }\n        expect(mockFn).toHaveBeenCalledTimes(2);\n        mockFn.mockClear();\n\n        listProp.forEach((item) => {\n          mockFn();\n        });\n        expect(mockFn).toHaveBeenCalledTimes(2);\n        mockFn.mockClear();\n\n        listProp.map((item) => {\n          return mockFn();\n        });\n        expect(mockFn).toHaveBeenCalledTimes(2);\n        mockFn.mockClear();\n      });\n    });\n  });\n\n  describe('slotNode / setAsSlot', () => {\n    const editor = new Editor();\n    const designer = new Designer({ editor, shellModelFactory });\n    const doc = new DocumentModel(designer.project, {\n      componentName: 'Page',\n      children: [\n        {\n          id: 'div',\n          componentName: 'Div',\n        },\n      ],\n    });\n    const div = doc.getNode('div');\n\n    const slotProp = new Prop(div?.getProps(), {\n      type: 'JSSlot',\n      value: [\n        {\n          componentName: 'Button',\n        },\n      ],\n    });\n\n    expect(slotProp.slotNode?.componentName).toBe('Slot');\n\n    // TODO: id 总是变，不好断言\n    expect(slotProp.code.includes('Button')).toBeTruthy();\n\n    slotProp.export();\n\n    expect(slotProp.export().value[0].componentName).toBe('Button');\n    expect(slotProp.export(IPublicEnumTransformStage.Serilize).value[0].componentName).toBe('Button');\n\n    slotProp.purge();\n    expect(slotProp.purged).toBeTruthy();\n    slotProp.dispose();\n  });\n\n  describe('slotNode-value / setAsSlot', () => {\n    const editor = new Editor();\n    const designer = new Designer({ editor, shellModelFactory });\n    const doc = new DocumentModel(designer.project, {\n      componentName: 'Page',\n      children: [\n        {\n          id: 'div',\n          componentName: 'Div',\n        },\n      ],\n    });\n    const div = doc.getNode('div');\n\n    const slotProp = new Prop(div?.getProps(), {\n      type: 'JSSlot',\n      value: {\n        componentName: 'Slot',\n        id: 'node_oclei5rv2e2',\n        props: {\n          slotName: \"content\",\n          slotTitle: \"主内容\"\n        },\n        children: [\n          {\n            componentName: 'Button',\n          }\n        ]\n      },\n    });\n\n    expect(slotProp.slotNode?.componentName).toBe('Slot');\n\n    expect(slotProp.slotNode?.title).toBe('主内容');\n    expect(slotProp.slotNode?.getExtraProp('name')?.getValue()).toBe('content');\n    expect(slotProp.slotNode?.export()?.id).toBe('node_oclei5rv2e2');\n\n    slotProp.export();\n\n    // Save\n    expect(slotProp.export()?.value[0].componentName).toBe('Button');\n    expect(slotProp.export()?.title).toBe('主内容');\n    expect(slotProp.export()?.name).toBe('content');\n\n    // Render\n    expect(slotProp.export(IPublicEnumTransformStage.Render)?.value.children[0].componentName).toBe('Button');\n    expect(slotProp.export(IPublicEnumTransformStage.Render)?.value.componentName).toBe('Slot');\n\n    slotProp.purge();\n    expect(slotProp.purged).toBeTruthy();\n    slotProp.dispose();\n  });\n});\n\ndescribe('其他导出函数', () => {\n  it('isProp', () => {\n    expect(isProp({ isProp: true })).toBeTruthy();\n  });\n\n  it('isValidArrayIndex', () => {\n    expect(isValidArrayIndex('1')).toBeTruthy();\n    expect(isValidArrayIndex('1', 2)).toBeTruthy();\n    expect(isValidArrayIndex('2', 1)).toBeFalsy();\n  });\n});\n\ndescribe('setValue with event', () => {\n  let propInstance;\n  let mockEmitChange;\n  let mockEventBusEmit;\n  let mockEmitPropChange;\n\n  beforeEach(() => {\n    // Initialize the instance of your class\n    propInstance = new Prop(mockPropsInst, true, 'stringProp');;\n\n    // Mock necessary methods and properties\n    mockEmitChange = jest.spyOn(propInstance, 'emitChange');\n    propInstance.owner = {\n      document: {\n        designer: {\n          editor: {\n            eventBus: {\n              emit: jest.fn(),\n            },\n          },\n        },\n      },\n      emitPropChange: jest.fn(),\n      delete() {},\n    };\n    mockEventBusEmit = jest.spyOn(propInstance.owner.document.designer.editor.eventBus, 'emit');\n    mockEmitPropChange = jest.spyOn(propInstance.owner, 'emitPropChange');\n  });\n\n  afterEach(() => {\n    jest.restoreAllMocks();\n  });\n\n  it('should correctly handle string values and emit changes', () => {\n    const oldValue = propInstance._value;\n    const newValue = 'new string value';\n\n    propInstance.setValue(newValue);\n\n    const expectedPartialPropsInfo = expect.objectContaining({\n      key: propInstance.key,\n      newValue, // You can specifically test only certain keys\n      oldValue,\n    });\n\n    expect(propInstance.getValue()).toBe(newValue);\n    expect(propInstance.type).toBe('literal');\n    expect(mockEmitChange).toHaveBeenCalledWith({ oldValue });\n    expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo);\n    expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo);\n  });\n\n  it('should handle object values and set type to map', () => {\n    const oldValue = propInstance._value;\n    const newValue = 234;\n\n    const expectedPartialPropsInfo = expect.objectContaining({\n      key: propInstance.key,\n      newValue, // You can specifically test only certain keys\n      oldValue,\n    });\n\n    propInstance.setValue(newValue);\n\n    expect(propInstance.getValue()).toEqual(newValue);\n    expect(propInstance.type).toBe('literal');\n    expect(mockEmitChange).toHaveBeenCalledWith({ oldValue });\n    expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo);\n    expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo);\n  });\n\n  it('should has event when unset call', () => {\n    const oldValue = propInstance._value;\n\n    propInstance.unset();\n\n    const expectedPartialPropsInfo = expect.objectContaining({\n      key: propInstance.key,\n      newValue: undefined, // You can specifically test only certain keys\n      oldValue,\n    });\n\n    expect(propInstance.getValue()).toEqual(undefined);\n    expect(propInstance.type).toBe('unset');\n    expect(mockEmitChange).toHaveBeenCalledWith({\n      oldValue,\n      newValue: undefined,\n    });\n    expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo);\n    expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo);\n\n    propInstance.unset();\n    expect(mockEmitChange).toHaveBeenCalledTimes(1);\n  });\n\n  // remove\n  it('should has event when remove call', () => {\n    const oldValue = propInstance._value;\n\n    propInstance.remove();\n\n    const expectedPartialPropsInfo = expect.objectContaining({\n      key: propInstance.key,\n      newValue: undefined, // You can specifically test only certain keys\n      oldValue,\n    });\n\n    expect(propInstance.getValue()).toEqual(undefined);\n    // expect(propInstance.type).toBe('unset');\n    expect(mockEmitChange).toHaveBeenCalledWith({\n      oldValue,\n      newValue: undefined,\n    });\n    expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo);\n    expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo);\n\n    propInstance.remove();\n    expect(mockEmitChange).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/props/props.test.ts",
    "content": "// @ts-nocheck\nimport '../../../fixtures/window';\nimport { set, delayObxTick } from '../../../utils';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport {\n  Props,\n  getConvertedExtraKey,\n  getOriginalExtraKey,\n  Prop,\n  isProp,\n  isValidArrayIndex,\n} from '../../../../src/document/node/props/props';\nimport { Designer } from '../../../../src/designer/designer';\nimport { Project } from '../../../../src/project/project';\nimport { DocumentModel } from '../../../../src/document/document-model';\n\nimport { TransformStage } from '@alilc/lowcode-types';\n\nconst mockOwner = { componentName: 'Page' };\n\ndescribe('Props 类测试', () => {\n  let props: Props;\n  beforeEach(() => {\n    props = new Props(\n      mockOwner,\n      {\n        a: 1,\n        b: 'str',\n        c: true,\n        d: {\n          type: 'JSExpression',\n          value: 'state.a',\n        },\n        z: {\n          z1: 1,\n          z2: 'str',\n        },\n      },\n      { condition: true },\n    );\n  });\n  afterEach(() => {\n    props.purge();\n  });\n\n  it('getNode', () => {\n    expect(props.getNode()).toBe(mockOwner);\n  });\n\n  it('items / get', async () => {\n    expect(props.size).toBe(6);\n\n    expect(props.get('a').getValue()).toBe(1);\n    expect(props.get('b').getValue()).toBe('str');\n    expect(props.get('c').getValue()).toBe(true);\n    expect(props.get('d').getValue()).toEqual({ type: 'JSExpression', value: 'state.a' });\n    expect(props.get('z').getValue()).toEqual({\n      z1: 1,\n      z2: 'str',\n    });\n\n    expect(props.getPropValue('a')).toBe(1);\n    props.setPropValue('a', 2);\n    expect(props.getPropValue('a')).toBe(2);\n    // props.clearPropValue('a');\n    // expect(props.get('a')?.isUnset()).toBeTruthy();\n\n    expect(props.get('z.z1')?.getValue()).toBe(1);\n    expect(props.get('z.z2')?.getValue()).toBe('str');\n\n    const notCreatedProp = props.get('i');\n    expect(notCreatedProp).toBeNull();\n    const newlyCreatedProp = props.get('l', true);\n    const newlyCreatedNestedProp = props.get('m.m1', true);\n    newlyCreatedProp.setValue('newlyCreatedProp');\n    newlyCreatedNestedProp?.setValue('newlyCreatedNestedProp');\n\n    expect(props.get('l').getValue()).toBe('newlyCreatedProp');\n    expect(props.get('m.m1').getValue()).toBe('newlyCreatedNestedProp');\n\n    // map / list 级联测试\n    props.get('loopArgs.0', true).setValue('newItem');\n    expect(props.get('loopArgs.0').getValue()).toBe('newItem');\n  });\n\n  it('export', () => {\n    expect(props.export()).toEqual({\n      props: {\n        a: 1,\n        b: 'str',\n        c: true,\n        d: {\n          type: 'JSExpression',\n          value: 'state.a',\n        },\n        z: {\n          z1: 1,\n          z2: 'str',\n        },\n      },\n      extras: {\n        condition: true,\n      },\n    });\n\n    expect(props.toData()).toEqual({\n      a: 1,\n      b: 'str',\n      c: true,\n      d: {\n        type: 'JSExpression',\n        value: 'state.a',\n      },\n      z: {\n        z1: 1,\n        z2: 'str',\n      },\n    });\n\n    props.get('a')?.unset();\n    expect(props.toData()).toEqual({\n      a: undefined,\n      b: 'str',\n      c: true,\n      d: {\n        type: 'JSExpression',\n        value: 'state.a',\n      },\n      z: {\n        z1: 1,\n        z2: 'str',\n      },\n    });\n  });\n\n  it('export - remove undefined items', () => {\n    props.import(\n      {\n        a: 1,\n      },\n      { loop: false },\n    );\n    props.setPropValue('x', undefined);\n    expect(props.export()).toEqual({\n      props: {\n        a: 1,\n      },\n      extras: {\n        loop: false,\n      },\n    });\n\n    props.setPropValue('x', 2);\n    expect(props.export()).toEqual({\n      props: {\n        a: 1,\n        x: 2,\n      },\n      extras: {\n        loop: false,\n      },\n    });\n\n    props.setPropValue('y.z', undefined);\n    expect(props.export()).toEqual({\n      props: {\n        a: 1,\n        x: 2,\n      },\n      extras: {\n        loop: false,\n      },\n    });\n\n    props.setPropValue('y.z', 2);\n    expect(props.export()).toEqual({\n      props: {\n        a: 1,\n        x: 2,\n        y: { z: 2 },\n      },\n      extras: {\n        loop: false,\n      },\n    });\n  });\n\n  it('import', () => {\n    props.import(\n      {\n        x: 1,\n        y: true,\n      },\n      { loop: false },\n    );\n    expect(props.export()).toEqual({\n      props: {\n        x: 1,\n        y: true,\n      },\n      extras: {\n        loop: false,\n      },\n    });\n\n    props.import();\n  });\n\n  it('merge', async () => {\n    props.merge({ x: 1 });\n\n    await delayObxTick();\n\n    expect(props.get('x')?.getValue()).toBe(1);\n  });\n\n  it('has / add / delete / deleteKey / remove', () => {\n    expect(props.has('a')).toBeTruthy();\n    expect(props.has('b')).toBeTruthy();\n    expect(props.has('c')).toBeTruthy();\n    expect(props.has('d')).toBeTruthy();\n    expect(props.has('z')).toBeTruthy();\n    expect(props.has('y')).toBeFalsy();\n\n    props.add(1, 'newAdded');\n    expect(props.has('newAdded')).toBeTruthy();\n\n    props.deleteKey('c');\n    expect(props.get('c', false)).toBeNull();\n    props.delete(props.get('b'));\n    expect(props.get('b', false)).toBeNull();\n\n    props.get('d')?.remove();\n    expect(props.get('d', false)).toBeNull();\n  });\n\n  it('迭代器 / map / forEach', () => {\n    const mockFn = jest.fn();\n    for (const item of props) {\n      mockFn();\n    }\n    expect(mockFn).toHaveBeenCalledTimes(6);\n    mockFn.mockClear();\n\n    props.forEach((item) => {\n      mockFn();\n    });\n    expect(mockFn).toHaveBeenCalledTimes(6);\n    mockFn.mockClear();\n\n    props.map((item) => {\n      return mockFn();\n    });\n    expect(mockFn).toHaveBeenCalledTimes(6);\n    mockFn.mockClear();\n\n    props.filter((item) => {\n      return mockFn();\n    });\n    expect(mockFn).toHaveBeenCalledTimes(6);\n    mockFn.mockClear();\n  });\n\n  it('purge', () => {\n    props.purge();\n\n    expect(props.purged).toBeTruthy();\n  });\n\n  it('empty items', () => {\n    expect(new Props(mockOwner).export()).toEqual({});\n  });\n\n  describe('list 类型', () => {\n    let props: Props;\n    beforeEach(() => {\n      props = new Props(mockOwner, [1, true, 'haha'], { condition: true });\n    });\n    it('constructor', () => {\n      props.purge();\n    });\n\n    it('export', () => {\n      expect(props.export().extras).toEqual({\n        condition: true,\n      });\n    });\n\n    it('import', () => {\n      props.import([1], { loop: true });\n      expect(props.export().extras).toEqual({\n        loop: true,\n      });\n\n      props.items[0]?.unset();\n      props.export();\n    });\n  });\n});\n\ndescribe('其他函数', () => {\n  it('getConvertedExtraKey', () => {\n    expect(getConvertedExtraKey()).toBe('');\n    expect(getConvertedExtraKey('a')).toBe('___a___');\n    expect(getConvertedExtraKey('a.b')).toBe('___a___.b');\n    expect(getConvertedExtraKey('a.0')).toBe('___a___.0');\n  });\n\n  it('getOriginalExtraKey', () => {\n    expect(getOriginalExtraKey('___a___')).toBe('a');\n    expect(getOriginalExtraKey('___a___.b')).toBe('a.b');\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/document/node/props/value-to-source.test.ts",
    "content": "// @ts-nocheck\nimport '../../../fixtures/silent-console';\nimport { getSource, valueToSource } from '../../../../src/document/node/props/value-to-source';\n\nit('valueToSource', () => {\n  expect(valueToSource(1)).toMatchSnapshot();\n  expect(valueToSource(true)).toMatchSnapshot();\n  expect(valueToSource([])).toMatchSnapshot();\n  expect(valueToSource([{ a: 1 }])).toMatchSnapshot();\n  expect(valueToSource({ a: 1 })).toMatchSnapshot();\n  expect(valueToSource(null)).toMatchSnapshot();\n  expect(valueToSource(() => {})).toMatchSnapshot();\n  expect(valueToSource(new Map())).toMatchSnapshot();\n  expect(valueToSource(new Set())).toMatchSnapshot();\n  expect(valueToSource(/haha/)).toMatchSnapshot();\n  expect(valueToSource('hahah')).toMatchSnapshot();\n  expect(valueToSource(Symbol('haha'))).toMatchSnapshot();\n  expect(valueToSource()).toMatchSnapshot();\n  expect(valueToSource(new Date(1607680998520))).toMatchSnapshot();\n});\n\nit('getSource', () => {\n  expect(getSource({ __source: { a: 1 } })).toEqual({ a: 1 });\n  expect(getSource()).toBe('');\n  const value = { abc: 1 };\n  getSource(value);\n  expect(value).toHaveProperty('__source');\n  expect(getSource(1)).toBe('1');\n});\n"
  },
  {
    "path": "packages/designer/tests/document/selection.test.ts",
    "content": "import set from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport '../fixtures/window';\nimport { Project } from '../../src/project/project';\nimport { Node } from '../../src/document/node/node';\nimport { Designer } from '../../src/designer/designer';\nimport formSchema from '../fixtures/schema/form';\nimport { getIdsFromSchema, getNodeFromSchemaById } from '../utils';\n\nconst mockCreateSettingEntry = jest.fn();\njest.mock('../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      return {\n        getComponentMeta() {\n          return {\n            getMetadata() {\n              return { configure: { advanced: null } };\n            },\n            get advanced() {\n              return {};\n            },\n          };\n        },\n        transformProps(props) { return props; },\n        createSettingEntry: mockCreateSettingEntry,\n        postEvent() {},\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({});\n});\n\ndescribe('选择区测试', () => {\n  it('常规方法', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap, selection } = currentDocument!;\n    const selectionChangeHandler = jest.fn();\n    selection.onSelectionChange(selectionChangeHandler);\n\n    selection.select('form');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selection.selected).toEqual(['form']);\n    selectionChangeHandler.mockClear();\n\n    selection.select('form');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(0);\n    expect(selection.selected).toEqual(['form']);\n\n    selection.select('node_k1ow3cbj');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['node_k1ow3cbj']);\n    expect(selection.selected).toEqual(['node_k1ow3cbj']);\n    selectionChangeHandler.mockClear();\n\n    selection.selectAll(['node_k1ow3cbj', 'form']);\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['node_k1ow3cbj', 'form']);\n    expect(selection.selected).toEqual(['node_k1ow3cbj', 'form']);\n    selectionChangeHandler.mockClear();\n\n    selection.remove('node_k1ow3cbj_fake');\n    selection.remove('node_k1ow3cbj');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);\n    expect(selection.selected).toEqual(['form']);\n    selectionChangeHandler.mockClear();\n\n    selection.clear();\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual([]);\n    expect(selection.selected).toEqual([]);\n    selectionChangeHandler.mockClear();\n\n    // 无选中时调用 clear，不再触发事件\n    selection.clear();\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(0);\n    expect(selection.selected).toEqual([]);\n    selectionChangeHandler.mockClear();\n  });\n\n  it('add 方法', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap, selection } = currentDocument!;\n    const selectionChangeHandler = jest.fn();\n    selection.onSelectionChange(selectionChangeHandler);\n\n    selection.add('form');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);\n    expect(selection.selected).toEqual(['form']);\n    selectionChangeHandler.mockClear();\n\n    // 再加一次相同的节点，不触发事件\n    selection.add('form');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(0);\n    expect(selection.selected).toEqual(['form']);\n    selectionChangeHandler.mockClear();\n\n    selection.add('form2');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form', 'form2']);\n    expect(selection.selected).toEqual(['form', 'form2']);\n    selectionChangeHandler.mockClear();\n  });\n\n  it('selectAll 包含不存在的 id', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap, selection } = currentDocument!;\n\n    selection.selectAll(['form', 'node_k1ow3cbj', 'form2']);\n\n    expect(selection.selected).toEqual(['form', 'node_k1ow3cbj']);\n  });\n\n  it('dispose 方法 - 选中的节点没有被删除的', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap, selection } = currentDocument!;\n\n    selection.selectAll(['form', 'node_k1ow3cbj']);\n\n    const selectionChangeHandler = jest.fn();\n    selection.onSelectionChange(selectionChangeHandler);\n    selection.dispose();\n\n    expect(selectionChangeHandler).not.toHaveBeenCalled();\n  });\n\n  it('containsNode 方法', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap, selection } = currentDocument!;\n    const selectionChangeHandler = jest.fn();\n    selection.onSelectionChange(selectionChangeHandler);\n\n    selection.select('form');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);\n    expect(selection.selected).toEqual(['form']);\n    expect(selection.has('form')).toBe(true);\n    expect(selection.containsNode(currentDocument?.getNode('form'))).toBe(true);\n    expect(selection.containsNode(currentDocument?.getNode('node_k1ow3cbj'))).toBe(true);\n    expect(selection.containsNode(currentDocument?.getNode('page'))).toBe(false);\n    expect(selection.getNodes()).toEqual([currentDocument?.getNode('form')]);\n    selectionChangeHandler.mockClear();\n\n    selection.add('node_k1ow3cbj');\n    expect(selection.selected).toEqual(['form', 'node_k1ow3cbj']);\n    expect(selection.getTopNodes()).toEqual([currentDocument?.getNode('form')]);\n    expect(selection.getTopNodes(true)).toEqual([currentDocument?.getNode('form')]);\n  });\n\n  it('containsNode 方法 - excludeRoot: true', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap, selection } = currentDocument!;\n    const selectionChangeHandler = jest.fn();\n    selection.onSelectionChange(selectionChangeHandler);\n\n    selection.select('page');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['page']);\n    expect(selection.selected).toEqual(['page']);\n    expect(selection.has('page')).toBe(true);\n    expect(selection.containsNode(currentDocument?.getNode('form'))).toBe(true);\n    expect(selection.containsNode(currentDocument?.getNode('form'), true)).toBe(false);\n    selectionChangeHandler.mockClear();\n  });\n\n  it('containsNode 方法 - excludeRoot: true', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    expect(project).toBeTruthy();\n    const { currentDocument } = project;\n    const { nodesMap, selection } = currentDocument!;\n    const selectionChangeHandler = jest.fn();\n    const dispose = selection.onSelectionChange(selectionChangeHandler);\n\n    selection.select('form');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(1);\n    expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form']);\n    selectionChangeHandler.mockClear();\n\n    // dispose 后，selected 会被赋值，但是变更事件不会被触发\n    dispose();\n    selection.select('page');\n    expect(selectionChangeHandler).toHaveBeenCalledTimes(0);\n    expect(selection.selected).toEqual(['page']);\n    selectionChangeHandler.mockClear();\n  });\n\n  it('getNodes', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    const { currentDocument } = project;\n    const { selection } = currentDocument!;\n\n    selection.selectAll(['form', 'node_k1ow3cbj', 'form2']);\n\n    // form2 is not a valid node\n    expect(selection.getNodes()).toHaveLength(2);\n  });\n\n  it('getTopNodes - BeforeOrAfter', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    const { currentDocument } = project;\n    const { selection } = currentDocument!;\n\n    selection.selectAll(['node_k1ow3cbj', 'node_k1ow3cbo']);\n\n    expect(selection.getTopNodes()).toHaveLength(2);\n  });\n  it('getTopNodes', () => {\n    const project = new Project(designer, {\n      componentsTree: [\n        formSchema,\n      ],\n    });\n    project.open();\n    const { currentDocument } = project;\n    const { selection } = currentDocument!;\n\n    selection.selectAll(['node_k1ow3cbj', 'node_k1ow3cbo', 'form', 'node_k1ow3cbl', 'form2']);\n\n    // form2 is not a valid node, and node_k1ow3cbj is a child node of form\n    expect(selection.getTopNodes()).toHaveLength(1);\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/abcgroup.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Abc.Group',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: { label: '容器' },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n    },\n    supports: {},\n    advanced: {\n      isTopFixed: true,\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/abcitem.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Abc.Item',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: { label: '容器' },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n    },\n    supports: {},\n    advanced: {\n      isTopFixed: true,\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/abcnode.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Abc.Node',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: { label: '容器' },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n    },\n    supports: {},\n    advanced: {\n      isTopFixed: true,\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/abcoption.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Abc.Option',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: { label: '容器' },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n    },\n    supports: {},\n    advanced: {\n      isTopFixed: true,\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/button.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Button',\n  npm: {\n    package: '@ali/vc-button',\n    componentName: 'Button',\n  },\n  title: '按钮',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'field',\n        name: 'non-exsiting',\n      },\n      {\n        type: 'field',\n        name: 'obj',\n        items: [\n          {\n            name: 'a',\n            title: 'a',\n            setter: () => 'StringSetter',\n          },\n          {\n            name: 'b',\n            title: 'b',\n            setter: 'NumberSetter',\n          },\n          {\n            name: 'c',\n            title: 'c',\n            setter: {\n              componentName: 'ColorSetter'\n            },\n          },\n        ],\n      },\n      () => 'haha', // IPublicTypeCustomView\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n      descriptor: 'xTitle'\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/dialog.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Dialog',\n  npm: {\n    package: '@ali/vc-dialog',\n    componentName: 'Dialog',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      isModal: true,\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n    advanced: {\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div10.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    component: {\n      nestingRule: {\n        parentWhitelist: (parent, my) => {\n          if (parent.componentName === 'Form' && my.componentName === 'Div') return true;\n          return false;\n        },\n        childWhitelist: (child, my) => {\n          if (child.componentName === 'Image' && my.componentName === 'Div') return true;\n          return false;\n        },\n      },\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div2.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: { label: '容器' },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n    },\n    supports: {},\n    advanced: {\n      isTopFixed: true,\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div3.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      }\n    },\n    supports: {},\n    advanced: {\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div4.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: [\n    {\n      type: 'field',\n      name: 'behavior',\n      title: '默认状态',\n      extraProps: {\n        display: 'inline',\n        defaultValue: 'NORMAL',\n      },\n      setter: {\n        componentName: 'MixedSetter',\n        props: {\n          setters: [\n            {\n              key: null,\n              ref: null,\n              props: {\n                options: [\n                  {\n                    title: '普通',\n                    value: 'NORMAL',\n                  },\n                  {\n                    title: '隐藏',\n                    value: 'HIDDEN',\n                  },\n                ],\n                loose: false,\n                cancelable: false,\n              },\n              _owner: null,\n            },\n            'VariableSetter',\n          ],\n        },\n      },\n    },\n    {\n      type: 'field',\n      name: '__style__',\n      title: {\n        label: '样式设置',\n        tip: '点击 ? 查看样式设置器用法指南',\n        docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n      },\n      extraProps: {\n        display: 'accordion',\n        defaultValue: {},\n      },\n      setter: {\n        key: null,\n        ref: null,\n        props: {\n          advanced: true,\n        },\n        _owner: null,\n      },\n    },\n    {\n      type: 'group',\n      name: 'groupkgzzeo41',\n      title: '高级',\n      extraProps: {\n        display: 'accordion',\n      },\n      items: [\n        {\n          type: 'field',\n          name: 'fieldId',\n          title: {\n            label: '唯一标识',\n          },\n          extraProps: {\n            display: 'block',\n          },\n          setter: {\n            key: null,\n            ref: null,\n            props: {\n              placeholder: '请输入唯一标识',\n              multiline: false,\n              rows: 10,\n              required: false,\n              pattern: null,\n              maxLength: null,\n            },\n            _owner: null,\n          },\n        },\n        {\n          type: 'field',\n          name: 'useFieldIdAsDomId',\n          title: {\n            label: '将唯一标识用作 DOM ID',\n          },\n          extraProps: {\n            display: 'block',\n            defaultValue: false,\n          },\n          setter: {\n            key: null,\n            ref: null,\n            props: {},\n            _owner: null,\n          },\n        },\n        {\n          type: 'field',\n          name: 'customClassName',\n          title: '自定义样式类',\n          extraProps: {\n            display: 'block',\n            defaultValue: '',\n          },\n          setter: {\n            componentName: 'MixedSetter',\n            props: {\n              setters: [\n                {\n                  key: null,\n                  ref: null,\n                  props: {\n                    placeholder: null,\n                    multiline: false,\n                    rows: 10,\n                    required: false,\n                    pattern: null,\n                    maxLength: null,\n                  },\n                  _owner: null,\n                },\n                'VariableSetter',\n              ],\n            },\n          },\n        },\n        {\n          type: 'field',\n          name: 'events',\n          title: {\n            label: '动作设置',\n            tip: '点击 ? 查看如何设置组件的事件响应动作',\n            docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n          },\n          extraProps: {\n            display: 'accordion',\n            defaultValue: {\n              ignored: true,\n            },\n          },\n          setter: {\n            key: null,\n            ref: null,\n            props: {\n              events: [\n                {\n                  name: 'onClick',\n                  title: '当点击时',\n                  initialValue:\n                    \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                },\n                {\n                  name: 'onMouseEnter',\n                  title: '当鼠标进入时',\n                  initialValue:\n                    \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                },\n                {\n                  name: 'onMouseLeave',\n                  title: '当鼠标离开时',\n                  initialValue:\n                    \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                },\n              ],\n            },\n            _owner: null,\n          },\n        },\n        {\n          type: 'field',\n          name: 'onClick',\n          extraProps: {\n            defaultValue: {\n              ignored: true,\n            },\n          },\n          setter: 'I18nSetter',\n        },\n        {\n          type: 'field',\n          name: 'onMouseEnter',\n          extraProps: {\n            defaultValue: {\n              ignored: true,\n            },\n          },\n          setter: 'I18nSetter',\n        },\n        {\n          type: 'field',\n          name: 'onMouseLeave',\n          extraProps: {\n            defaultValue: {\n              ignored: true,\n            },\n          },\n          setter: 'I18nSetter',\n        },\n      ],\n    },\n  ],\n  experimental: {\n    callbacks: {\n      onNodeAdd: (dragment, self) => { console.log(dragment); },\n      onNodeRemove: (dragment, self) => { console.log(dragment); }\n    },\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div5.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n      disableBehaviors: '*',\n    },\n    supports: {},\n    advanced: {\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div6.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n      disableBehaviors: '*',\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {\n      onNodeAdd: (dragment, self) => { console.log(dragment); },\n      onNodeRemove: (dragment, self) => { console.log(dragment); }\n    },\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div7.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    supports: {},\n    advanced: {\n      callbacks: {\n        onNodeAdd: (dragment, self) => { console.log(dragment); },\n        onNodeRemove: (dragment, self) => { console.log(dragment); }\n      },\n      initials: [\n        {\n          name: 'behavior',\n        },\n        {\n          name: '__style__',\n        },\n        {\n          name: 'fieldId',\n        },\n        {\n          name: 'useFieldIdAsDomId',\n        },\n        {\n          name: 'customClassName',\n        },\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      filters: [\n        {\n          name: 'events',\n        },\n        {\n          name: 'onClick',\n        },\n        {\n          name: 'onMouseEnter',\n        },\n        {\n          name: 'onMouseLeave',\n        },\n      ],\n      autoruns: [],\n    },\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div8.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  npm: {\n    package: '@ali/vc-div',\n    componentName: 'Div',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/div9.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Div',\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/form.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Form',\n  npm: {\n    package: '@ali/vc-form',\n  },\n  title: '表单',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        parentWhitelist: 'Div,Page',\n        // childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/other.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Other',\n  npm: {\n    package: '@ali/vc-other',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        parentWhitelist: 'Div',\n        childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/page.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Page',\n  npm: {\n    package: '@ali/vc-page',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/page2.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'Page',\n  npm: {\n    package: '@ali/vc-page',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/root-content.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'RootContent',\n  npm: {\n    package: '@ali/vc-page',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/root-footer.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'RootFooter',\n  npm: {\n    package: '@ali/vc-page',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/component-metadata/root-header.ts",
    "content": "import { IPublicTypeComponentMetadata } from \"@alilc/lowcode-types\";\nexport default {\n  componentName: 'RootHeader',\n  npm: {\n    package: '@ali/vc-page',\n  },\n  title: '容器',\n  docUrl: 'https://github.com/alibaba/lowcode-materials/tree/main/docs',\n  devMode: 'proCode',\n  tags: ['布局'],\n  configure: {\n    props: [\n      {\n        type: 'field',\n        name: 'behavior',\n        title: '默认状态',\n        extraProps: {\n          display: 'inline',\n          defaultValue: 'NORMAL',\n        },\n        setter: {\n          componentName: 'MixedSetter',\n          props: {\n            setters: [\n              {\n                key: null,\n                ref: null,\n                props: {\n                  options: [\n                    {\n                      title: '普通',\n                      value: 'NORMAL',\n                    },\n                    {\n                      title: '隐藏',\n                      value: 'HIDDEN',\n                    },\n                  ],\n                  loose: false,\n                  cancelable: false,\n                },\n                _owner: null,\n              },\n              'VariableSetter',\n            ],\n          },\n        },\n      },\n      {\n        type: 'field',\n        name: '__style__',\n        title: {\n          label: '样式设置',\n          tip: '点击 ? 查看样式设置器用法指南',\n          docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',\n        },\n        extraProps: {\n          display: 'accordion',\n          defaultValue: {},\n        },\n        setter: {\n          key: null,\n          ref: null,\n          props: {\n            advanced: true,\n          },\n          _owner: null,\n        },\n      },\n      {\n        type: 'group',\n        name: 'groupkgzzeo41',\n        title: '高级',\n        extraProps: {\n          display: 'accordion',\n        },\n        items: [\n          {\n            type: 'field',\n            name: 'fieldId',\n            title: {\n              label: '唯一标识',\n            },\n            extraProps: {\n              display: 'block',\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                placeholder: '请输入唯一标识',\n                multiline: false,\n                rows: 10,\n                required: false,\n                pattern: null,\n                maxLength: null,\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'useFieldIdAsDomId',\n            title: {\n              label: '将唯一标识用作 DOM ID',\n            },\n            extraProps: {\n              display: 'block',\n              defaultValue: false,\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {},\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'customClassName',\n            title: '自定义样式类',\n            extraProps: {\n              display: 'block',\n              defaultValue: '',\n            },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                setters: [\n                  {\n                    key: null,\n                    ref: null,\n                    props: {\n                      placeholder: null,\n                      multiline: false,\n                      rows: 10,\n                      required: false,\n                      pattern: null,\n                      maxLength: null,\n                    },\n                    _owner: null,\n                  },\n                  'VariableSetter',\n                ],\n              },\n            },\n          },\n          {\n            type: 'field',\n            name: 'events',\n            title: {\n              label: '动作设置',\n              tip: '点击 ? 查看如何设置组件的事件响应动作',\n              docUrl: 'https://lark.alipay.com/legao/legao/events-call',\n            },\n            extraProps: {\n              display: 'accordion',\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: {\n              key: null,\n              ref: null,\n              props: {\n                events: [\n                  {\n                    name: 'onClick',\n                    title: '当点击时',\n                    initialValue:\n                      \"/**\\n * 容器 当点击时\\n */\\nfunction onClick(event) {\\n  console.log('onClick', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseEnter',\n                    title: '当鼠标进入时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标进入时\\n */\\nfunction onMouseEnter(event) {\\n  console.log('onMouseEnter', event);\\n}\",\n                  },\n                  {\n                    name: 'onMouseLeave',\n                    title: '当鼠标离开时',\n                    initialValue:\n                      \"/**\\n * 容器 当鼠标离开时\\n */\\nfunction onMouseLeave(event) {\\n  console.log('onMouseLeave', event);\\n}\",\n                  },\n                ],\n              },\n              _owner: null,\n            },\n          },\n          {\n            type: 'field',\n            name: 'onClick',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseEnter',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n          {\n            type: 'field',\n            name: 'onMouseLeave',\n            extraProps: {\n              defaultValue: {\n                ignored: true,\n              },\n            },\n            setter: 'I18nSetter',\n          },\n        ],\n      },\n    ],\n    component: {\n      isContainer: true,\n      nestingRule: {\n        // parentWhitelist: 'Div',\n        // childWhitelist: 'Div',\n      },\n    },\n    supports: {},\n  },\n  experimental: {\n    callbacks: {},\n    initials: [\n      {\n        name: 'behavior',\n      },\n      {\n        name: '__style__',\n      },\n      {\n        name: 'fieldId',\n      },\n      {\n        name: 'useFieldIdAsDomId',\n      },\n      {\n        name: 'customClassName',\n      },\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    filters: [\n      {\n        name: 'events',\n      },\n      {\n        name: 'onClick',\n      },\n      {\n        name: 'onMouseEnter',\n      },\n      {\n        name: 'onMouseLeave',\n      },\n    ],\n    autoruns: [],\n  },\n} as IPublicTypeComponentMetadata;\n"
  },
  {
    "path": "packages/designer/tests/fixtures/disable-raf.ts",
    "content": "Object.defineProperty(window, 'requestAnimationFrame', {\n  value: null,\n});\n"
  },
  {
    "path": "packages/designer/tests/fixtures/schema/form-with-modal.ts",
    "content": "export default {\n  componentName: 'Page',\n  id: 'page',\n  title: \"hey, i' a page!\",\n  props: {\n    extensions: {\n      启用页头: true,\n    },\n    pageStyle: {\n      backgroundColor: '#f2f3f5',\n    },\n    containerStyle: {},\n    className: 'page_kgaqfbm4',\n    templateVersion: '1.0.0',\n  },\n  lifeCycles: {\n    constructor: {\n      type: 'js',\n      compiled:\n        \"function constructor() {\\nvar module = { exports: {} };\\nvar _this = this;\\nthis.__initMethods__(module.exports, module);\\nObject.keys(module.exports).forEach(function(item) {\\n  if(typeof module.exports[item] === 'function'){\\n    _this[item] = module.exports[item];\\n  }\\n});\\n\\n}\",\n      source:\n        \"function constructor() {\\nvar module = { exports: {} };\\nvar _this = this;\\nthis.__initMethods__(module.exports, module);\\nObject.keys(module.exports).forEach(function(item) {\\n  if(typeof module.exports[item] === 'function'){\\n    _this[item] = module.exports[item];\\n  }\\n});\\n\\n}\",\n    },\n  },\n  condition: true,\n  css:\n    'body{background-color:#f2f3f5}.card_kgaqfbm5 {\\n  margin-bottom: 12px;\\n}.card_kgaqfbm6 {\\n  margin-bottom: 12px;\\n}.button_kgaqfbm7 {\\n  margin-right: 16px;\\n  width: 80px\\n}.button_kgaqfbm8 {\\n  width: 80px;\\n}.div_kgaqfbm9 {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n  methods: {\n    __initMethods__: {\n      type: 'js',\n      source: 'function (exports, module) { /*set actions code here*/ }',\n      compiled: 'function (exports, module) { /*set actions code here*/ }',\n    },\n  },\n  dataSource: {\n    offline: [],\n    globalConfig: {\n      fit: {\n        compiled: '',\n        source: '',\n        type: 'js',\n        error: {},\n      },\n    },\n    online: [],\n    sync: true,\n    list: [],\n  },\n  children: [\n    {\n      componentName: 'Dialog',\n      id: 'modal',\n      props: {\n        title: {\n          type: 'i18n',\n          use: 'zh-CN',\n          'en-US': 'Dialog Title',\n          'zh-CN': 'Dialog标题',\n        },\n        visible: false,\n        hasMask: true,\n        closeable: 'esc',\n        autoFocus: true,\n        footer: true,\n        footerAlign: 'right',\n        footerActions: 'cancel,ok',\n        confirmText: {\n          type: 'i18n',\n          use: 'zh-CN',\n          'en-US': 'Confirm',\n          'zh-CN': '确定',\n        },\n        cancelText: {\n          type: 'i18n',\n          use: 'zh-CN',\n          'en-US': 'Cancel',\n          'zh-CN': '取消',\n        },\n        confirmStyle: 'primary',\n        confirmState: '确定',\n        __style__: {},\n        fieldId: 'dialog_kijq2hni',\n        popupOutDialog: true,\n      },\n    },\n    {\n      componentName: 'RootHeader',\n      id: 'node_k1ow3cba',\n      props: {},\n      condition: true,\n      children: [\n        {\n          componentName: 'PageHeader',\n          id: 'node_k1ow3cbd',\n          props: {\n            extraContent: '',\n            __slot__extraContent: false,\n            __slot__action: false,\n            title: {\n              // type: 'JSSlot',\n              value: [\n                {\n                  componentName: 'Text',\n                  id: 'node_k1ow3cbf',\n                  props: {\n                    showTitle: false,\n                    behavior: 'NORMAL',\n                    content: {\n                      use: 'zh-CN',\n                      'en-US': 'Title',\n                      'zh-CN': '个人信息',\n                      type: 'i18n',\n                    },\n                    __style__: {},\n                    fieldId: 'text_k1ow3h1j',\n                    maxLine: 0,\n                  },\n                  condition: true,\n                },\n              ],\n            },\n            content: '',\n            __slot__logo: false,\n            __slot__crumb: false,\n            crumb: '',\n            tab: '',\n            logo: '',\n            action: '',\n            __slot__tab: false,\n            __style__: {},\n            __slot__content: false,\n            fieldId: 'pageHeader_k1ow3h1i',\n            subTitle: false,\n          },\n          condition: true,\n        },\n      ],\n    },\n    {\n      componentName: 'RootContent',\n      id: 'node_k1ow3cbb',\n      props: {\n        contentBgColor: 'transparent',\n        contentPadding: '0',\n        contentMargin: '20',\n      },\n      condition: true,\n      children: [\n        {\n          componentName: 'Form',\n          id: 'form',\n          extraPropA: 'extraPropA',\n          props: {\n            size: 'medium',\n            labelAlign: 'top',\n            autoValidate: true,\n            scrollToFirstError: true,\n            autoUnmount: true,\n            behavior: 'NORMAL',\n            dataSource: {\n              type: 'variable',\n              variable: 'state.formData',\n            },\n            obj: {\n              a: 1,\n              b: false,\n              c: 'string',\n            },\n            __style__: {},\n            fieldId: 'form',\n            fieldOptions: {},\n            slotA: '',\n          },\n          condition: true,\n          children: [\n            {\n              componentName: 'Card',\n              id: 'node_k1ow3cbj',\n              props: {\n                __slot__title: false,\n                subTitle: {\n                  use: 'zh-CN',\n                  'en-US': '',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                __slot__subTitle: false,\n                extra: {\n                  use: 'zh-CN',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                className: 'card_kgaqfbm5',\n                title: {\n                  use: 'zh-CN',\n                  'en-US': 'Title',\n                  'zh-CN': '基本信息',\n                  type: 'i18n',\n                },\n                __slot__extra: false,\n                showHeadDivider: true,\n                __style__: ':root {\\n  margin-bottom: 12px;\\n}',\n                showTitleBullet: true,\n                contentHeight: '',\n                fieldId: 'card_k1ow3h1l',\n                dividerNoInset: false,\n              },\n              condition: true,\n              children: [\n                {\n                  componentName: 'CardContent',\n                  id: 'node_k1ow3cbk',\n                  props: {},\n                  condition: true,\n                  children: [\n                    {\n                      componentName: 'ColumnsLayout',\n                      id: 'node_k1ow3cbw',\n                      props: {\n                        layout: '6:6',\n                        columnGap: '20',\n                        rowGap: 0,\n                        __style__: {},\n                        fieldId: 'columns_k1ow3h1v',\n                      },\n                      condition: true,\n                      children: [\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cbx',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjm',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cbz',\n                              props: {\n                                fieldName: 'name',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [\n                                  {\n                                    type: 'required',\n                                  },\n                                ],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h1w',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '姓名',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': null,\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc1',\n                              props: {\n                                fieldName: 'englishName',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h1y',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '英文名',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': null,\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc3',\n                              props: {\n                                fieldName: 'jobTitle',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h20',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '职位',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': null,\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cby',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjn',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc2',\n                              props: {\n                                fieldName: 'nickName',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h1z',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '花名',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': null,\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                            {\n                              componentName: 'SelectField',\n                              id: 'node_k1ow3cc0',\n                              props: {\n                                fieldName: 'gender',\n                                hasClear: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                mode: 'single',\n                                showSearch: false,\n                                autoWidth: true,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please select',\n                                  'zh-CN': '请选择',\n                                  type: 'i18n',\n                                },\n                                hasBorder: true,\n                                behavior: 'NORMAL',\n                                value: '',\n                                validation: [\n                                  {\n                                    type: 'required',\n                                  },\n                                ],\n                                __style__: {},\n                                fieldId: 'select_k1ow3h1x',\n                                notFoundContent: {\n                                  use: 'zh-CN',\n                                  type: 'i18n',\n                                },\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'SelectField',\n                                  'zh-CN': '性别',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                wrapperColOffset: 0,\n                                hasSelectAll: false,\n                                hasArrow: true,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                filterLocal: true,\n                                dataSource: [\n                                  {\n                                    defaultChecked: false,\n                                    text: {\n                                      'en-US': 'Option 1',\n                                      'zh-CN': '男',\n                                      type: 'i18n',\n                                      __sid__: 'param_k1owc4tb',\n                                    },\n                                    __sid__: 'serial_k1owc4t1',\n                                    value: 'M',\n                                    sid: 'opt_k1owc4t2',\n                                  },\n                                  {\n                                    defaultChecked: false,\n                                    text: {\n                                      'en-US': 'Option 2',\n                                      'zh-CN': '女',\n                                      type: 'i18n',\n                                      __sid__: 'param_k1owc4tf',\n                                    },\n                                    __sid__: 'serial_k1owc4t2',\n                                    value: 'F',\n                                    sid: 'opt_k1owc4t3',\n                                  },\n                                ],\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': null,\n                                  'zh-CN': '',\n                                },\n                                searchDelay: 300,\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'Card',\n              id: 'node_k1ow3cbl',\n              props: {\n                __slot__title: false,\n                subTitle: {\n                  use: 'zh-CN',\n                  'en-US': '',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                __slot__subTitle: false,\n                extra: {\n                  use: 'zh-CN',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                className: 'card_kgaqfbm6',\n                title: {\n                  use: 'zh-CN',\n                  'en-US': 'Title',\n                  'zh-CN': '部门信息',\n                  type: 'i18n',\n                },\n                __slot__extra: false,\n                showHeadDivider: true,\n                __style__: ':root {\\n  margin-bottom: 12px;\\n}',\n                showTitleBullet: true,\n                contentHeight: '',\n                fieldId: 'card_k1ow3h1m',\n                dividerNoInset: false,\n              },\n              condition: true,\n              children: [\n                {\n                  componentName: 'CardContent',\n                  id: 'node_k1ow3cbm',\n                  props: {},\n                  condition: true,\n                  children: [\n                    {\n                      componentName: 'TextField',\n                      id: 'node_k1ow3cc4',\n                      props: {\n                        fieldName: 'department',\n                        hasClear: false,\n                        autoFocus: false,\n                        tips: {\n                          'en-US': '',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        trim: false,\n                        labelTextAlign: 'right',\n                        placeholder: {\n                          use: 'zh-CN',\n                          'en-US': 'please input',\n                          'zh-CN': '请输入',\n                          type: 'i18n',\n                        },\n                        state: '',\n                        behavior: 'NORMAL',\n                        value: {\n                          use: 'zh-CN',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        addonBefore: {\n                          use: 'zh-CN',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        validation: [],\n                        hasLimitHint: false,\n                        cutString: false,\n                        __style__: {},\n                        fieldId: 'textField_k1ow3h21',\n                        htmlType: 'input',\n                        autoHeight: false,\n                        labelColOffset: 0,\n                        label: {\n                          use: 'zh-CN',\n                          'en-US': 'TextField',\n                          'zh-CN': '所属部门',\n                          type: 'i18n',\n                        },\n                        __category__: 'form',\n                        labelColSpan: 4,\n                        wrapperColSpan: 0,\n                        rows: 4,\n                        addonAfter: {\n                          use: 'zh-CN',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        wrapperColOffset: 0,\n                        size: 'medium',\n                        labelAlign: 'top',\n                        __useMediator: 'value',\n                        labelTipsTypes: 'none',\n                        labelTipsIcon: '',\n                        labelTipsText: {\n                          type: 'i18n',\n                          use: 'zh-CN',\n                          'en-US': null,\n                          'zh-CN': '',\n                        },\n                      },\n                      condition: true,\n                    },\n                    {\n                      componentName: 'ColumnsLayout',\n                      id: 'node_k1ow3cc5',\n                      props: {\n                        layout: '6:6',\n                        columnGap: '20',\n                        rowGap: 0,\n                        __style__: {},\n                        fieldId: 'columns_k1ow3h22',\n                      },\n                      condition: true,\n                      children: [\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cc6',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjo',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc8',\n                              props: {\n                                fieldName: 'leader',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h23',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '主管',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': null,\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cc7',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjp',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc9',\n                              props: {\n                                fieldName: 'hrg',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h24',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': 'HRG',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': null,\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'Div',\n              id: 'node_k1ow3cbo',\n              props: {\n                className: 'div_kgaqfbm9',\n                behavior: 'NORMAL',\n                __style__:\n                  ':root {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n                events: {},\n                fieldId: 'div_k1ow3h1o',\n                useFieldIdAsDomId: false,\n                customClassName: '',\n              },\n              condition: true,\n              children: [\n                {\n                  componentName: 'Button',\n                  id: 'node_k1ow3cbn',\n                  props: {\n                    triggerEventsWhenLoading: false,\n                    onClick: {\n                      rawType: 'events',\n                      type: 'JSExpression',\n                      value: 'this.utils.legaoBuiltin.execEventFlow.bind(this, [this.submit])',\n                      events: [\n                        {\n                          name: 'submit',\n                          id: 'submit',\n                          params: {},\n                          type: 'actionRef',\n                          uuid: '1570966253282_0',\n                        },\n                      ],\n                    },\n                    size: 'medium',\n                    baseIcon: '',\n                    otherIcon: '',\n                    className: 'button_kgaqfbm7',\n                    type: 'primary',\n                    behavior: 'NORMAL',\n                    loading: false,\n                    content: {\n                      use: 'zh-CN',\n                      'en-US': 'Button',\n                      'zh-CN': '提交',\n                      type: 'i18n',\n                    },\n                    __style__: ':root {\\n  margin-right: 16px;\\n  width: 80px\\n}',\n                    fieldId: 'button_k1ow3h1n',\n                  },\n                  condition: true,\n                },\n                {\n                  componentName: 'Button',\n                  id: 'node_k1ow3cbp',\n                  props: {\n                    triggerEventsWhenLoading: false,\n                    size: 'medium',\n                    baseIcon: '',\n                    otherIcon: '',\n                    className: 'button_kgaqfbm8',\n                    type: 'normal',\n                    behavior: 'NORMAL',\n                    loading: false,\n                    content: {\n                      use: 'zh-CN',\n                      'en-US': 'Button',\n                      'zh-CN': '取消',\n                      type: 'i18n',\n                    },\n                    __style__: ':root {\\n  width: 80px;\\n}',\n                    fieldId: 'button_k1ow3h1p',\n                    greeting: {\n                      // type: 'JSSlot',\n                      value: [\n                        {\n                          componentName: 'Text',\n                          props: {},\n                        },\n                      ],\n                    },\n                  },\n                  condition: true,\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'RootFooter',\n      id: 'node_k1ow3cbc',\n      props: {},\n      condition: true,\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/designer/tests/fixtures/schema/form.ts",
    "content": "export default {\n  componentName: 'Page',\n  id: 'page',\n  title: 'hey, i\\' a page!',\n  props: {\n    extensions: {\n      启用页头: true,\n    },\n    pageStyle: {\n      backgroundColor: '#f2f3f5',\n    },\n    containerStyle: {},\n    className: 'page_kgaqfbm4',\n    templateVersion: '1.0.0',\n  },\n  lifeCycles: {\n    constructor: {\n      type: 'js',\n      compiled:\n        \"function constructor() {\\nvar module = { exports: {} };\\nvar _this = this;\\nthis.__initMethods__(module.exports, module);\\nObject.keys(module.exports).forEach(function(item) {\\n  if(typeof module.exports[item] === 'function'){\\n    _this[item] = module.exports[item];\\n  }\\n});\\n\\n}\",\n      source:\n        \"function constructor() {\\nvar module = { exports: {} };\\nvar _this = this;\\nthis.__initMethods__(module.exports, module);\\nObject.keys(module.exports).forEach(function(item) {\\n  if(typeof module.exports[item] === 'function'){\\n    _this[item] = module.exports[item];\\n  }\\n});\\n\\n}\",\n    },\n  },\n  condition: true,\n  css:\n    'body{background-color:#f2f3f5}.card_kgaqfbm5 {\\n  margin-bottom: 12px;\\n}.card_kgaqfbm6 {\\n  margin-bottom: 12px;\\n}.button_kgaqfbm7 {\\n  margin-right: 16px;\\n  width: 80px\\n}.button_kgaqfbm8 {\\n  width: 80px;\\n}.div_kgaqfbm9 {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n  methods: {\n    __initMethods__: {\n      type: 'js',\n      source: 'function (exports, module) { /*set actions code here*/ }',\n      compiled: 'function (exports, module) { /*set actions code here*/ }',\n    },\n  },\n  dataSource: {\n    offline: [],\n    globalConfig: {\n      fit: {\n        compiled: '',\n        source: '',\n        type: 'js',\n        error: {},\n      },\n    },\n    online: [],\n    sync: true,\n    list: [],\n  },\n  children: [\n    {\n      componentName: 'RootHeader',\n      id: 'node_k1ow3cba',\n      props: {},\n      condition: true,\n      children: [\n        {\n          componentName: 'PageHeader',\n          id: 'node_k1ow3cbd',\n          props: {\n            extraContent: '',\n            __slot__extraContent: false,\n            __slot__action: false,\n            title: {\n              // type: 'JSSlot',\n              value: [\n                {\n                  componentName: 'Text',\n                  id: 'node_k1ow3cbf',\n                  props: {\n                    showTitle: false,\n                    behavior: 'NORMAL',\n                    content: {\n                      use: 'zh-CN',\n                      'en-US': 'Title',\n                      'zh-CN': '个人信息',\n                      type: 'i18n',\n                    },\n                    __style__: {},\n                    fieldId: 'text_k1ow3h1j',\n                    maxLine: 0,\n                  },\n                  condition: true,\n                },\n              ],\n            },\n            content: '',\n            __slot__logo: false,\n            __slot__crumb: false,\n            crumb: '',\n            tab: '',\n            logo: '',\n            action: '',\n            __slot__tab: false,\n            __style__: {},\n            __slot__content: false,\n            fieldId: 'pageHeader_k1ow3h1i',\n            subTitle: false,\n          },\n          condition: true,\n        },\n      ],\n    },\n    {\n      componentName: 'RootContent',\n      id: 'node_k1ow3cbb',\n      props: {\n        contentBgColor: 'transparent',\n        contentPadding: '0',\n        contentMargin: '20',\n      },\n      condition: true,\n      children: [\n        {\n          componentName: 'Form',\n          id: 'form',\n          extraPropA: 'extraPropA',\n          props: {\n            size: 'medium',\n            labelAlign: 'top',\n            autoValidate: true,\n            scrollToFirstError: true,\n            autoUnmount: true,\n            behavior: 'NORMAL',\n            dataSource: {\n              type: 'variable',\n              variable: 'state.formData',\n            },\n            obj: {\n              a: 1,\n              b: false,\n              c: 'string',\n            },\n            __style__: {},\n            fieldId: 'form',\n            fieldOptions: {},\n            slotA: '',\n          },\n          condition: true,\n          children: [\n            {\n              componentName: 'Card',\n              id: 'node_k1ow3cbj',\n              props: {\n                __slot__title: false,\n                subTitle: {\n                  use: 'zh-CN',\n                  'en-US': '',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                __slot__subTitle: false,\n                extra: {\n                  use: 'zh-CN',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                className: 'card_kgaqfbm5',\n                title: {\n                  use: 'zh-CN',\n                  'en-US': 'Title',\n                  'zh-CN': '基本信息',\n                  type: 'i18n',\n                },\n                __slot__extra: false,\n                showHeadDivider: true,\n                __style__: ':root {\\n  margin-bottom: 12px;\\n}',\n                showTitleBullet: true,\n                contentHeight: '',\n                fieldId: 'card_k1ow3h1l',\n                dividerNoInset: false,\n              },\n              condition: true,\n              children: [\n                {\n                  componentName: 'CardContent',\n                  id: 'node_k1ow3cbk',\n                  props: {},\n                  condition: true,\n                  children: [\n                    {\n                      componentName: 'ColumnsLayout',\n                      id: 'node_k1ow3cbw',\n                      props: {\n                        layout: '6:6',\n                        columnGap: '20',\n                        rowGap: 0,\n                        __style__: {},\n                        fieldId: 'columns_k1ow3h1v',\n                      },\n                      condition: true,\n                      children: [\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cbx',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjm',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cbz',\n                              props: {\n                                fieldName: 'name',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [\n                                  {\n                                    type: 'required',\n                                  },\n                                ],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h1w',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '姓名',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc1',\n                              props: {\n                                fieldName: 'englishName',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h1y',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '英文名',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc3',\n                              props: {\n                                fieldName: 'jobTitle',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h20',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '职位',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cby',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjn',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc2',\n                              props: {\n                                fieldName: 'nickName',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h1z',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '花名',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                            {\n                              componentName: 'SelectField',\n                              id: 'node_k1ow3cc0',\n                              props: {\n                                fieldName: 'gender',\n                                hasClear: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                mode: 'single',\n                                showSearch: false,\n                                autoWidth: true,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please select',\n                                  'zh-CN': '请选择',\n                                  type: 'i18n',\n                                },\n                                hasBorder: true,\n                                behavior: 'NORMAL',\n                                value: '',\n                                validation: [\n                                  {\n                                    type: 'required',\n                                  },\n                                ],\n                                __style__: {},\n                                fieldId: 'select_k1ow3h1x',\n                                notFoundContent: {\n                                  use: 'zh-CN',\n                                  type: 'i18n',\n                                },\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'SelectField',\n                                  'zh-CN': '性别',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                wrapperColOffset: 0,\n                                hasSelectAll: false,\n                                hasArrow: true,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                filterLocal: true,\n                                dataSource: [\n                                  {\n                                    defaultChecked: false,\n                                    text: {\n                                      'en-US': 'Option 1',\n                                      'zh-CN': '男',\n                                      type: 'i18n',\n                                      __sid__: 'param_k1owc4tb',\n                                    },\n                                    __sid__: 'serial_k1owc4t1',\n                                    value: 'M',\n                                    sid: 'opt_k1owc4t2',\n                                  },\n                                  {\n                                    defaultChecked: false,\n                                    text: {\n                                      'en-US': 'Option 2',\n                                      'zh-CN': '女',\n                                      type: 'i18n',\n                                      __sid__: 'param_k1owc4tf',\n                                    },\n                                    __sid__: 'serial_k1owc4t2',\n                                    value: 'F',\n                                    sid: 'opt_k1owc4t3',\n                                  },\n                                ],\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                },\n                                searchDelay: 300,\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'Card',\n              id: 'node_k1ow3cbl',\n              props: {\n                __slot__title: false,\n                subTitle: {\n                  use: 'zh-CN',\n                  'en-US': '',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                __slot__subTitle: false,\n                extra: {\n                  use: 'zh-CN',\n                  'zh-CN': '',\n                  type: 'i18n',\n                },\n                className: 'card_kgaqfbm6',\n                title: {\n                  use: 'zh-CN',\n                  'en-US': 'Title',\n                  'zh-CN': '部门信息',\n                  type: 'i18n',\n                },\n                __slot__extra: false,\n                showHeadDivider: true,\n                __style__: ':root {\\n  margin-bottom: 12px;\\n}',\n                showTitleBullet: true,\n                contentHeight: '',\n                fieldId: 'card_k1ow3h1m',\n                dividerNoInset: false,\n              },\n              condition: true,\n              children: [\n                {\n                  componentName: 'CardContent',\n                  id: 'node_k1ow3cbm',\n                  props: {},\n                  condition: true,\n                  children: [\n                    {\n                      componentName: 'TextField',\n                      id: 'node_k1ow3cc4',\n                      props: {\n                        fieldName: 'department',\n                        hasClear: false,\n                        autoFocus: false,\n                        tips: {\n                          'en-US': '',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        trim: false,\n                        labelTextAlign: 'right',\n                        placeholder: {\n                          use: 'zh-CN',\n                          'en-US': 'please input',\n                          'zh-CN': '请输入',\n                          type: 'i18n',\n                        },\n                        state: '',\n                        behavior: 'NORMAL',\n                        value: {\n                          use: 'zh-CN',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        addonBefore: {\n                          use: 'zh-CN',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        validation: [],\n                        hasLimitHint: false,\n                        cutString: false,\n                        __style__: {},\n                        fieldId: 'textField_k1ow3h21',\n                        htmlType: 'input',\n                        autoHeight: false,\n                        labelColOffset: 0,\n                        label: {\n                          use: 'zh-CN',\n                          'en-US': 'TextField',\n                          'zh-CN': '所属部门',\n                          type: 'i18n',\n                        },\n                        __category__: 'form',\n                        labelColSpan: 4,\n                        wrapperColSpan: 0,\n                        rows: 4,\n                        addonAfter: {\n                          use: 'zh-CN',\n                          'zh-CN': '',\n                          type: 'i18n',\n                        },\n                        wrapperColOffset: 0,\n                        size: 'medium',\n                        labelAlign: 'top',\n                        __useMediator: 'value',\n                        labelTipsTypes: 'none',\n                        labelTipsIcon: '',\n                        labelTipsText: {\n                          type: 'i18n',\n                          use: 'zh-CN',\n                          'en-US': '',\n                          'zh-CN': '',\n                        },\n                      },\n                      condition: true,\n                    },\n                    {\n                      componentName: 'ColumnsLayout',\n                      id: 'node_k1ow3cc5',\n                      props: {\n                        layout: '6:6',\n                        columnGap: '20',\n                        rowGap: 0,\n                        __style__: {},\n                        fieldId: 'columns_k1ow3h22',\n                      },\n                      condition: true,\n                      children: [\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cc6',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjo',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc8',\n                              props: {\n                                fieldName: 'leader',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h23',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': '主管',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                        {\n                          componentName: 'Column',\n                          id: 'node_k1ow3cc7',\n                          props: {\n                            colSpan: '',\n                            __style__: {},\n                            fieldId: 'column_k1p1bnjp',\n                          },\n                          condition: true,\n                          children: [\n                            {\n                              componentName: 'TextField',\n                              id: 'node_k1ow3cc9',\n                              props: {\n                                fieldName: 'hrg',\n                                hasClear: false,\n                                autoFocus: false,\n                                tips: {\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                trim: false,\n                                labelTextAlign: 'right',\n                                placeholder: {\n                                  use: 'zh-CN',\n                                  'en-US': 'please input',\n                                  'zh-CN': '请输入',\n                                  type: 'i18n',\n                                },\n                                state: '',\n                                behavior: 'NORMAL',\n                                value: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                addonBefore: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                validation: [],\n                                hasLimitHint: false,\n                                cutString: false,\n                                __style__: {},\n                                fieldId: 'textField_k1ow3h24',\n                                htmlType: 'input',\n                                autoHeight: false,\n                                labelColOffset: 0,\n                                label: {\n                                  use: 'zh-CN',\n                                  'en-US': 'TextField',\n                                  'zh-CN': 'HRG',\n                                  type: 'i18n',\n                                },\n                                __category__: 'form',\n                                labelColSpan: 4,\n                                wrapperColSpan: 0,\n                                rows: 4,\n                                addonAfter: {\n                                  use: 'zh-CN',\n                                  'zh-CN': '',\n                                  type: 'i18n',\n                                },\n                                wrapperColOffset: 0,\n                                size: 'medium',\n                                labelAlign: 'top',\n                                __useMediator: 'value',\n                                labelTipsTypes: 'none',\n                                labelTipsIcon: '',\n                                labelTipsText: {\n                                  type: 'i18n',\n                                  use: 'zh-CN',\n                                  'en-US': '',\n                                  'zh-CN': '',\n                                },\n                              },\n                              condition: true,\n                            },\n                          ],\n                        },\n                      ],\n                    },\n                  ],\n                },\n              ],\n            },\n            {\n              componentName: 'Div',\n              id: 'node_k1ow3cbo',\n              props: {\n                className: 'div_kgaqfbm9',\n                behavior: 'NORMAL',\n                __style__:\n                  ':root {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n                events: {},\n                fieldId: 'div_k1ow3h1o',\n                useFieldIdAsDomId: false,\n                customClassName: '',\n              },\n              condition: true,\n              children: [\n                {\n                  componentName: 'Button',\n                  id: 'node_k1ow3cbn',\n                  props: {\n                    triggerEventsWhenLoading: false,\n                    onClick: {\n                      rawType: 'events',\n                      type: 'JSExpression',\n                      value: 'this.utils.legaoBuiltin.execEventFlow.bind(this, [this.submit])',\n                      events: [\n                        {\n                          name: 'submit',\n                          id: 'submit',\n                          params: {},\n                          type: 'actionRef',\n                          uuid: '1570966253282_0',\n                        },\n                      ],\n                    },\n                    size: 'medium',\n                    baseIcon: '',\n                    otherIcon: '',\n                    className: 'button_kgaqfbm7',\n                    type: 'primary',\n                    behavior: 'NORMAL',\n                    loading: false,\n                    content: {\n                      use: 'zh-CN',\n                      'en-US': 'Button',\n                      'zh-CN': '提交',\n                      type: 'i18n',\n                    },\n                    __style__: ':root {\\n  margin-right: 16px;\\n  width: 80px\\n}',\n                    fieldId: 'button_k1ow3h1n',\n                  },\n                  condition: true,\n                },\n                {\n                  componentName: 'Button',\n                  id: 'node_k1ow3cbp',\n                  props: {\n                    triggerEventsWhenLoading: false,\n                    size: 'medium',\n                    baseIcon: '',\n                    otherIcon: '',\n                    className: 'button_kgaqfbm8',\n                    type: 'normal',\n                    behavior: 'NORMAL',\n                    loading: false,\n                    content: {\n                      use: 'zh-CN',\n                      'en-US': 'Button',\n                      'zh-CN': '取消',\n                      type: 'i18n',\n                    },\n                    __style__: ':root {\\n  width: 80px;\\n}',\n                    fieldId: 'button_k1ow3h1p',\n                    greeting: {\n                      // type: 'JSSlot',\n                      value: [{\n                        componentName: 'Text',\n                        props: {},\n                      }],\n                    },\n                  },\n                  condition: true,\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'RootFooter',\n      id: 'node_k1ow3cbc',\n      props: {},\n      condition: true,\n    },\n  ],\n  i18n: {\n    'zh-CN': {\n      'i18n-jwg27yo4': '你好',\n      'i18n-jwg27yo3': '中国',\n    },\n    'en-US': {\n      'i18n-jwg27yo4': 'Hello',\n      'i18n-jwg27yo3': 'China',\n    },\n  },\n};\n"
  },
  {
    "path": "packages/designer/tests/fixtures/schema/setting.ts",
    "content": "export default {\n  componentName: 'Page',\n  id: 'page',\n  title: 'hey, i\\' a page!',\n  props: {\n    extensions: {\n      启用页头: true,\n    },\n    pageStyle: {\n      backgroundColor: '#f2f3f5',\n    },\n    containerStyle: {},\n    className: 'page_kgaqfbm4',\n    templateVersion: '1.0.0',\n  },\n  lifeCycles: {\n    constructor: {\n      type: 'js',\n      compiled:\n        \"function constructor() {\\nvar module = { exports: {} };\\nvar _this = this;\\nthis.__initMethods__(module.exports, module);\\nObject.keys(module.exports).forEach(function(item) {\\n  if(typeof module.exports[item] === 'function'){\\n    _this[item] = module.exports[item];\\n  }\\n});\\n\\n}\",\n      source:\n        \"function constructor() {\\nvar module = { exports: {} };\\nvar _this = this;\\nthis.__initMethods__(module.exports, module);\\nObject.keys(module.exports).forEach(function(item) {\\n  if(typeof module.exports[item] === 'function'){\\n    _this[item] = module.exports[item];\\n  }\\n});\\n\\n}\",\n    },\n  },\n  condition: true,\n  css:\n    'body{background-color:#f2f3f5}.card_kgaqfbm5 {\\n  margin-bottom: 12px;\\n}.card_kgaqfbm6 {\\n  margin-bottom: 12px;\\n}.button_kgaqfbm7 {\\n  margin-right: 16px;\\n  width: 80px\\n}.button_kgaqfbm8 {\\n  width: 80px;\\n}.div_kgaqfbm9 {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n  methods: {\n    __initMethods__: {\n      type: 'js',\n      source: 'function (exports, module) { /*set actions code here*/ }',\n      compiled: 'function (exports, module) { /*set actions code here*/ }',\n    },\n  },\n  children: [\n    {\n      componentName: 'Div',\n      id: 'div',\n      props: {\n        className: 'div_kgaqfbm9',\n        behavior: 'NORMAL',\n        __style__:\n          ':root {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n        events: {},\n        fieldId: 'div_k1ow3h1o',\n        useFieldIdAsDomId: false,\n        customClassName: {\n          type: 'JSExpression',\n          value: 'getFromSomewhere()',\n        },\n        customClassName2: {\n          type: 'JSExpression',\n          mock: { hi: 'mock' },\n          value: 'getFromSomewhere()',\n        },\n      },\n      extraPropA: 'haha',\n    },\n    {\n      componentName: 'Div',\n      id: 'div2',\n      props: {\n        className: 'div_kgaqfbm9',\n        behavior: 'NORMAL',\n        __style__:\n          ':root {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n        events: {},\n        fieldId: 'div_k1ow3h1o',\n        useFieldIdAsDomId: false,\n        customClassName: '',\n      },\n      extraPropA: 'haha',\n    },\n    {\n      componentName: 'Test',\n      id: 'test',\n      props: {\n        className: 'div_kgaqfbm9',\n        behavior: 'NORMAL',\n        __style__:\n          ':root {\\n  display: flex;\\n  align-items: flex-start;\\n  justify-content: center;\\n  background: #fff;\\n  padding: 20px 0;\\n}',\n        events: {},\n        fieldId: 'div_k1ow3h1o',\n        useFieldIdAsDomId: false,\n        customClassName: '',\n      },\n      extraPropA: 'haha',\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/designer/tests/fixtures/silent-console.ts",
    "content": "export const mockConsoleError = jest.fn();\nexport const mockConsoleWarn = jest.fn();\n// const mockConsoleInfo = jest.fn();\nconsole.error = mockConsoleError;\nconsole.warn = mockConsoleWarn;\n\n"
  },
  {
    "path": "packages/designer/tests/fixtures/unhandled-rejection.ts",
    "content": "if (!process.env.LISTENING_TO_UNHANDLED_REJECTION) {\n  process.on('unhandledRejection', reason => {\n    throw reason;\n  });\n  // Avoid memory leak by adding too many listeners\n  process.env.LISTENING_TO_UNHANDLED_REJECTION = true;\n}\n"
  },
  {
    "path": "packages/designer/tests/fixtures/window.ts",
    "content": "Object.defineProperty(window, 'matchMedia', {\n  writable: true,\n  value: jest.fn().mockImplementation(query => ({\n    matches: false,\n    media: query,\n    onchange: null,\n    addListener: jest.fn(), // deprecated\n    removeListener: jest.fn(), // deprecated\n    addEventListener: jest.fn(),\n    removeEventListener: jest.fn(),\n    dispatchEvent: jest.fn(),\n  })),\n});\n\nObject.defineProperty(window, 'React', {\n  writable: true,\n  value: {},\n});\n\nwindow.scrollTo = () => {};\nwindow.console.warn = () => {};\nconst originalLog = window.console.log;\nwindow.console.log = (...args) => {\n  // suppress boring warnings\n  if (args[0]?.includes && args[0].includes('@babel/plugin-proposal-private-property-in-object')) return;\n  originalLog.apply(window.console, args);\n};\nwindow.React = window.React || {};\n"
  },
  {
    "path": "packages/designer/tests/main/meta/component-meta.test.ts",
    "content": "import '../../fixtures/window';\nimport { Designer } from '../../../src/designer/designer';\nimport divMeta from '../../fixtures/component-metadata/div';\nimport div2Meta from '../../fixtures/component-metadata/div2';\nimport div3Meta from '../../fixtures/component-metadata/div3';\nimport div4Meta from '../../fixtures/component-metadata/div4';\nimport div5Meta from '../../fixtures/component-metadata/div5';\nimport div6Meta from '../../fixtures/component-metadata/div6';\nimport div7Meta from '../../fixtures/component-metadata/div7';\nimport div8Meta from '../../fixtures/component-metadata/div8';\nimport div9Meta from '../../fixtures/component-metadata/div9';\nimport div10Meta from '../../fixtures/component-metadata/div10';\nimport abcgroup from '../../fixtures/component-metadata/abcgroup';\nimport abcitem from '../../fixtures/component-metadata/abcitem';\nimport abcnode from '../../fixtures/component-metadata/abcnode';\nimport abcoption from '../../fixtures/component-metadata/abcoption';\nimport page2Meta from '../../fixtures/component-metadata/page2';\nimport {\n  ComponentMeta,\n  isComponentMeta,\n  ensureAList,\n  buildFilter,\n} from '../../../src/component-meta';\n\n\njest.mock('../../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      const { ComponentActions } = require('../../../src/component-actions');\n      return {\n        getGlobalComponentActions: () => [],\n        componentActions: new ComponentActions(),\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({} as any);\n});\n\ndescribe('组件元数据处理', () => {\n  it('构造函数', () => {\n    const meta = new ComponentMeta(designer, divMeta);\n    expect(meta.isContainer).toBeTruthy();\n    expect(isComponentMeta(meta)).toBeTruthy();\n    expect(meta.acceptable).toBeFalsy();\n    expect(meta.isRootComponent()).toBeFalsy();\n    expect(meta.isModal).toBeFalsy();\n    expect(meta.rootSelector).toBeUndefined();\n    expect(meta.liveTextEditing).toBeUndefined();\n    expect(meta.descriptor).toBeUndefined();\n    expect(typeof meta.icon).toBe('function');\n    expect(meta.getMetadata().title).toBe('容器');\n    expect(meta.title).toEqual({ type: 'i18n', 'en-US': 'Div', 'zh-CN': '容器' });\n    expect(meta.isMinimalRenderUnit).toBeFalsy();\n    expect(meta.isTopFixed).toBeFalsy();\n\n    meta.setNpm({ package: '@ali/vc-div', componentName: 'Div' });\n    expect(meta.npm).toEqual({ package: '@ali/vc-div', componentName: 'Div' });\n    meta.npm = { package: '@ali/vc-div', componentName: 'Div' };\n    expect(meta.npm).toEqual({ package: '@ali/vc-div', componentName: 'Div' });\n\n\n    const mockFn = jest.fn();\n    const offFn = meta.onMetadataChange(mockFn);\n    meta.setMetadata(divMeta);\n    expect(mockFn).toHaveBeenCalledTimes(1);\n    offFn();\n    meta.setMetadata(divMeta);\n    // 不会再触发函数\n    expect(mockFn).toHaveBeenCalledTimes(1);\n  });\n\n  it('构造函数 - 兼容场景（title 是个普通对象）', () => {\n    const meta = new ComponentMeta(designer, div2Meta);\n    expect(meta.title).toEqual('容器');\n\n    expect(meta.isTopFixed).toBeTruthy();\n  });\n\n  it('构造函数 - 兼容场景（title fallback 到 componentName）', () => {\n    const meta = new ComponentMeta(designer, div3Meta);\n    expect(meta.title).toEqual('Div');\n  });\n\n  it('构造函数 - 兼容场景（configure 是个数组）', () => {\n    const meta = new ComponentMeta(designer, div4Meta);\n    expect(meta.configure).toEqual(div4Meta.configure);\n  });\n\n  it('构造函数 - 兼容场景（使用 experimental）', () => {\n    const meta = new ComponentMeta(designer, div6Meta);\n    expect(meta.getMetadata().configure.advanced.initials).toHaveLength(9);\n  });\n\n  it('构造函数 - 兼容场景（没有 configure.component）', () => {\n    const meta = new ComponentMeta(designer, div7Meta);\n    expect(meta.isContainer).toBeFalsy();\n    expect(meta.isModal).toBeFalsy();\n  });\n\n  it('构造函数 - 兼容场景（没有 configure）', () => {\n    const meta = new ComponentMeta(designer, div8Meta);\n    expect(meta.configure).toEqual([]);\n  });\n\n  it('构造函数 - 兼容场景（没有 npm）', () => {\n    const meta = new ComponentMeta(designer, div9Meta);\n    expect(meta.npm).toBeUndefined();\n\n    meta.setNpm({ package: '@ali/vc-div', componentName: 'Div' });\n    expect(meta.npm).toEqual({ package: '@ali/vc-div', componentName: 'Div' });\n  });\n\n  it('availableActions', () => {\n    const meta = new ComponentMeta(designer, divMeta);\n    expect(meta.availableActions).toHaveLength(5);\n    expect(meta.availableActions[0].name).toBe('remove');\n    expect(meta.availableActions[1].name).toBe('hide');\n    expect(meta.availableActions[2].name).toBe('copy');\n\n    designer.componentActions.removeBuiltinComponentAction('remove');\n    expect(meta.availableActions).toHaveLength(4);\n    expect(meta.availableActions[0].name).toBe('hide');\n    expect(meta.availableActions[1].name).toBe('copy');\n\n    designer.componentActions.addBuiltinComponentAction({\n      name: 'new',\n      content: {\n        action() {},\n      },\n    });\n    expect(meta.availableActions).toHaveLength(5);\n    expect(meta.availableActions[0].name).toBe('hide');\n    expect(meta.availableActions[1].name).toBe('copy');\n    expect(meta.availableActions[4].name).toBe('new');\n  });\n\n  it('availableActions - disableBehaviors: *', () => {\n    const meta = new ComponentMeta(designer, div5Meta);\n    expect(meta.availableActions).toHaveLength(0);\n  });\n\n  it('availableActions - rootCompoment', () => {\n    const meta = new ComponentMeta(designer, page2Meta);\n    // (hide + new) left\n    expect(meta.availableActions).toHaveLength(2);\n  });\n\n  describe('checkNesting', () => {\n    const mockNode = (componentName) => {\n      return {\n        internalToShellNode() {\n          return {\n            componentName,\n          };\n        },\n        isNode: true,\n      };\n    };\n    const mockNodeForm = mockNode('Form');\n    const mockNodeImage = mockNode('Image');\n    const mockNodeDiv = mockNode('Div');\n    it('checkNestingUp', () => {\n      const meta1 = new ComponentMeta(designer, divMeta);\n      // 没有配置 parentWhitelist，判断默认为 true\n      expect(meta1.checkNestingUp(mockNodeDiv, mockNodeDiv)).toBeTruthy();\n\n      const meta2 = new ComponentMeta(designer, div10Meta);\n      expect(meta2.checkNestingUp(mockNodeDiv, mockNodeForm)).toBeTruthy();\n      expect(meta2.checkNestingUp(mockNodeDiv, mockNodeDiv)).toBeFalsy();\n    });\n\n    it('checkNestingDown', () => {\n      const meta1 = new ComponentMeta(designer, divMeta);\n      // 没有配置 childWhitelist，判断默认为 true\n      expect(meta1.checkNestingDown(mockNodeDiv, mockNodeDiv)).toBeTruthy();\n\n      const meta2 = new ComponentMeta(designer, div10Meta);\n      expect(meta2.checkNestingDown(mockNodeDiv, mockNodeForm)).toBeFalsy();\n      expect(meta2.checkNestingDown(mockNodeDiv, mockNodeImage)).toBeTruthy();\n    });\n  });\n});\n\ndescribe('组件元数据 transducers', () => {\n  it('legacyIssues', () => {\n    const legacyMeta: any = {\n      ...divMeta,\n      devMode: 'procode',\n    };\n    const meta = new ComponentMeta(designer, legacyMeta);\n    const metadata = meta.getMetadata();\n    expect(metadata.devMode).toBe('proCode');\n  });\n});\n\ndescribe('帮助函数', () => {\n  it('ensureAList', () => {\n    expect(ensureAList()).toBeNull();\n    expect(ensureAList(1)).toBeNull();\n    expect(ensureAList([])).toBeNull();\n    expect(ensureAList('copy lock')).toEqual(['copy', 'lock']);\n    expect(ensureAList(['copy', 'lock'])).toEqual(['copy', 'lock']);\n  });\n\n  it('buildFilter', () => {\n    const mockFn = () => {};\n    expect(buildFilter()).toBeNull();\n    expect(buildFilter([])).toBeNull();\n    expect(buildFilter(mockFn)).toBe(mockFn);\n\n    const mockRE = /xxx/;\n    const filter = buildFilter(mockRE);\n    expect(filter({ componentName: 'xxx' })).toBeTruthy();\n    expect(filter({ componentName: 'yyy' })).toBeFalsy();\n\n    expect(buildFilter('xxx yyy')({ componentName: 'xxx' })).toBeTruthy();\n    expect(buildFilter('xxx yyy')({ componentName: 'zzz' })).toBeFalsy();\n  });\n\n  it('registerMetadataTransducer', () => {\n    expect(designer.componentActions.getRegisteredMetadataTransducers()).toHaveLength(2);\n    // 插入到 legacy-issues 和 component-defaults 的中间\n    designer.componentActions.registerMetadataTransducer((metadata) => metadata, 3, 'noop');\n    expect(designer.componentActions.getRegisteredMetadataTransducers()).toHaveLength(3);\n\n    designer.componentActions.registerMetadataTransducer((metadata) => metadata);\n    expect(designer.componentActions.getRegisteredMetadataTransducers()).toHaveLength(4);\n  });\n\n  it('modifyBuiltinComponentAction', () => {\n    designer.componentActions.modifyBuiltinComponentAction('copy', (action) => {\n      expect(action.name).toBe('copy');\n    });\n  });\n});\n\ndescribe('transducers', () => {\n  it('componentDefaults', () => {\n    const meta1 = new ComponentMeta(designer, abcgroup);\n    const meta2 = new ComponentMeta(designer, abcitem);\n    const meta3 = new ComponentMeta(designer, abcnode);\n    const meta4 = new ComponentMeta(designer, abcoption);\n    expect(meta1.getMetadata().configure.component.nestingRule.childWhitelist).toEqual(['Abc']);\n    expect(meta2.getMetadata().configure.component.nestingRule.parentWhitelist).toEqual(['Abc']);\n    expect(meta3.getMetadata().configure.component.nestingRule.parentWhitelist).toEqual(['Abc', 'Abc.Node']);\n    expect(meta4.getMetadata().configure.component.nestingRule.parentWhitelist).toEqual(['Abc']);\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/main/simulator.test.ts",
    "content": "import '../fixtures/window';\nimport { isSimulatorHost } from '../../src/simulator';\n\nit('isSimulatorHost', () => {\n  expect(isSimulatorHost({ isSimulator: true })).toBeTruthy();\n  expect(isSimulatorHost({ a: 1 })).toBeFalsy();\n});\n"
  },
  {
    "path": "packages/designer/tests/plugin/plugin-manager.test.ts",
    "content": "import '../fixtures/window';\nimport { Editor, engineConfig } from '@alilc/lowcode-editor-core';\nimport { LowCodePluginManager } from '../../src/plugin/plugin-manager';\nimport { IPublicModelPluginContext, IPublicApiPlugins } from '@alilc/lowcode-types';\nimport { ILowCodePluginContextPrivate } from '../../src/plugin/plugin-types';\n\nconst editor = new Editor();\nlet contextApiAssembler;\n\ndescribe('plugin 测试', () => {\n  let pluginManager: IPublicApiPlugins;\n  beforeEach(() => {\n    contextApiAssembler = {\n      assembleApis(context: ILowCodePluginContextPrivate){\n        context.plugins = pluginManager as IPublicApiPlugins;\n        // mock set apis\n      }\n    };\n    pluginManager = new LowCodePluginManager(contextApiAssembler).toProxy();\n  });\n  afterEach(() => {\n    pluginManager.dispose();\n  });\n\n  it('注册插件，插件参数生成函数能被调用，且能拿到正确的 ctx ', () => {\n    const mockFn = jest.fn();\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      mockFn(ctx);\n      return {\n        init: jest.fn(),\n      };\n    };\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n\n    const [expectedCtx] = mockFn.mock.calls[0];\n    expect(expectedCtx).toHaveProperty('project');\n    expect(expectedCtx).toHaveProperty('setters');\n    expect(expectedCtx).toHaveProperty('material');\n    expect(expectedCtx).toHaveProperty('hotkey');\n    expect(expectedCtx).toHaveProperty('plugins');\n    expect(expectedCtx).toHaveProperty('skeleton');\n    expect(expectedCtx).toHaveProperty('logger');\n    expect(expectedCtx).toHaveProperty('config');\n    expect(expectedCtx).toHaveProperty('event');\n    expect(expectedCtx).toHaveProperty('preference');\n  });\n\n  it('注册插件，调用插件 init 方法', async () => {\n    const mockFn = jest.fn();\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: mockFn,\n        exports() {\n          return {\n            x: 1,\n            y: 2,\n          };\n        },\n      };\n    };\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n    await pluginManager.init();\n    expect(pluginManager.size).toBe(1);\n    expect(pluginManager.has('demo1')).toBeTruthy();\n    expect(pluginManager.get('demo1')!.isInited()).toBeTruthy();\n    expect(pluginManager.demo1).toBeTruthy();\n    expect(pluginManager.demo1.x).toBe(1);\n    expect(pluginManager.demo1.y).toBe(2);\n    expect(pluginManager.demo1.z).toBeUndefined();\n    expect(mockFn).toHaveBeenCalled();\n  });\n\n  it('注册插件，调用 setDisabled 方法', async () => {\n    const mockFn = jest.fn();\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: mockFn,\n      };\n    };\n    creator2.pluginName = 'demo1';\n\n    pluginManager.register(creator2);\n    await pluginManager.init();\n    expect(pluginManager.demo1).toBeTruthy();\n    pluginManager.setDisabled('demo1', true);\n    expect(pluginManager.demo1).toBeUndefined();\n  });\n\n  it('注册插件，调用 plugin.setDisabled 方法', async () => {\n    const mockFn = jest.fn();\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: mockFn,\n      };\n    };\n    creator2.pluginName = 'demo1';\n\n    pluginManager.register(creator2);\n    await pluginManager.init();\n    expect(pluginManager.demo1).toBeTruthy();\n    pluginManager.get('demo1').setDisabled();\n    expect(pluginManager.demo1).toBeUndefined();\n  });\n\n  it('删除插件，调用插件 destroy 方法', async () => {\n    const mockFn = jest.fn();\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: jest.fn(),\n        destroy: mockFn,\n      };\n    };\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n\n    await pluginManager.init();\n    await pluginManager.delete('demo1');\n    expect(mockFn).toHaveBeenCalled();\n    await pluginManager.delete('non-existing');\n  });\n\n  describe('dependencies 依赖', () => {\n    it('dependencies 依赖', async () => {\n      const mockFn = jest.fn();\n      const creator21 = (ctx: IPublicModelPluginContext) => {\n        return {\n          init: () => mockFn('demo1'),\n        };\n      };\n      creator21.pluginName = 'demo1';\n      creator21.meta = {\n        dependencies: ['demo2'],\n      };\n      pluginManager.register(creator21);\n      const creator22 = (ctx: IPublicModelPluginContext) => {\n        return {\n          init: () => mockFn('demo2'),\n        };\n      };\n      creator22.pluginName = 'demo2';\n      pluginManager.register(creator22);\n\n      await pluginManager.init();\n      expect(mockFn).toHaveBeenNthCalledWith(1, 'demo2');\n      expect(mockFn).toHaveBeenNthCalledWith(2, 'demo1');\n    });\n\n    it('dependencies 依赖 - string', async () => {\n      const mockFn = jest.fn();\n      const creator21 = (ctx: IPublicModelPluginContext) => {\n        return {\n          init: () => mockFn('demo1'),\n        };\n      };\n      creator21.pluginName = 'demo1';\n      creator21.meta = {\n        dependencies: 'demo2',\n      };\n      pluginManager.register(creator21);\n      const creator22 = (ctx: IPublicModelPluginContext) => {\n        return {\n          init: () => mockFn('demo2'),\n        };\n      };\n      creator22.pluginName = 'demo2';\n      pluginManager.register(creator22);\n\n      await pluginManager.init();\n      expect(mockFn).toHaveBeenNthCalledWith(1, 'demo2');\n      expect(mockFn).toHaveBeenNthCalledWith(2, 'demo1');\n    });\n\n    it('dependencies 依赖 - 兼容 dep', async () => {\n      const mockFn = jest.fn();\n      const creator21 = (ctx: IPublicModelPluginContext) => {\n        return {\n          dep: ['demo4'],\n          init: () => mockFn('demo3'),\n        };\n      };\n      creator21.pluginName = 'demo3';\n      pluginManager.register(creator21);\n      const creator22 = (ctx: IPublicModelPluginContext) => {\n        return {\n          init: () => mockFn('demo4'),\n        };\n      };\n      creator22.pluginName = 'demo4';\n      pluginManager.register(creator22);\n\n      await pluginManager.init();\n      expect(mockFn).toHaveBeenNthCalledWith(1, 'demo4');\n      expect(mockFn).toHaveBeenNthCalledWith(2, 'demo3');\n    });\n\n    it('dependencies 依赖 - 兼容 dep & string', async () => {\n      const mockFn = jest.fn();\n      const creator21 = (ctx: IPublicModelPluginContext) => {\n        return {\n          dep: 'demo4',\n          init: () => mockFn('demo3'),\n        };\n      };\n      creator21.pluginName = 'demo3';\n      pluginManager.register(creator21);\n      const creator22 = (ctx: IPublicModelPluginContext) => {\n        return {\n          init: () => mockFn('demo4'),\n        };\n      };\n      creator22.pluginName = 'demo4';\n      pluginManager.register(creator22);\n\n      await pluginManager.init();\n      expect(mockFn).toHaveBeenNthCalledWith(1, 'demo4');\n      expect(mockFn).toHaveBeenNthCalledWith(2, 'demo3');\n    });\n  });\n\n  it('version 依赖', async () => {\n    const mockFn = jest.fn();\n    const creator21 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: () => mockFn('demo1'),\n      };\n    };\n    creator21.pluginName = 'demo1';\n    creator21.meta = {\n      engines: {\n        lowcodeEngine: '^1.1.0',\n      },\n    };\n    engineConfig.set('ENGINE_VERSION', '1.0.1');\n\n    console.log('version: ', engineConfig.get('ENGINE_VERSION'));\n    // not match should skip\n    pluginManager.register(creator21).catch((e) => {\n      expect(e).toEqual(\n        new Error(\n          'plugin demo1 skipped, engine check failed, current engine version is 1.0.1, meta.engines.lowcodeEngine is ^1.1.0',\n        ),\n      );\n    });\n\n    expect(pluginManager.plugins.length).toBe(0);\n\n    const creator22 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: () => mockFn('demo2'),\n      };\n    };\n    creator22.pluginName = 'demo2';\n    creator22.meta = {\n      engines: {\n        lowcodeEngine: '^1.0.1',\n      },\n    };\n\n    engineConfig.set('ENGINE_VERSION', '1.0.3');\n    pluginManager.register(creator22);\n    expect(pluginManager.plugins.length).toBe(1);\n\n    const creator23 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: () => mockFn('demo3'),\n      };\n    };\n    creator23.pluginName = 'demo3';\n    creator23.meta = {\n      engines: {\n        lowcodeEngine: '1.x',\n      },\n    };\n    engineConfig.set('ENGINE_VERSION', '1.1.1');\n    pluginManager.register(creator23);\n    expect(pluginManager.plugins.length).toBe(2);\n  });\n\n  it('autoInit 功能', async () => {\n    const mockFn = jest.fn();\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: mockFn,\n      };\n    };\n    creator2.pluginName = 'demo1';\n    await pluginManager.register(creator2, { autoInit: true });\n    expect(mockFn).toHaveBeenCalled();\n  });\n\n  it('插件不会重复 init，除非强制重新 init', async () => {\n    const mockFn = jest.fn();\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {\n        name: 'demo1',\n        init: mockFn,\n      };\n    };\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n    await pluginManager.init();\n    expect(mockFn).toHaveBeenCalledTimes(1);\n\n    pluginManager.get('demo1')!.init();\n    expect(mockFn).toHaveBeenCalledTimes(1);\n\n    pluginManager.get('demo1')!.init(true);\n    expect(mockFn).toHaveBeenCalledTimes(2);\n  });\n\n  it('默认情况不允许重复注册', async () => {\n    const mockFn = jest.fn();\n    const mockPlugin = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: mockFn,\n      };\n    };\n    mockPlugin.pluginName = 'demoDuplicated';\n    pluginManager.register(mockPlugin);\n    pluginManager.register(mockPlugin).catch((e) => {\n      expect(e).toEqual(new Error('Plugin with name demoDuplicated exists'));\n    });\n    await pluginManager.init();\n  });\n\n  it('插件增加 override 参数时可以重复注册', async () => {\n    const mockFn = jest.fn();\n    const mockPlugin = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: mockFn,\n      };\n    };\n    mockPlugin.pluginName = 'demoOverride';\n    pluginManager.register(mockPlugin);\n    pluginManager.register(mockPlugin, { override: true });\n    await pluginManager.init();\n  });\n\n  it('插件增加 override 参数时可以重复注册, 被覆盖的如果已初始化，会被销毁', async () => {\n    const mockInitFn = jest.fn();\n    const mockDestroyFn = jest.fn();\n    const mockPlugin = (ctx: IPublicModelPluginContext) => {\n      return {\n        init: mockInitFn,\n        destroy: mockDestroyFn,\n      };\n    };\n    mockPlugin.pluginName = 'demoOverride';\n    await pluginManager.register(mockPlugin, { autoInit: true });\n    expect(mockInitFn).toHaveBeenCalledTimes(1);\n    await pluginManager.register(mockPlugin, { override: true });\n    expect(mockDestroyFn).toHaveBeenCalledTimes(1);\n    await pluginManager.init();\n  });\n\n  it('dispose 方法', async () => {\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {};\n    };\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n    await pluginManager.init();\n    const plugin = pluginManager.get('demo1')!;\n    await plugin.dispose();\n\n    expect(pluginManager.has('demo1')).toBeFalsy();\n  });\n\n  it('getAll 方法', async () => {\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {};\n    };\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n    await pluginManager.init();\n\n    expect(pluginManager.getAll()).toHaveLength(1);\n  });\n\n  it('getPluginPreference 方法 - null', async () => {\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {};\n    };\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n    await pluginManager.init();\n\n    expect(pluginManager.getPluginPreference()).toBeNull();\n  });\n\n  it('getPluginPreference 方法', async () => {\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {};\n    };\n    const preference = new Map();\n    preference.set('demo1', { a: 1, b: 2 });\n    creator2.pluginName = 'demo1';\n    pluginManager.register(creator2);\n    await pluginManager.init(preference);\n\n    expect(pluginManager.getPluginPreference('demo1')).toEqual({ a: 1, b: 2 });\n  });\n\n  it('注册插件，调用插件 init 方法并传入 preference，可以成功获取', async () => {\n    const mockFn = jest.fn();\n    const mockFnForCtx = jest.fn();\n    const mockFnForCtx2 = jest.fn();\n    const mockPreference = new Map();\n    mockPreference.set('demo1', {\n      key1: 'value for key1',\n      key2: false,\n      key3: 123,\n      key5: 'value for key5, but declared, should not work',\n    });\n\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      mockFnForCtx(ctx);\n      return {\n        init: jest.fn(),\n      };\n    };\n    creator2.pluginName = 'demo1';\n    creator2.meta = {\n      preferenceDeclaration: {\n        title: 'demo1的的参数定义',\n        properties: [\n          {\n            key: 'key1',\n            type: 'string',\n            description: 'this is description for key1',\n          },\n          {\n            key: 'key2',\n            type: 'boolean',\n            description: 'this is description for key2',\n          },\n          {\n            key: 'key3',\n            type: 'number',\n            description: 'this is description for key3',\n          },\n          {\n            key: 'key4',\n            type: 'string',\n            description: 'this is description for key4',\n          },\n        ],\n      },\n    };\n    const creator22 = (ctx: IPublicModelPluginContext) => {\n      mockFnForCtx2(ctx);\n      return {\n        init: jest.fn(),\n      };\n    };\n    creator22.pluginName = 'demo2';\n    creator22.meta = {\n      preferenceDeclaration: {\n        title: 'demo1的的参数定义',\n        properties: [\n          {\n            key: 'key1',\n            type: 'string',\n            description: 'this is description for key1',\n          },\n        ],\n      },\n    };\n    pluginManager.register(creator2);\n    pluginManager.register(creator22);\n    expect(mockFnForCtx).toHaveBeenCalledTimes(1);\n\n    await pluginManager.init(mockPreference);\n    // creator2 only get excuted once\n    expect(mockFnForCtx).toHaveBeenCalledTimes(1);\n\n    const [expectedCtx, expectedOptions] = mockFnForCtx.mock.calls[0];\n    expect(expectedCtx).toHaveProperty('preference');\n\n    // test normal case\n    expect(expectedCtx.preference.getPreferenceValue('key1', 'default')).toBe('value for key1');\n\n    // test default value logic\n    expect(expectedCtx.preference.getPreferenceValue('key4', 'default for key4')).toBe(\n      'default for key4',\n    );\n\n    // test undeclared key\n    expect(expectedCtx.preference.getPreferenceValue('key5', 'default for key5')).toBeUndefined();\n\n    // no preference defined\n    const [expectedCtx2] = mockFnForCtx2.mock.calls[0];\n    expect(expectedCtx2.preference.getPreferenceValue('key1')).toBeUndefined();\n  });\n\n  it('注册插件，没有填写 pluginName，默认值为 anonymous', async () => {\n    const mockFn = jest.fn();\n\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      return {\n        name: 'xxx',\n        init: () => mockFn('anonymous'),\n      };\n    };\n    await pluginManager.register(creator2);\n    expect(pluginManager.get('anonymous')).toBeUndefined();\n  });\n\n  it('自定义/扩展 plugin context', async () => {\n    const mockFn = jest.fn();\n    const mockFn2 = jest.fn();\n\n    const creator2 = (ctx: IPublicModelPluginContext) => {\n      mockFn2(ctx);\n      return {\n        init: () => mockFn('anonymous'),\n      };\n    };\n    creator2.pluginName = 'yyy';\n    editor.set('enhancePluginContextHook', (originalContext) => {\n      originalContext.newProp = 1;\n    });\n    await pluginManager.register(creator2);\n    const [expectedCtx] = mockFn2.mock.calls[0];\n    expect(expectedCtx).toHaveProperty('newProp');\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/plugin/plugin-utils.test.ts",
    "content": "import '../fixtures/window';\nimport { isValidPreferenceKey, filterValidOptions } from '../../src/plugin/plugin-utils';\n\ndescribe('plugin utils 测试', () => {\n  it('isValidPreferenceKey', () => {\n    expect(isValidPreferenceKey('x')).toBeFalsy();\n    expect(isValidPreferenceKey('x', { properties: {} })).toBeFalsy();\n    expect(isValidPreferenceKey('x', { properties: 1 })).toBeFalsy();\n    expect(isValidPreferenceKey('x', { properties: 'str' })).toBeFalsy();\n    expect(isValidPreferenceKey('x', { properties: [] })).toBeFalsy();\n    expect(\n      isValidPreferenceKey('x', {\n        title: 'title',\n        properties: [\n          {\n            key: 'y',\n            type: 'string',\n            description: 'x desc',\n          },\n        ],\n      }),\n    ).toBeFalsy();\n    expect(\n      isValidPreferenceKey('x', {\n        title: 'title',\n        properties: [\n          {\n            key: 'x',\n            type: 'string',\n            description: 'x desc',\n          },\n        ],\n      }),\n    ).toBeTruthy();\n  });\n\n  it('filterValidOptions', () => {\n    const mockDeclaration = {\n      title: 'title',\n      properties: [\n        {\n          key: 'x',\n          type: 'string',\n          description: 'x desc',\n        },\n        {\n          key: 'y',\n          type: 'string',\n          description: 'y desc',\n        },\n        {\n          key: 'z',\n          type: 'string',\n          description: 'z desc',\n        },\n      ],\n    };\n\n    expect(filterValidOptions()).toBeUndefined();\n    expect(filterValidOptions(1)).toBe(1);\n    expect(filterValidOptions({\n      x: 1,\n      y: 2,\n    }, mockDeclaration)).toEqual({\n      x: 1,\n      y: 2,\n    });\n    expect(filterValidOptions({\n      x: 1,\n      y: undefined,\n    }, mockDeclaration)).toEqual({\n      x: 1,\n    });\n    expect(filterValidOptions({\n      x: 1,\n      z: null,\n    }, mockDeclaration)).toEqual({\n      x: 1,\n    });\n    expect(filterValidOptions({\n      a: 1,\n    }, mockDeclaration)).toEqual({\n    });\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/plugin/sequencify.test.ts",
    "content": "import sequencify, { sequence } from '../../src/plugin/sequencify';\n\ndescribe('sequence', () => {\n  it('handles tasks with no dependencies', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: [] },\n      task2: { name: 'Task 2', dep: [] }\n    };\n    const results = [];\n    const missing = [];\n    const recursive = [];\n    sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest: [] });\n\n    expect(results).toEqual(['task1', 'task2']);\n    expect(missing).toEqual([]);\n    expect(recursive).toEqual([]);\n  });\n\n  it('correctly orders tasks based on dependencies', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: [] },\n      task2: { name: 'Task 2', dep: ['task1'] }\n    };\n    const results = [];\n    const missing = [];\n    const recursive = [];\n    sequence({ tasks, names: ['task2', 'task1'], results, missing, recursive, nest: [] });\n\n    expect(results).toEqual(['task1', 'task2']);\n    expect(missing).toEqual([]);\n    expect(recursive).toEqual([]);\n  });\n\n  it('identifies missing tasks', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: [] }\n    };\n    const results = [];\n    const missing = [];\n    const recursive = [];\n    const nest = []\n    sequence({ tasks, names: ['task2'], results, missing, recursive, nest });\n\n    expect(results).toEqual(['task2']);\n    expect(missing).toEqual(['task2']);\n    expect(recursive).toEqual([]);\n    expect(nest).toEqual([]);\n  });\n\n  it('detects recursive dependencies', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: ['task2'] },\n      task2: { name: 'Task 2', dep: ['task1'] }\n    };\n    const results = [];\n    const missing = [];\n    const recursive = [];\n    const nest = []\n    sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest });\n\n    expect(results).toEqual(['task1', 'task2', 'task1']);\n    expect(missing).toEqual([]);\n    expect(recursive).toEqual([['task1', 'task2', 'task1']]);\n    expect(nest).toEqual([]);\n  });\n});\n\ndescribe('sequence', () => {\n\n  it('should return tasks in sequence without dependencies', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: [] },\n      task2: { name: 'Task 2', dep: [] },\n      task3: { name: 'Task 3', dep: [] }\n    };\n    const names = ['task1', 'task2', 'task3'];\n    const expected = {\n      sequence: ['task1', 'task2', 'task3'],\n      missingTasks: [],\n      recursiveDependencies: []\n    };\n    expect(sequencify(tasks, names)).toEqual(expected);\n  });\n\n  it('should handle tasks with dependencies', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: [] },\n      task2: { name: 'Task 2', dep: ['task1'] },\n      task3: { name: 'Task 3', dep: ['task2'] }\n    };\n    const names = ['task3', 'task2', 'task1'];\n    const expected = {\n      sequence: ['task1', 'task2', 'task3'],\n      missingTasks: [],\n      recursiveDependencies: []\n    };\n    expect(sequencify(tasks, names)).toEqual(expected);\n  });\n\n  it('should identify missing tasks', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: [] },\n      task2: { name: 'Task 2', dep: ['task3'] } // task3 is missing\n    };\n    const names = ['task1', 'task2'];\n    const expected = {\n      sequence: [],\n      missingTasks: ['task2.task3'],\n      recursiveDependencies: []\n    };\n    expect(sequencify(tasks, names)).toEqual(expected);\n  });\n\n  it('should detect recursive dependencies', () => {\n    const tasks = {\n      task1: { name: 'Task 1', dep: ['task2'] },\n      task2: { name: 'Task 2', dep: ['task1'] } // Recursive dependency\n    };\n    const names = ['task1', 'task2'];\n    const expected = {\n      sequence: [],\n      missingTasks: [],\n      recursiveDependencies: [['task1', 'task2', 'task1']]\n    };\n    expect(sequencify(tasks, names)).toEqual(expected);\n  });\n\n});"
  },
  {
    "path": "packages/designer/tests/project/project-methods.test.ts",
    "content": "import '../fixtures/window';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../src/project/project';\nimport { DocumentModel } from '../../src/document/document-model';\nimport { Designer } from '../../src/designer/designer';\nimport formSchema from '../fixtures/schema/form';\nimport { shellModelFactory } from '../../../engine/src/modules/shell-model-factory';\n\ndescribe.only('Project 方法测试', () => {\n  let editor: Editor;\n  let designer: Designer;\n  let project: Project;\n  let doc: DocumentModel;\n\n  beforeEach(() => {\n    editor = new Editor();\n    designer = new Designer({ editor, shellModelFactory });\n    project = designer.project;\n    doc = new DocumentModel(project, formSchema);\n  });\n\n  afterEach(() => {\n    project.unload();\n    designer.purge();\n    editor = null;\n    designer = null;\n    project = null;\n  });\n\n  it('simulator', () => {\n    const mockSimulator = { isSimulator: true, a: 1 };\n    project.mountSimulator(mockSimulator);\n    expect(project.simulator).toEqual(mockSimulator);\n  });\n\n  it('config / get / set', () => {\n    const mockConfig = { version: '1.0.0', componentsTree: [] };\n    project.config = mockConfig;\n    expect(project.config).toEqual(mockConfig);\n    const mockConfig2 = { version: '2.0.0', componentsTree: [] };\n    project.set('config', mockConfig2);\n    expect(project.get('config')).toEqual(mockConfig2);\n\n    project.set('version', '2.0.0');\n    expect(project.get('version')).toBe('2.0.0');\n  });\n\n  it('load', () => {\n    project.load({\n      componentsTree: [{\n        componentName: 'Page',\n        fileName: 'f1',\n      }],\n    }, 'f1');\n    expect(project.currentDocument?.fileName).toBe('f1');\n  });\n\n  it.skip('setSchema', () => {\n    project.load({\n      componentsTree: [{\n        componentName: 'Page',\n        fileName: 'f1',\n      }],\n    }, true);\n    project.setSchema({\n      componentsTree: [{\n        componentName: 'Page',\n        props: { a: 1 },\n      }],\n    });\n    expect(project.currentDocument?.rootNode?.propsData).toEqual({ a: 1 });\n  });\n\n  it('open / getDocument / checkExclusive', () => {\n    project.load({\n      componentsTree: [{\n        componentName: 'Page',\n        fileName: 'f1',\n      }],\n    });\n    const doc1 = project.createDocument({\n      componentName: 'Page',\n      fileName: 'f2',\n    });\n    const doc2 = project.createDocument({\n      componentName: 'Page',\n      fileName: 'f3',\n    });\n\n    project.open();\n\n    project.open('f2');\n    expect(project.currentDocument).toBe(doc1);\n    project.open('f3');\n    expect(project.currentDocument).toBe(doc2);\n\n    project.open('f1');\n    expect(project.currentDocument?.fileName).toBe('f1');\n\n    expect(project.open('not-existing')).toBeNull();\n\n    project.open(doc2);\n    expect(project.currentDocument).toBe(doc2);\n\n    const doc3 = project.open({\n      componentName: 'Page',\n      fileName: 'f4',\n    });\n    expect(project.currentDocument).toBe(doc3);\n    expect(project.documents.length).toBe(4);\n\n    expect(project.getDocument(project.currentDocument?.id)).toBe(doc3);\n    expect(project.getDocumentByFileName(project.currentDocument?.fileName)).toBe(doc3);\n    expect(project.getDocumentByFileName('unknown')).toBeNull();\n    expect(project.checkExclusive(project.currentDocument));\n\n    expect(project.documents[0].opened).toBeTruthy();\n    expect(project.documents[1].opened).toBeTruthy();\n    expect(project.documents[2].opened).toBeTruthy();\n    expect(project.documents[3].opened).toBeTruthy();\n    expect(project.documents[0].suspensed).toBeTruthy();\n    expect(project.documents[1].suspensed).toBeTruthy();\n    expect(project.documents[2].suspensed).toBeTruthy();\n    expect(project.documents[3].suspensed).toBeFalsy();\n\n    project.closeOthers(project.currentDocument);\n    expect(project.documents[0].opened).toBeFalsy();\n    expect(project.documents[1].opened).toBeFalsy();\n    expect(project.documents[2].opened).toBeFalsy();\n    expect(project.documents[3].opened).toBeTruthy();\n    expect(project.documents[0].suspensed).toBeTruthy();\n    expect(project.documents[1].suspensed).toBeTruthy();\n    expect(project.documents[2].suspensed).toBeTruthy();\n    expect(project.documents[3].suspensed).toBeFalsy();\n  });\n\n  it('removeDocument', () => {\n    const doc1 = project.createDocument({\n      componentName: 'Page',\n      fileName: 'f1',\n    });\n    project.removeDocument({});\n    expect(project.documents.length).toBe(1);\n  });\n\n  it('simulatorProps', () => {\n    designer._simulatorProps = { a: 1 };\n    expect(designer.simulatorProps.a).toBe(1);\n    designer._simulatorProps = () => ({ a: 1 });\n    expect(designer.simulatorProps.a).toBe(1);\n  });\n\n  it('onCurrentDocumentChange', () => {\n    const mockFn = jest.fn();\n    const off = project.onCurrentDocumentChange(mockFn);\n\n    project.open({\n      componentName: 'Page',\n    });\n\n    expect(mockFn).toHaveBeenCalled();\n\n    off();\n    mockFn.mockClear();\n    project.open({\n      componentName: 'Page',\n    });\n    expect(mockFn).not.toHaveBeenCalled();\n  });\n\n  it('setRendererReady / onRendererReady', () => {\n    const mockFn = jest.fn();\n    const off = project.onRendererReady(mockFn);\n    project.setRendererReady({ a: 1 });\n    expect(mockFn).toHaveBeenCalledWith({ a: 1 });\n    off();\n    mockFn.mockClear();\n    project.setRendererReady({ a: 1 });\n    expect(mockFn).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/project/project.test.ts",
    "content": "import set from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport '../fixtures/window';\nimport { Editor } from '@alilc/lowcode-editor-core';\nimport { Project } from '../../src/project/project';\nimport { Designer } from '../../src/designer/designer';\nimport formSchema from '../fixtures/schema/form';\nimport { getIdsFromSchema, getNodeFromSchemaById } from '../utils';\n\nconst mockCreateSettingEntry = jest.fn();\njest.mock('../../src/designer/designer', () => {\n  return {\n    Designer: jest.fn().mockImplementation(() => {\n      return {\n        getComponentMeta() {\n          return {\n            getMetadata() {\n              return { configure: { advanced: null } };\n            },\n            get advanced() {\n              return {};\n            },\n          };\n        },\n        transformProps(props) { return props; },\n        createSettingEntry: mockCreateSettingEntry,\n        postEvent() {},\n      };\n    }),\n  };\n});\n\nlet designer = null;\nbeforeAll(() => {\n  designer = new Designer({});\n  designer.editor = new Editor();\n});\n\ndescribe('schema 生成节点模型测试', () => {\n  describe('block ❌ | component ❌ | slot ❌', () => {\n    beforeEach(() => {\n      mockCreateSettingEntry.mockClear();\n    });\n\n    it('基本的节点模型初始化，模型导出，初始化传入 schema', () => {\n      const project = new Project(designer, {\n        componentsTree: [\n          formSchema,\n        ],\n      });\n      project.open();\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      expect(nodesMap.size).toBe(expectedNodeCnt);\n      ids.forEach(id => {\n        expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);\n      });\n\n      const exportSchema = currentDocument?.export(1);\n      expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);\n      nodesMap.forEach(node => {\n        // 触发 getter\n        node.settingEntry;\n      });\n      expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);\n    });\n\n    it('onSimulatorReady works', () => {\n      const project = new Project(designer, {\n        componentsTree: [\n          formSchema,\n        ],\n      });\n      project.open();\n      expect(project).toBeTruthy();\n      const mockCallback = jest.fn();\n      const removeListener = project.onSimulatorReady(mockCallback);\n      project.mountSimulator(undefined);\n      expect(mockCallback).toBeCalled();\n      removeListener();\n    });\n\n    it('open doc when doc is blank', () => {\n      const project = new Project(designer);\n      project.open();\n      expect(project).toBeTruthy();\n      const blankDoc = project.documents[0];\n      expect(blankDoc).toBeTruthy();\n      // 触发保存\n      blankDoc.history.savePoint();\n      expect(blankDoc.isModified()).toBeFalsy();\n      expect(blankDoc.isBlank()).toBeTruthy();\n\n      //二次打开doc，会使用前面那个\n      const openedDoc = project.open();\n      expect(openedDoc).toBe(blankDoc);\n    });\n\n    it('load schema with autoOpen === true', () => {\n      const project = new Project(designer);\n      expect(project).toBeTruthy();\n      // trigger autoOpen case\n      project.load({\n        componentsTree: [\n          formSchema,\n        ],\n      }, true);\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      expect(nodesMap.size).toBe(expectedNodeCnt);\n      ids.forEach(id => {\n        expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);\n      });\n\n      const exportSchema = currentDocument?.export(1);\n      expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);\n      nodesMap.forEach(node => {\n        // 触发 getter\n        node.settingEntry;\n      });\n      expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);\n    });\n    it('load schema with autoOpen === true, and config contains layout.props.tabBar.item', () => {\n      const project = new Project(designer);\n      expect(project).toBeTruthy();\n      // trigger autoOpen case\n      project.load({\n        componentsTree: [\n          {\n            ...formSchema,\n            fileName: 'demoFile1',\n          },\n          {\n            ...formSchema,\n            fileName: 'demoFile2',\n          }\n        ],\n        config: {\n          layout: {\n            props: {\n              tabBar: {\n                items: [\n                  {\n                    path: '/demoFile2',\n                  }\n                ],\n              }\n            }\n          }\n        }\n      }, true);\n      const { currentDocument } = project;\n      expect(currentDocument.fileName).toBe('demoFile2');\n    });\n\n    it('load schema with autoOpen === true', () => {\n      const project = new Project(designer);\n      expect(project).toBeTruthy();\n      // trigger autoOpen case\n      project.load({\n        componentsTree: [\n          {\n            ...formSchema,\n            fileName: 'demoFile1',\n          },\n          {\n            ...formSchema,\n            fileName: 'demoFile2',\n          }\n        ],\n      }, 'demoFile2');\n      const { currentDocument } = project;\n      expect(currentDocument.fileName).toBe('demoFile2');\n    });\n\n\n    it('setSchema works', () => {\n      const project = new Project(designer);\n      project.open();\n      expect(project).toBeTruthy();\n      project.setSchema({\n        componentsTree: [\n          {\n            ...formSchema,\n            fileName: 'demoFile1',\n          },\n        ],\n      });\n      const { currentDocument } = project;\n      expect(currentDocument.fileName).toBe('demoFile1');\n    });\n\n    it('基本的节点模型初始化，模型导出，project.open 传入 schema', () => {\n      const project = new Project(designer);\n      project.open(formSchema);\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument;\n      const ids = getIdsFromSchema(formSchema);\n      const expectedNodeCnt = ids.length;\n      expect(nodesMap.size).toBe(expectedNodeCnt);\n      ids.forEach(id => {\n        expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);\n      });\n\n      const exportSchema = currentDocument?.export(1);\n      expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);\n      nodesMap.forEach(node => {\n        // 触发 getter\n        node.settingEntry;\n      });\n      expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);\n    });\n\n    it('project 卸载所有 document - unload()', () => {\n      const project = new Project(designer);\n      project.open(formSchema);\n      expect(project).toBeTruthy();\n      const { currentDocument, documents } = project;\n\n      expect(documents).toHaveLength(1);\n      expect(currentDocument).toBe(documents[0]);\n\n      project.unload();\n\n      expect(documents).toHaveLength(0);\n    });\n\n    it('project 卸载指定 document - removeDocument()', () => {\n      const project = new Project(designer);\n      project.open(formSchema);\n      expect(project).toBeTruthy();\n      const { currentDocument, documents } = project;\n\n      expect(documents).toHaveLength(1);\n      expect(currentDocument).toBe(documents[0]);\n\n      project.removeDocument(currentDocument);\n\n      expect(documents).toHaveLength(0);\n    });\n\n    it('get unknown document', () => {\n      const project = new Project(designer);\n      project.open(formSchema);\n      expect(project).toBeTruthy();\n      expect(project.getDocument('unknownId')).toBeNull();\n    });\n\n    it('get set i18n works', () => {\n      const project = new Project(designer);\n      project.open(formSchema);\n      expect(project).toBeTruthy();\n\n      project.i18n = formSchema.i18n;\n      expect(project.i18n).toStrictEqual(formSchema.i18n);\n      project.i18n = null;\n      expect(project.i18n).toStrictEqual({});\n\n      project.set('i18n', formSchema.i18n);\n      expect(project.get('i18n')).toStrictEqual(formSchema.i18n);\n      project.set('i18n', null);\n      expect(project.get('i18n')).toStrictEqual({});\n    });\n  });\n\n  describe('block ❌ | component ❌ | slot ✅', () => {\n    it('基本的节点模型初始化，模型导出，初始化传入 schema', () => {\n      const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title.type', 'JSSlot');\n      const project = new Project(designer, {\n        componentsTree: [\n          formSchemaWithSlot,\n        ],\n      });\n      project.open();\n      expect(project).toBeTruthy();\n      const { currentDocument } = project;\n      const { nodesMap } = currentDocument!;\n      const ids = getIdsFromSchema(formSchema);\n      // 目前每个 slot 会新增（1 + children.length）个节点\n      const expectedNodeCnt = ids.length + 2;\n      expect(nodesMap.size).toBe(expectedNodeCnt);\n      // PageHeader\n      expect(nodesMap.get('node_k1ow3cbd').slots).toHaveLength(1);\n    });\n  });\n\n  describe.skip('多 document 测试', () => {\n\n  });\n});\n"
  },
  {
    "path": "packages/designer/tests/utils/bom.ts",
    "content": "import { getMockRenderer } from './renderer';\n\ninterface MockDocument extends Document {\n  // open(): any;\n  // write(): any;\n  // close(): any;\n  // addEventListener(): any;\n  // removeEventListener(): any;\n  triggerEventListener(): any;\n  // createElement(): any;\n  // appendChild(): any;\n  // removeChild(): any;\n}\n\n\nconst eventsMap : Map<string, Set<Function>> = new Map<string, Set<Function>>();\nconst mockRemoveAttribute = jest.fn();\nconst mockAddEventListener = jest.fn((eventName: string, cb) => {\n  if (!eventsMap.has(eventName)) {\n    eventsMap.set(eventName, new Set([cb]));\n    return;\n  }\n  eventsMap.get(eventName)!.add(cb);\n});\n\nconst mockRemoveEventListener = jest.fn((eventName: string, cb) => {\n  if (!eventsMap.has(eventName)) return;\n  if (!cb) {\n    eventsMap.delete(eventName);\n    return;\n  }\n  eventsMap.get(eventName)?.delete(cb);\n});\n\nconst mockTriggerEventListener = jest.fn((eventName: string, data: any, context: object = {}) => {\n  if (!eventsMap.has(eventName)) return;\n  for (const cb of eventsMap.get(eventName)) {\n    cb.call(context, data);\n  }\n});\n\nconst mockCreateElement = jest.fn((tagName) => {\n  return {\n    style: {},\n    appendChild() {},\n    addEventListener: mockAddEventListener,\n    removeEventListener: mockRemoveEventListener,\n    triggerEventListener: mockTriggerEventListener,\n    removeAttribute: mockRemoveAttribute,\n  };\n});\n\nexport function getMockDocument(): MockDocument {\n  return {\n    open() {},\n    write() {},\n    close() {},\n    addEventListener: mockAddEventListener,\n    removeEventListener: mockRemoveEventListener,\n    triggerEventListener: mockTriggerEventListener,\n    createElement: mockCreateElement,\n    removeChild() {},\n    body: { appendChild() {}, removeChild() {} },\n  };\n}\n\nexport function getMockWindow(doc?: MockDocument) {\n  return {\n    SimulatorRenderer: getMockRenderer(),\n    addEventListener: mockAddEventListener,\n    removeEventListener: mockRemoveEventListener,\n    triggerEventListener: mockTriggerEventListener,\n    document: doc || getMockDocument(),\n  };\n}\n\nexport function clearEventsMap() {\n  eventsMap.clear();\n}\n\nexport function getMockElement(tagName, options = {}) {\n  const elem = document.createElement(tagName);\n  let {\n    width = 0,\n    height = 0,\n    top = 0,\n    bottom = 0,\n    left = 0,\n    right = 0,\n  } = options;\n  elem.getBoundingClientRect = () => {\n    return {\n      width,\n      height,\n      top,\n      bottom,\n      left,\n      right,\n    };\n  };\n  elem.setWidth = (newWidth) => {\n    width = newWidth;\n  };\n  elem.setHeight = (newHeight) => {\n    height = newHeight;\n  };\n  // console.log(elem.ownerDocument);\n  // elem.ownerDocument = document;\n  // elem.ownerDocument.defaultView = window;\n  return elem;\n}\n"
  },
  {
    "path": "packages/designer/tests/utils/event.ts",
    "content": "export function getMockEvent(target, options) {\n  return {\n    target,\n    preventDefault() {},\n    stopPropagation() {},\n    ...options,\n  };\n}\n"
  },
  {
    "path": "packages/designer/tests/utils/index.ts",
    "content": "export { getIdsFromSchema, getNodeFromSchemaById } from '@alilc/lowcode-test-mate/es/utils';\nexport * from './bom';\nexport * from './event';\nexport * from './renderer';\nexport * from './misc';\n"
  },
  {
    "path": "packages/designer/tests/utils/misc.ts",
    "content": "import lodashSet from 'lodash/set';\n\nexport function set(obj: any, path: any, val: any) {\n  if (typeof path === 'string' && path.startsWith('prototype')) {\n    const segs = path.split('.');\n    let acc = obj;\n    segs.forEach((seg, idx) => {\n      if (idx !== segs.length - 1) {\n        acc[seg] = acc[seg] || {};\n        acc = acc[seg];\n      } else {\n        acc[seg] = val;\n      }\n    });\n  }\n  return lodashSet(obj, path, val);\n}\n\nexport function delay(ms) {\n  return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport function delayObxTick() {\n  return delay(100);\n}\n"
  },
  {
    "path": "packages/designer/tests/utils/renderer.ts",
    "content": "export function getMockRenderer() {\n  return {\n    isSimulatorRenderer: true,\n    run() {\n      // console.log('renderer run');\n    },\n  };\n}\n"
  },
  {
    "path": "packages/designer/tests/utils-ut/invariant.test.ts",
    "content": "// @ts-nocheck\nimport { invariant } from '../../src/utils/invariant';\n\nit('invariant', () => {\n  expect(() => invariant(true)).not.toThrow();\n  expect(() => invariant(false, 'abc', 'xxx')).toThrow(/Invariant failed:/);\n  expect(() => invariant(false, 'abc')).toThrow(/Invariant failed:/);\n});"
  },
  {
    "path": "packages/designer/tests/utils-ut/misc.test.ts",
    "content": "// @ts-nocheck\nimport { isElementNode, isDOMNodeVisible, normalizeTriggers, makeEventsHandler } from '../../src/utils/misc';\n\nit('isElementNode', () => {\n  expect(isElementNode(document.createElement('div'))).toBeTruthy();\n  expect(isElementNode(1)).toBeFalsy();\n});\n\n/**\n * const domNodeRect = domNode.getBoundingClientRect();\n  const { width, height } = viewport.contentBounds;\n  const { left, right, top, bottom, width: nodeWidth, height: nodeHeight } = domNodeRect;\n  return (\n    left >= -nodeWidth &&\n    top >= -nodeHeight &&\n    bottom <= height + nodeHeight &&\n    right <= width + nodeWidth\n  );\n */\n\nconst genMockNode = ({ left, right, top, bottom, width, height }) => {\n  return { getBoundingClientRect: () => {\n    if (width === undefined || height === undefined) throw new Error('width and height is required.');\n    const base = { width, height };\n    let coordinate = {};\n    if (left !== undefined) {\n      coordinate = top !== undefined ? {\n        left,\n        right: left + width,\n        top,\n        bottom: top + height,\n      } : {\n        left,\n        right: left + width,\n        bottom,\n        top: bottom - height,\n      }\n    } else if (right !== undefined) {\n      coordinate = top !== undefined ? {\n        left: right - width,\n        right,\n        top,\n        bottom: top + height,\n      } : {\n        left: right - width,\n        right,\n        bottom,\n        top: bottom - height,\n      }\n    }\n    return { ...base, ...coordinate };\n  } };\n};\nconst mockViewport = {\n  contentBounds: {\n    width: 300,\n    height: 300,\n  },\n};\ndescribe('isDOMNodeVisible', () => {\n  it('isDOMNodeVisible', () => {\n    expect(\n      isDOMNodeVisible(\n        genMockNode({\n          width: 100,\n          height: 100,\n          left: 0,\n          top: 0,\n        }),\n        mockViewport,\n      ),\n    ).toBeTruthy();\n\n    expect(\n      isDOMNodeVisible(\n        genMockNode({\n          width: 100,\n          height: 100,\n          left: -100,\n          top: 0,\n        }),\n        mockViewport,\n      ),\n    ).toBeTruthy();\n\n    expect(\n      isDOMNodeVisible(\n        genMockNode({\n          width: 100,\n          height: 100,\n          left: 50,\n          top: 50,\n        }),\n        mockViewport,\n      ),\n    ).toBeTruthy();\n\n    // 左侧出界了\n    expect(\n      isDOMNodeVisible(\n        genMockNode({\n          width: 100,\n          height: 100,\n          left: -101,\n          top: 0,\n        }),\n        mockViewport,\n      ),\n    ).toBeFalsy();\n\n    // 右侧出界了\n    expect(\n      isDOMNodeVisible(\n        genMockNode({\n          width: 100,\n          height: 100,\n          right: 401,\n          top: 0,\n        }),\n        mockViewport,\n      ),\n    ).toBeFalsy();\n\n    // 上侧出界了\n    expect(\n      isDOMNodeVisible(\n        genMockNode({\n          width: 100,\n          height: 100,\n          left: 50,\n          top: -101,\n        }),\n        mockViewport,\n      ),\n    ).toBeFalsy();\n\n    // 下侧出界了\n    expect(\n      isDOMNodeVisible(\n        genMockNode({\n          width: 100,\n          height: 100,\n          left: 50,\n          bottom: 401,\n        }),\n        mockViewport,\n      ),\n    ).toBeFalsy();\n  });\n});\n\nit('normalizeTriggers', () => {\n  expect(normalizeTriggers(['n', 'w'])).toEqual(['N', 'W']);\n});\n\nit('makeEventsHandler', () => {\n  const sensor = { contentDocument: document };\n  // no contentDocument\n  const sensor2 = {};\n  const bind = makeEventsHandler({ view: { document } } as any, [sensor, sensor2]);\n  const fn = jest.fn();\n  bind((doc) => fn(doc));\n  expect(fn).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "packages/designer/tests/utils-ut/slot.test.ts",
    "content": "// @ts-nocheck\nimport { includeSlot, removeSlot } from '../../src/utils/slot';\n\nconst genGetExtraProp = (val: string) => () => {\n  return {\n    getAsString() {\n      return val;\n    },\n  };\n};\n\nconst remove = () => {};\n\nconst mockNode = {\n  slots: [{\n    getExtraProp: genGetExtraProp('haha'),\n    remove,\n  }, {\n    getExtraProp: genGetExtraProp('heihei'),\n    remove,\n  }]\n};\n\n// 没有 slots\nconst mockNode2 = {};\n\nit('includeSlot', () => {\n  expect(includeSlot(mockNode, 'haha')).toBeTruthy();\n  expect(includeSlot(mockNode, 'heihei')).toBeTruthy();\n  expect(includeSlot(mockNode, 'xixi')).toBeFalsy();\n  expect(includeSlot(mockNode2, 'xixi')).toBeFalsy();\n});\n\nit('removeSlot', () => {\n  expect(removeSlot(mockNode, 'xixi')).toBeFalsy();\n  expect(mockNode.slots).toHaveLength(2);\n  expect(removeSlot(mockNode, 'haha')).toBeTruthy();\n  expect(mockNode.slots).toHaveLength(1);\n  expect(removeSlot(mockNode, 'heihei')).toBeTruthy();\n  expect(mockNode.slots).toHaveLength(0);\n\n  expect(removeSlot(mockNode2, 'xixi')).toBeFalsy();\n});\n"
  },
  {
    "path": "packages/designer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"types\": [\"node\",\"jest\"]\n  },\n  \"include\": [\n    \"./src/\",\n    \"./tests/\"\n  ],\n  \"exclude\": [\"**/lib\", \"**/es\", \"node_modules\"]\n}\n"
  },
  {
    "path": "packages/editor-core/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"build-plugin-fusion\",\n    \"./build.plugin.js\"\n  ]\n}\n"
  },
  {
    "path": "packages/editor-core/build.plugin.js",
    "content": "const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');\n\nmodule.exports = ({ onGetWebpackConfig }) => {\n  onGetWebpackConfig((config) => {\n    config.resolve\n      .plugin('tsconfigpaths')\n      .use(TsconfigPathsPlugin, [{\n        configFile: './tsconfig.json',\n      }]);\n  });\n};\n"
  },
  {
    "path": "packages/editor-core/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ],\n  \"babelPlugins\": [\n    [\"@babel/plugin-proposal-private-property-in-object\", { \"loose\": true }]\n  ]\n}\n"
  },
  {
    "path": "packages/editor-core/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: false,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    '!src/**/*.d.ts',\n    '!src/icons/**',\n    '!src/locale/**',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/editor-core/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-editor-core\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Core Api for Ali lowCode engine\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"scripts\": {\n    \"build\": \"build-scripts build\",\n    \"test\": \"build-scripts test --config build.test.json\",\n    \"test:cov\": \"build-scripts test --config build.test.json --jest-coverage\"\n  },\n  \"dependencies\": {\n    \"@alifd/next\": \"^1.19.16\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"debug\": \"^4.1.1\",\n    \"intl-messageformat\": \"^9.3.1\",\n    \"lodash.get\": \"^4.4.2\",\n    \"mobx\": \"^6.3.0\",\n    \"mobx-react\": \"^7.2.0\",\n    \"power-di\": \"^2.2.4\",\n    \"react\": \"^16\",\n    \"react-dom\": \"^16.7.0\",\n    \"store\": \"^2.0.12\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@alilc/lowcode-datasource-types\": \"^1.0.1\",\n    \"@types/classnames\": \"^2.2.7\",\n    \"@types/lodash.get\": \"^4.4.6\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\",\n    \"@types/react-dom\": \"^16\",\n    \"@types/store\": \"^2.0.2\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/editor-core\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/editor-core/src/command.ts",
    "content": "import { IPublicApiCommand, IPublicEnumTransitionType, IPublicModelPluginContext, IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '@alilc/lowcode-types';\nimport { checkPropTypes } from '@alilc/lowcode-utils';\nexport interface ICommand extends Omit<IPublicApiCommand, 'registerCommand' | 'batchExecuteCommand'> {\n  registerCommand(command: IPublicTypeCommand, options?: {\n    commandScope?: string;\n  }): void;\n\n  batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[], pluginContext?: IPublicModelPluginContext): void;\n}\n\nexport interface ICommandOptions {\n  commandScope?: string;\n}\n\nexport class Command implements ICommand {\n  private commands: Map<string, IPublicTypeCommand> = new Map();\n  private commandErrors: Function[] = [];\n\n  registerCommand(command: IPublicTypeCommand, options?: ICommandOptions): void {\n    if (!options?.commandScope) {\n      throw new Error('plugin meta.commandScope is required.');\n    }\n    const name = `${options.commandScope}:${command.name}`;\n    if (this.commands.has(name)) {\n      throw new Error(`Command '${command.name}' is already registered.`);\n    }\n    this.commands.set(name, {\n      ...command,\n      name,\n    });\n  }\n\n  unregisterCommand(name: string): void {\n    if (!this.commands.has(name)) {\n      throw new Error(`Command '${name}' is not registered.`);\n    }\n    this.commands.delete(name);\n  }\n\n  executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void {\n    const command = this.commands.get(name);\n    if (!command) {\n      throw new Error(`Command '${name}' is not registered.`);\n    }\n    command.parameters?.forEach(d => {\n      if (!checkPropTypes(args[d.name], d.name, d.propType, 'command')) {\n        throw new Error(`Command '${name}' arguments ${d.name} is invalid.`);\n      }\n    });\n    try {\n      command.handler(args);\n    } catch (error) {\n      if (this.commandErrors && this.commandErrors.length) {\n        this.commandErrors.forEach(callback => callback(name, error));\n      } else {\n        throw error;\n      }\n    }\n  }\n\n  batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[], pluginContext: IPublicModelPluginContext): void {\n    if (!commands || !commands.length) {\n      return;\n    }\n    pluginContext.common.utils.executeTransaction(() => {\n      commands.forEach(command => this.executeCommand(command.name, command.args));\n    }, IPublicEnumTransitionType.REPAINT);\n  }\n\n  listCommands(): IPublicTypeListCommand[] {\n    return Array.from(this.commands.values()).map(d => {\n      const result: IPublicTypeListCommand = {\n        name: d.name,\n      };\n\n      if (d.description) {\n        result.description = d.description;\n      }\n\n      if (d.parameters) {\n        result.parameters = d.parameters;\n      }\n\n      return result;\n    });\n  }\n\n  onCommandError(callback: (name: string, error: Error) => void): void {\n    this.commandErrors.push(callback);\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/config.ts",
    "content": "import { get as lodashGet } from 'lodash';\nimport { isPlainObject } from '@alilc/lowcode-utils';\nimport {\n  IPublicTypeEngineOptions,\n  IPublicModelEngineConfig,\n  IPublicModelPreference,\n} from '@alilc/lowcode-types';\nimport { getLogger } from './utils/logger';\nimport Preference from './utils/preference';\n\nconst logger = getLogger({ level: 'log', bizName: 'config' });\n\n// this default behavior will be different later\nconst STRICT_PLUGIN_MODE_DEFAULT = true;\n\n// used in strict mode, when only options in this VALID_ENGINE_OPTIONS can be accepted\n// type and description are only used for developer`s assistance, won`t affect runtime\nconst VALID_ENGINE_OPTIONS = {\n  enableCondition: {\n    type: 'boolean',\n    description: '是否开启 condition 的能力，默认在设计器中不管 condition 是啥都正常展示',\n  },\n  designMode: {\n    type: 'string',\n    enum: ['design', 'live'],\n    default: 'design',\n    description: '设计模式，live 模式将会实时展示变量值',\n  },\n  device: {\n    type: 'string',\n    enum: ['default', 'mobile', 'any string value'],\n    default: 'default',\n    description: '设备类型',\n  },\n  deviceClassName: {\n    type: 'string',\n    default: undefined,\n    description: '指定初始化的 deviceClassName，挂载到画布的顶层节点上',\n  },\n  locale: {\n    type: 'string',\n    default: 'zh-CN',\n    description: '语言',\n  },\n  renderEnv: {\n    type: 'string',\n    enum: ['react', 'any string value'],\n    default: 'react',\n    description: '渲染器类型',\n  },\n  deviceMapper: {\n    type: 'object',\n    description: '设备类型映射器，处理设计器与渲染器中 device 的映射',\n  },\n  enableStrictPluginMode: {\n    type: 'boolean',\n    default: STRICT_PLUGIN_MODE_DEFAULT,\n    description: '开启严格插件模式，默认值：STRICT_PLUGIN_MODE_DEFAULT , 严格模式下，插件将无法通过 engineOptions 传递自定义配置项',\n  },\n  enableReactiveContainer: {\n    type: 'boolean',\n    default: false,\n    description: '开启拖拽组件时，即将被放入的容器是否有视觉反馈',\n  },\n  disableAutoRender: {\n    type: 'boolean',\n    default: false,\n    description: '关闭画布自动渲染，在资产包多重异步加载的场景有效',\n  },\n  disableDetecting: {\n    type: 'boolean',\n    default: false,\n    description: '关闭拖拽组件时的虚线响应，性能考虑',\n  },\n  customizeIgnoreSelectors: {\n    type: 'function',\n    default: undefined,\n    description: '定制画布中点击被忽略的 selectors, eg. (defaultIgnoreSelectors: string[], e: MouseEvent) => string[]',\n  },\n  disableDefaultSettingPanel: {\n    type: 'boolean',\n    default: false,\n    description: '禁止默认的设置面板',\n  },\n  disableDefaultSetters: {\n    type: 'boolean',\n    default: false,\n    description: '禁止默认的设置器',\n  },\n  enableCanvasLock: {\n    type: 'boolean',\n    default: false,\n    description: '打开画布的锁定操作',\n  },\n  enableLockedNodeSetting: {\n    type: 'boolean',\n    default: false,\n    description: '容器锁定后，容器本身是否可以设置属性，仅当画布锁定特性开启时生效',\n  },\n  stayOnTheSameSettingTab: {\n    type: 'boolean',\n    default: false,\n    description: '当选中节点切换时，是否停留在相同的设置 tab 上',\n  },\n  hideSettingsTabsWhenOnlyOneItem: {\n    type: 'boolean',\n    description: '是否在只有一个 item 的时候隐藏设置 tabs',\n  },\n  loadingComponent: {\n    type: 'ComponentType',\n    default: undefined,\n    description: '自定义 loading 组件',\n  },\n  supportVariableGlobally: {\n    type: 'boolean',\n    default: false,\n    description: '设置所有属性支持变量配置',\n  },\n  visionSettings: {\n    type: 'object',\n    description: 'Vision-polyfill settings',\n  },\n  simulatorUrl: {\n    type: 'array',\n    description: '自定义 simulatorUrl 的地址',\n  },\n  // 与 react-renderer 的 appHelper 一致，https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper\n  appHelper: {\n    type: 'object',\n    description: '定义 utils 和 constants 等对象',\n  },\n  requestHandlersMap: {\n    type: 'object',\n    description: '数据源引擎的请求处理器映射',\n  },\n  thisRequiredInJSE: {\n    type: 'boolean',\n    description: 'JSExpression 是否只支持使用 this 来访问上下文变量',\n  },\n  enableStrictNotFoundMode: {\n    type: 'boolean',\n    description: '当开启组件未找到严格模式时，渲染模块不会默认给一个容器组件',\n  },\n  focusNodeSelector: {\n    type: 'function',\n    description: '配置指定节点为根组件',\n  },\n  enableAutoOpenFirstWindow: {\n    type: 'boolean',\n    description: '应用级设计模式下，自动打开第一个窗口',\n    default: true,\n  },\n  enableWorkspaceMode: {\n    type: 'boolean',\n    description: '是否开启应用级设计模式',\n    default: false,\n  },\n  workspaceEmptyComponent: {\n    type: 'function',\n    description: '应用级设计模式下，窗口为空时展示的占位组件',\n  },\n  enableContextMenu: {\n    type: 'boolean',\n    description: '是否开启右键菜单',\n    default: false,\n  },\n  hideComponentAction: {\n    type: 'boolean',\n    description: '是否隐藏设计器辅助层',\n    default: false,\n  },\n};\n\nconst getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => {\n  if (!engineOptions || !isPlainObject(engineOptions)) {\n    return defaultValue;\n  }\n  if (engineOptions.enableStrictPluginMode === undefined\n    || engineOptions.enableStrictPluginMode === null) {\n    return defaultValue;\n  }\n  return engineOptions.enableStrictPluginMode;\n};\n\nexport interface IEngineConfig extends IPublicModelEngineConfig {\n\n  /**\n   * if engineOptions.strictPluginMode === true, only accept propertied predefined in EngineOptions.\n   *\n   * @param {IPublicTypeEngineOptions} engineOptions\n   */\n  setEngineOptions(engineOptions: IPublicTypeEngineOptions): void;\n\n  notifyGot(key: string): void;\n\n  setWait(key: string, resolve: (data: any) => void, once?: boolean): void;\n\n  delWait(key: string, fn: any): void;\n}\n\nexport class EngineConfig implements IEngineConfig {\n  private config: { [key: string]: any } = {};\n\n  private waits = new Map<\n  string,\n  Array<{\n    once?: boolean;\n    resolve: (data: any) => void;\n  }>\n  >();\n\n  /**\n   * used to store preferences\n   *\n   */\n  readonly preference: IPublicModelPreference;\n\n  constructor(config?: { [key: string]: any }) {\n    this.config = config || {};\n    this.preference = new Preference();\n  }\n\n  /**\n   * 判断指定 key 是否有值\n   * @param key\n   */\n  has(key: string): boolean {\n    return this.config[key] !== undefined;\n  }\n\n  /**\n   * 获取指定 key 的值\n   * @param key\n   * @param defaultValue\n   */\n  get(key: string, defaultValue?: any): any {\n    return lodashGet(this.config, key, defaultValue);\n  }\n\n  /**\n   * 设置指定 key 的值\n   * @param key\n   * @param value\n   */\n  set(key: string, value: any) {\n    this.config[key] = value;\n    this.notifyGot(key);\n  }\n\n  /**\n   * 批量设值，set 的对象版本\n   * @param config\n   */\n  setConfig(config: { [key: string]: any }) {\n    if (config) {\n      Object.keys(config).forEach((key) => {\n        this.set(key, config[key]);\n      });\n    }\n  }\n\n  /**\n   * if engineOptions.strictPluginMode === true, only accept propertied predefined in EngineOptions.\n   *\n   * @param {IPublicTypeEngineOptions} engineOptions\n   */\n  setEngineOptions(engineOptions: IPublicTypeEngineOptions) {\n    if (!engineOptions || !isPlainObject(engineOptions)) {\n      return;\n    }\n    const strictMode = getStrictModeValue(engineOptions, STRICT_PLUGIN_MODE_DEFAULT) === true;\n    if (strictMode) {\n      const isValidKey = (key: string) => {\n        const result = (VALID_ENGINE_OPTIONS as any)[key];\n        return !(result === undefined || result === null);\n      };\n      Object.keys(engineOptions).forEach((key) => {\n        if (isValidKey(key)) {\n          this.set(key, (engineOptions as any)[key]);\n        } else {\n          logger.warn(`failed to config ${key} to engineConfig, only predefined options can be set under strict mode, predefined options: `, VALID_ENGINE_OPTIONS);\n        }\n      });\n    } else {\n      this.setConfig(engineOptions as any);\n    }\n  }\n\n  /**\n   * 获取指定 key 的值，若此时还未赋值，则等待，若已有值，则直接返回值\n   *  注：此函数返回 Promise 实例，只会执行（fullfill）一次\n   * @param key\n   * @returns\n   */\n  onceGot(key: string): Promise<any> {\n    const val = this.config[key];\n    if (val !== undefined) {\n      return Promise.resolve(val);\n    }\n    return new Promise((resolve) => {\n      this.setWait(key, resolve, true);\n    });\n  }\n\n  /**\n   * 获取指定 key 的值，函数回调模式，若多次被赋值，回调会被多次调用\n   * @param key\n   * @param fn\n   * @returns\n   */\n  onGot(key: string, fn: (data: any) => void): () => void {\n    const val = this.config?.[key];\n    if (val !== undefined) {\n      fn(val);\n    }\n    this.setWait(key, fn);\n    return () => {\n      this.delWait(key, fn);\n    };\n  }\n\n  notifyGot(key: string): void {\n    let waits = this.waits.get(key);\n    if (!waits) {\n      return;\n    }\n    waits = waits.slice().reverse();\n    let i = waits.length;\n    while (i--) {\n      waits[i].resolve(this.get(key));\n      if (waits[i].once) {\n        waits.splice(i, 1);\n      }\n    }\n    if (waits.length > 0) {\n      this.waits.set(key, waits);\n    } else {\n      this.waits.delete(key);\n    }\n  }\n\n  setWait(key: string, resolve: (data: any) => void, once?: boolean) {\n    const waits = this.waits.get(key);\n    if (waits) {\n      waits.push({ resolve, once });\n    } else {\n      this.waits.set(key, [{ resolve, once }]);\n    }\n  }\n\n  delWait(key: string, fn: any) {\n    const waits = this.waits.get(key);\n    if (!waits) {\n      return;\n    }\n    let i = waits.length;\n    while (i--) {\n      if (waits[i].resolve === fn) {\n        waits.splice(i, 1);\n      }\n    }\n    if (waits.length < 1) {\n      this.waits.delete(key);\n    }\n  }\n\n  getPreference(): IPublicModelPreference {\n    return this.preference;\n  }\n}\n\nexport const engineConfig = new EngineConfig();\n"
  },
  {
    "path": "packages/editor-core/src/di/index.ts",
    "content": "export * from './setter';\nexport * from './ioc-context';\nexport * from '../widgets/tip/tip';\n"
  },
  {
    "path": "packages/editor-core/src/di/ioc-context.ts",
    "content": "import { IocContext } from 'power-di';\n\nexport * from 'power-di';\n\nexport const globalContext = IocContext.DefaultInstance;\n"
  },
  {
    "path": "packages/editor-core/src/di/setter.ts",
    "content": "import { ReactNode } from 'react';\nimport { IPublicApiSetters, IPublicModelSettingField, IPublicTypeCustomView, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types';\nimport { createContent, isCustomView } from '@alilc/lowcode-utils';\n\nconst settersMap = new Map<string, IPublicTypeRegisteredSetter & {\n  type: string;\n}>();\nexport function registerSetter(\n  typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter },\n  setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter,\n) {\n  if (typeof typeOrMaps === 'object') {\n    Object.keys(typeOrMaps).forEach(type => {\n      registerSetter(type, typeOrMaps[type]);\n    });\n    return;\n  }\n  if (!setter) {\n    return;\n  }\n  if (isCustomView(setter)) {\n    setter = {\n      component: setter,\n      // todo: intl\n      title: (setter as any).displayName || (setter as any).name || 'CustomSetter',\n    };\n  }\n  if (!setter.initialValue) {\n    const initial = getInitialFromSetter(setter.component);\n    if (initial) {\n      setter.initialValue = (field: IPublicModelSettingField) => {\n        return initial.call(field, field.getValue());\n      };\n    }\n  }\n  settersMap.set(typeOrMaps, { type: typeOrMaps, ...setter });\n}\n\nfunction getInitialFromSetter(setter: any) {\n  return setter && (\n    setter.initial || setter.Initial\n      || (setter.type && (setter.type.initial || setter.type.Initial))\n    ) || null; // eslint-disable-line\n}\n\nexport interface ISetters extends IPublicApiSetters {\n\n}\n\nexport class Setters implements ISetters {\n  settersMap = new Map<string, IPublicTypeRegisteredSetter & {\n    type: string;\n  }>();\n\n  constructor(readonly viewName: string = 'global') {}\n\n  getSetter = (type: string): IPublicTypeRegisteredSetter | null => {\n    return this.settersMap.get(type) || null;\n  };\n\n  registerSetter = (\n    typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter },\n    setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter,\n  ) => {\n    if (typeof typeOrMaps === 'object') {\n      Object.keys(typeOrMaps).forEach(type => {\n        this.registerSetter(type, typeOrMaps[type]);\n      });\n      return;\n    }\n    if (!setter) {\n      return;\n    }\n    if (isCustomView(setter)) {\n      setter = {\n        component: setter,\n        // todo: intl\n        title: (setter as any).displayName || (setter as any).name || 'CustomSetter',\n      };\n    }\n    if (!setter.initialValue) {\n      const initial = getInitialFromSetter(setter.component);\n      if (initial) {\n        setter.initialValue = (field: IPublicModelSettingField) => {\n          return initial.call(field, field.getValue());\n        };\n      }\n    }\n    this.settersMap.set(typeOrMaps, { type: typeOrMaps, ...setter });\n  };\n\n  getSettersMap = () => {\n    return this.settersMap;\n  };\n\n  createSetterContent = (setter: any, props: Record<string, any>): ReactNode => {\n    if (typeof setter === 'string') {\n      setter = this.getSetter(setter);\n      if (!setter) {\n        return null;\n      }\n      if (setter.defaultProps) {\n        props = {\n          ...setter.defaultProps,\n          ...props,\n        };\n      }\n      setter = setter.component;\n    }\n\n    // Fusion 的表单组件都是通过 'value' in props 来判断是否使用 defaultValue\n    if ('value' in props && typeof props.value === 'undefined') {\n      delete props.value;\n    }\n\n    return createContent(setter, props);\n  };\n}"
  },
  {
    "path": "packages/editor-core/src/editor.ts",
    "content": "/* eslint-disable no-console */\n/* eslint-disable max-len */\nimport { StrictEventEmitter } from 'strict-event-emitter-types';\nimport { EventEmitter } from 'events';\nimport { EventBus, IEventBus } from './event-bus';\nimport {\n  IPublicModelEditor,\n  EditorConfig,\n  PluginClassSet,\n  IPublicTypeEditorValueKey,\n  IPublicTypeEditorGetResult,\n  HookConfig,\n  IPublicTypeComponentDescription,\n  IPublicTypeRemoteComponentDescription,\n  GlobalEvent,\n} from '@alilc/lowcode-types';\nimport { engineConfig } from './config';\nimport { globalLocale } from './intl';\nimport { obx } from './utils';\nimport { IPublicTypeAssetsJson, AssetLoader } from '@alilc/lowcode-utils';\nimport { assetsTransform } from './utils/assets-transform';\n\nEventEmitter.defaultMaxListeners = 100;\n\n// inner instance keys which should not be stored in config\nconst keyBlacklist = [\n  'designer',\n  'skeleton',\n  'currentDocument',\n  'simulator',\n  'plugins',\n  'setters',\n  'material',\n  'innerHotkey',\n  'innerPlugins',\n];\n\nconst AssetsCache: {\n  [key: string]: IPublicTypeRemoteComponentDescription;\n} = {};\n\nexport declare interface Editor extends StrictEventEmitter<EventEmitter, GlobalEvent.EventConfig> {\n  addListener(event: string | symbol, listener: (...args: any[]) => void): this;\n  once(event: string | symbol, listener: (...args: any[]) => void): this;\n  removeListener(event: string | symbol, listener: (...args: any[]) => void): this;\n  off(event: string | symbol, listener: (...args: any[]) => void): this;\n  removeAllListeners(event?: string | symbol): this;\n  setMaxListeners(n: number): this;\n  getMaxListeners(): number;\n  listeners(event: string | symbol): Function[];\n  rawListeners(event: string | symbol): Function[];\n  listenerCount(type: string | symbol): number;\n  // Added in Node 6...\n  prependListener(event: string | symbol, listener: (...args: any[]) => void): this;\n  prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;\n  eventNames(): Array<string | symbol>;\n}\n\nexport interface IEditor extends IPublicModelEditor {\n  config?: EditorConfig;\n\n  components?: PluginClassSet;\n\n  eventBus: IEventBus;\n\n  init(config?: EditorConfig, components?: PluginClassSet): Promise<any>;\n}\n\n// eslint-disable-next-line no-redeclare\nexport class Editor extends EventEmitter implements IEditor {\n\n  /**\n   * Ioc Container\n   */\n  @obx.shallow private context = new Map<IPublicTypeEditorValueKey, any>();\n\n  get locale() {\n    return globalLocale.getLocale();\n  }\n\n  config?: EditorConfig;\n\n  eventBus: EventBus;\n\n  components?: PluginClassSet;\n\n  // readonly utils = utils;\n\n  private hooks: HookConfig[] = [];\n\n  private waits = new Map<\n    IPublicTypeEditorValueKey,\n    Array<{\n      once?: boolean;\n      resolve: (data: any) => void;\n    }>\n  >();\n\n  constructor(readonly viewName: string = 'global', readonly workspaceMode: boolean = false) {\n    // eslint-disable-next-line constructor-super\n    super();\n    // set global emitter maxListeners\n    this.setMaxListeners(200);\n    this.eventBus = new EventBus(this);\n  }\n\n  get<T = undefined, KeyOrType = any>(\n      keyOrType: KeyOrType,\n    ): IPublicTypeEditorGetResult<T, KeyOrType> | undefined {\n    return this.context.get(keyOrType as any);\n  }\n\n  has(keyOrType: IPublicTypeEditorValueKey): boolean {\n    return this.context.has(keyOrType);\n  }\n\n  set(key: IPublicTypeEditorValueKey, data: any): void | Promise<void> {\n    if (key === 'assets') {\n      return this.setAssets(data);\n    }\n    // store the data to engineConfig while invoking editor.set()\n    if (!keyBlacklist.includes(key as string)) {\n      engineConfig.set(key as any, data);\n    }\n    this.context.set(key, data);\n    this.notifyGot(key);\n  }\n\n  async setAssets(assets: IPublicTypeAssetsJson) {\n    const { components } = assets;\n    if (components && components.length) {\n      const componentDescriptions: IPublicTypeComponentDescription[] = [];\n      const remoteComponentDescriptions: IPublicTypeRemoteComponentDescription[] = [];\n      components.forEach((component: any) => {\n        if (!component) {\n          return;\n        }\n        if (component.exportName && component.url) {\n          remoteComponentDescriptions.push(component);\n        } else {\n          componentDescriptions.push(component);\n        }\n      });\n      assets.components = componentDescriptions;\n      assets.componentList = assets.componentList || [];\n\n      // 如果有远程组件描述协议，则自动加载并补充到资产包中，同时出发 designer.incrementalAssetsReady 通知组件面板更新数据\n      if (remoteComponentDescriptions && remoteComponentDescriptions.length) {\n        await Promise.all(\n          remoteComponentDescriptions.map(async (component: IPublicTypeRemoteComponentDescription) => {\n            const { exportName, url, npm } = component;\n            if (!url || !exportName) {\n              return;\n            }\n            if (!AssetsCache[exportName] || !npm?.version || AssetsCache[exportName].npm?.version !== npm?.version) {\n              await (new AssetLoader()).load(url);\n            }\n            AssetsCache[exportName] = component;\n            function setAssetsComponent(component: any, extraNpmInfo: any = {}) {\n              const components = component.components;\n              assets.componentList = assets.componentList?.concat(component.componentList || []);\n              if (Array.isArray(components)) {\n                components.forEach(d => {\n                  assets.components = assets.components.concat({\n                    npm: {\n                      ...npm,\n                      ...extraNpmInfo,\n                    },\n                    ...d,\n                  } || []);\n                });\n                return;\n              }\n              if (component.components) {\n                assets.components = assets.components.concat({\n                  npm: {\n                    ...npm,\n                    ...extraNpmInfo,\n                  },\n                  ...component.components,\n                } || []);\n              }\n            }\n            function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') {\n              value.forEach((d: any, i: number) => {\n                const exportName = [preExportName, i.toString()].filter(d => !!d).join('.');\n                const subName = [preSubName, i.toString()].filter(d => !!d).join('.');\n                Array.isArray(d) ? setArrayAssets(d, exportName, subName) : setAssetsComponent(d, {\n                  exportName,\n                  subName,\n                });\n              });\n            }\n            if ((window as any)[exportName]) {\n              if (Array.isArray((window as any)[exportName])) {\n                setArrayAssets((window as any)[exportName] as any);\n              } else {\n                setAssetsComponent((window as any)[exportName] as any);\n              }\n            }\n            return (window as any)[exportName];\n          }),\n        );\n      }\n    }\n    const innerAssets = assetsTransform(assets);\n    this.context.set('assets', innerAssets);\n    this.notifyGot('assets');\n  }\n\n  onceGot<T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>(keyOrType: KeyOrType): Promise<IPublicTypeEditorGetResult<T, KeyOrType>> {\n    const x = this.context.get(keyOrType);\n    if (x !== undefined) {\n      return Promise.resolve(x);\n    }\n    return new Promise((resolve) => {\n      this.setWait(keyOrType, resolve, true);\n    });\n  }\n\n  onGot<T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>(\n    keyOrType: KeyOrType,\n    fn: (data: IPublicTypeEditorGetResult<T, KeyOrType>) => void,\n  ): () => void {\n    const x = this.context.get(keyOrType);\n    if (x !== undefined) {\n      fn(x);\n    }\n    this.setWait(keyOrType, fn);\n    return () => {\n      this.delWait(keyOrType, fn);\n    };\n  }\n\n  onChange<T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>(\n    keyOrType: KeyOrType,\n    fn: (data: IPublicTypeEditorGetResult<T, KeyOrType>) => void,\n  ): () => void {\n    this.setWait(keyOrType, fn);\n    return () => {\n      this.delWait(keyOrType, fn);\n    };\n  }\n\n  register(data: any, key?: IPublicTypeEditorValueKey): void {\n    this.context.set(key || data, data);\n    this.notifyGot(key || data);\n  }\n\n  async init(config?: EditorConfig, components?: PluginClassSet): Promise<any> {\n    this.config = config || {};\n    this.components = components || {};\n    const { hooks = [], lifeCycles } = this.config;\n\n    this.emit('editor.beforeInit');\n    const init = (lifeCycles && lifeCycles.init) || ((): void => { });\n\n    try {\n      await init(this);\n      // 注册快捷键\n      // 注册 hooks\n      this.registerHooks(hooks);\n      this.emit('editor.afterInit');\n\n      return true;\n    } catch (err) {\n      console.error(err);\n    }\n  }\n\n  destroy(): void {\n    if (!this.config) {\n      return;\n    }\n    try {\n      const { lifeCycles = {} } = this.config;\n\n      this.unregisterHooks();\n\n      if (lifeCycles.destroy) {\n        lifeCycles.destroy(this);\n      }\n    } catch (err) {\n      console.warn(err);\n    }\n  }\n\n  initHooks = (hooks: HookConfig[]) => {\n    this.hooks = hooks.map((hook) => ({\n      ...hook,\n      // 指定第一个参数为 editor\n      handler: hook.handler.bind(this, this),\n    }));\n\n    return this.hooks;\n  };\n\n  registerHooks = (hooks: HookConfig[]) => {\n    this.initHooks(hooks).forEach(({ message, type, handler }) => {\n      if (['on', 'once'].indexOf(type) !== -1) {\n        this[type]((message as any), handler);\n      }\n    });\n  };\n\n  unregisterHooks = () => {\n    this.hooks.forEach(({ message, handler }) => {\n      this.removeListener(message, handler);\n    });\n  };\n\n  private notifyGot(key: IPublicTypeEditorValueKey) {\n    let waits = this.waits.get(key);\n    if (!waits) {\n      return;\n    }\n    waits = waits.slice().reverse();\n    let i = waits.length;\n    while (i--) {\n      waits[i].resolve(this.get(key));\n      if (waits[i].once) {\n        waits.splice(i, 1);\n      }\n    }\n    if (waits.length > 0) {\n      this.waits.set(key, waits);\n    } else {\n      this.waits.delete(key);\n    }\n  }\n\n  private setWait(key: IPublicTypeEditorValueKey, resolve: (data: any) => void, once?: boolean) {\n    const waits = this.waits.get(key);\n    if (waits) {\n      waits.push({ resolve, once });\n    } else {\n      this.waits.set(key, [{ resolve, once }]);\n    }\n  }\n\n  private delWait(key: IPublicTypeEditorValueKey, fn: any) {\n    const waits = this.waits.get(key);\n    if (!waits) {\n      return;\n    }\n    let i = waits.length;\n    while (i--) {\n      if (waits[i].resolve === fn) {\n        waits.splice(i, 1);\n      }\n    }\n    if (waits.length < 1) {\n      this.waits.delete(key);\n    }\n  }\n}\n\nexport const commonEvent = new EventBus(new EventEmitter());\n"
  },
  {
    "path": "packages/editor-core/src/event-bus.ts",
    "content": "import { IPublicApiEvent } from '@alilc/lowcode-types';\nimport { Logger } from '@alilc/lowcode-utils';\nimport EventEmitter from 'events';\n\nconst logger = new Logger({ level: 'warn', bizName: 'event-bus' });\nconst moduleLogger = new Logger({ level: 'warn', bizName: 'module-event-bus' });\n\nexport interface IEventBus extends IPublicApiEvent {\n  removeListener(event: string | symbol, listener: (...args: any[]) => void): any;\n  addListener(event: string | symbol, listener: (...args: any[]) => void): any;\n  setMaxListeners(n: number): any;\n  removeAllListeners(event?: string | symbol): any;\n}\n\nexport class EventBus implements IEventBus {\n  private readonly eventEmitter: EventEmitter;\n  private readonly name?: string;\n\n  /**\n   * 内核触发的事件名\n   */\n  readonly names = [];\n\n  constructor(emitter: EventEmitter, name?: string) {\n    this.eventEmitter = emitter;\n    this.name = name;\n  }\n\n  private getMsgPrefix(type: string): string {\n    if (this.name && this.name.length > 0) {\n      return `[${this.name}][event-${type}]`;\n    } else {\n      return `[*][event-${type}]`;\n    }\n  }\n\n  private getLogger(): Logger {\n    if (this.name && this.name.length > 0) {\n      return moduleLogger;\n    } else {\n      return logger;\n    }\n  }\n\n  /**\n   * 监听事件\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  on(event: string, listener: (...args: any[]) => void): () => void {\n    this.eventEmitter.on(event, listener);\n    this.getLogger().debug(`${this.getMsgPrefix('on')} ${event}`);\n    return () => {\n      this.off(event, listener);\n    };\n  }\n\n  prependListener(event: string, listener: (...args: any[]) => void): () => void {\n    this.eventEmitter.prependListener(event, listener);\n    this.getLogger().debug(`${this.getMsgPrefix('prependListener')} ${event}`);\n    return () => {\n      this.off(event, listener);\n    };\n  }\n\n  /**\n   * 取消监听事件\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  off(event: string, listener: (...args: any[]) => void) {\n    this.eventEmitter.off(event, listener);\n    this.getLogger().debug(`${this.getMsgPrefix('off')} ${event}`);\n  }\n\n  /**\n   * 触发事件\n   * @param event 事件名称\n   * @param args 事件参数\n   * @returns\n   */\n  emit(event: string, ...args: any[]) {\n    this.eventEmitter.emit(event, ...args);\n    this.getLogger().debug(`${this.getMsgPrefix('emit')} name: ${event}, args: `, ...args);\n  }\n\n  removeListener(event: string | symbol, listener: (...args: any[]) => void): any {\n    return this.eventEmitter.removeListener(event, listener);\n  }\n\n  addListener(event: string | symbol, listener: (...args: any[]) => void): any {\n    return this.eventEmitter.addListener(event, listener);\n  }\n\n  setMaxListeners(n: number): any {\n    return this.eventEmitter.setMaxListeners(n);\n  }\n  removeAllListeners(event?: string | symbol): any {\n    return this.eventEmitter.removeAllListeners(event);\n  }\n}\n\nexport const createModuleEventBus = (moduleName: string, maxListeners?: number): IEventBus => {\n  const emitter = new EventEmitter();\n  if (maxListeners) {\n    emitter.setMaxListeners(maxListeners);\n  }\n  return new EventBus(emitter, moduleName);\n};"
  },
  {
    "path": "packages/editor-core/src/hotkey.ts",
    "content": "import { isEqual } from 'lodash';\nimport { globalContext } from './di';\nimport { IPublicTypeHotkeyCallback, IPublicTypeHotkeyCallbackConfig, IPublicTypeHotkeyCallbacks, IPublicApiHotkey } from '@alilc/lowcode-types';\n\ninterface KeyMap {\n  [key: number]: string;\n}\n\ninterface CtrlKeyMap {\n  [key: string]: string;\n}\n\ninterface ActionEvent {\n  type: string;\n}\n\ninterface HotkeyDirectMap {\n  [key: string]: IPublicTypeHotkeyCallback;\n}\n\ninterface KeyInfo {\n  key: string;\n  modifiers: string[];\n  action: string;\n}\n\ninterface SequenceLevels {\n  [key: string]: number;\n}\n\nconst MAP: KeyMap = {\n  8: 'backspace',\n  9: 'tab',\n  13: 'enter',\n  16: 'shift',\n  17: 'ctrl',\n  18: 'alt',\n  20: 'capslock',\n  27: 'esc',\n  32: 'space',\n  33: 'pageup',\n  34: 'pagedown',\n  35: 'end',\n  36: 'home',\n  37: 'left',\n  38: 'up',\n  39: 'right',\n  40: 'down',\n  45: 'ins',\n  46: 'del',\n  91: 'meta',\n  93: 'meta',\n  224: 'meta',\n};\n\nconst KEYCODE_MAP: KeyMap = {\n  106: '*',\n  107: '+',\n  109: '-',\n  110: '.',\n  111: '/',\n  186: ';',\n  187: '=',\n  188: ',',\n  189: '-',\n  190: '.',\n  191: '/',\n  192: '`',\n  219: '[',\n  220: '\\\\',\n  221: ']',\n  222: \"'\",\n};\n\nconst SHIFT_MAP: CtrlKeyMap = {\n  '~': '`',\n  '!': '1',\n  '@': '2',\n  '#': '3',\n  $: '4',\n  '%': '5',\n  '^': '6',\n  '&': '7',\n  '*': '8',\n  '(': '9',\n  ')': '0',\n  _: '-',\n  '+': '=',\n  ':': ';',\n  '\"': \"'\",\n  '<': ',',\n  '>': '.',\n  '?': '/',\n  '|': '\\\\',\n};\n\nconst SPECIAL_ALIASES: CtrlKeyMap = {\n  option: 'alt',\n  command: 'meta',\n  return: 'enter',\n  escape: 'esc',\n  plus: '+',\n  mod: /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl',\n};\n\nlet REVERSE_MAP: CtrlKeyMap;\n\n/**\n * loop through the f keys, f1 to f19 and add them to the map\n * programatically\n */\nfor (let i = 1; i < 20; ++i) {\n  MAP[111 + i] = `f${ i}`;\n}\n\n/**\n * loop through to map numbers on the numeric keypad\n */\nfor (let i = 0; i <= 9; ++i) {\n  MAP[i + 96] = String(i);\n}\n\n/**\n * takes the event and returns the key character\n */\nfunction characterFromEvent(e: KeyboardEvent): string {\n  const keyCode = e.keyCode || e.which;\n  // for keypress events we should return the character as is\n  if (e.type === 'keypress') {\n    let character = String.fromCharCode(keyCode);\n    // if the shift key is not pressed then it is safe to assume\n    // that we want the character to be lowercase.  this means if\n    // you accidentally have caps lock on then your key bindings\n    // will continue to work\n    //\n    // the only side effect that might not be desired is if you\n    // bind something like 'A' cause you want to trigger an\n    // event when capital A is pressed caps lock will no longer\n    // trigger the event.  shift+a will though.\n    if (!e.shiftKey) {\n      character = character.toLowerCase();\n    }\n    return character;\n  }\n  // for non keypress events the special maps are needed\n  if (MAP[keyCode]) {\n    return MAP[keyCode];\n  }\n  if (KEYCODE_MAP[keyCode]) {\n    return KEYCODE_MAP[keyCode];\n  }\n  // if it is not in the special map\n  // with keydown and keyup events the character seems to always\n  // come in as an uppercase character whether you are pressing shift\n  // or not.  we should make sure it is always lowercase for comparisons\n  // tips: Q29weXJpZ2h0IChjKSAyMDIwLXByZXNlbnQgQWxpYmFiYSBJbmMuIFYy\n  return String.fromCharCode(keyCode).toLowerCase();\n}\n\ninterface KeypressEvent extends KeyboardEvent {\n  type: 'keypress';\n}\n\nfunction isPressEvent(e: KeyboardEvent | ActionEvent): e is KeypressEvent {\n  return e.type === 'keypress';\n}\n\n/**\n * checks if two arrays are equal\n */\nfunction modifiersMatch(modifiers1: string[], modifiers2: string[]): boolean {\n  return modifiers1.sort().join(',') === modifiers2.sort().join(',');\n}\n\n/**\n * takes a key event and figures out what the modifiers are\n */\nfunction eventModifiers(e: KeyboardEvent): string[] {\n  const modifiers = [];\n\n  if (e.shiftKey) {\n    modifiers.push('shift');\n  }\n\n  if (e.altKey) {\n    modifiers.push('alt');\n  }\n\n  if (e.ctrlKey) {\n    modifiers.push('ctrl');\n  }\n\n  if (e.metaKey) {\n    modifiers.push('meta');\n  }\n\n  return modifiers;\n}\n\n/**\n * determines if the keycode specified is a modifier key or not\n */\nfunction isModifier(key: string): boolean {\n  return key === 'shift' || key === 'ctrl' || key === 'alt' || key === 'meta';\n}\n\n/**\n * reverses the map lookup so that we can look for specific keys\n * to see what can and can't use keypress\n *\n * @return {Object}\n */\nfunction getReverseMap(): CtrlKeyMap {\n  if (!REVERSE_MAP) {\n    REVERSE_MAP = {};\n    for (const key in MAP) {\n      // pull out the numeric keypad from here cause keypress should\n      // be able to detect the keys from the character\n      if (Number(key) > 95 && Number(key) < 112) {\n        continue;\n      }\n\n      if (MAP.hasOwnProperty(key)) {\n        REVERSE_MAP[MAP[key]] = key;\n      }\n    }\n  }\n  return REVERSE_MAP;\n}\n\n/**\n * picks the best action based on the key combination\n */\nfunction pickBestAction(key: string, modifiers: string[], action?: string): string {\n  // if no action was picked in we should try to pick the one\n  // that we think would work best for this key\n  if (!action) {\n    action = getReverseMap()[key] ? 'keydown' : 'keypress';\n  }\n  // modifier keys don't work as expected with keypress,\n  // switch to keydown\n  if (action === 'keypress' && modifiers.length) {\n    action = 'keydown';\n  }\n  return action;\n}\n\n/**\n * Converts from a string key combination to an array\n *\n * @param  {string} combination like \"command+shift+l\"\n * @return {Array}\n */\nfunction keysFromString(combination: string): string[] {\n  if (combination === '+') {\n    return ['+'];\n  }\n\n  combination = combination.replace(/\\+{2}/g, '+plus');\n  return combination.split('+');\n}\n\n/**\n * Gets info for a specific key combination\n *\n * @param combination key combination (\"command+s\" or \"a\" or \"*\")\n */\nfunction getKeyInfo(combination: string, action?: string): KeyInfo {\n  let keys: string[] = [];\n  let key = '';\n  let i: number;\n  const modifiers: string[] = [];\n\n  // take the keys from this pattern and figure out what the actual\n  // pattern is all about\n  keys = keysFromString(combination);\n\n  for (i = 0; i < keys.length; ++i) {\n    key = keys[i];\n\n    // normalize key names\n    if (SPECIAL_ALIASES[key]) {\n      key = SPECIAL_ALIASES[key];\n    }\n\n    // if this is not a keypress event then we should\n    // be smart about using shift keys\n    // this will only work for US keyboards however\n    if (action && action !== 'keypress' && SHIFT_MAP[key]) {\n      key = SHIFT_MAP[key];\n      modifiers.push('shift');\n    }\n\n    // if this key is a modifier then add it to the list of modifiers\n    if (isModifier(key)) {\n      modifiers.push(key);\n    }\n  }\n\n  // depending on what the key combination is\n  // we will try to pick the best event for it\n  action = pickBestAction(key, modifiers, action);\n\n  return {\n    key,\n    modifiers,\n    action,\n  };\n}\n\n/**\n * actually calls the callback function\n *\n * if your callback function returns false this will use the jquery\n * convention - prevent default and stop propogation on the event\n */\nfunction fireCallback(callback: IPublicTypeHotkeyCallback, e: KeyboardEvent, combo?: string, sequence?: string): void {\n  try {\n    const workspace = globalContext.get('workspace');\n    const editor = workspace.isActive ? workspace.window?.editor : globalContext.get('editor');\n    const designer = editor?.get('designer');\n    const node = designer?.currentSelection?.getNodes()?.[0];\n    const npm = node?.componentMeta?.npm;\n    const selected =\n      [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';\n    if (callback(e, combo) === false) {\n      e.preventDefault();\n      e.stopPropagation();\n    }\n    editor?.eventBus.emit('hotkey.callback.call', {\n      callback,\n      e,\n      combo,\n      sequence,\n      selected,\n    });\n  } catch (err) {\n    console.error(err.message);\n  }\n}\n\nexport interface IHotKey extends Omit<IPublicApiHotkey, 'bind' | 'callbacks'> {\n  activate(activate: boolean): void;\n}\n\nexport class Hotkey implements IHotKey {\n  callBacks: IPublicTypeHotkeyCallbacks = {};\n\n  private directMap: HotkeyDirectMap = {};\n\n  private sequenceLevels: SequenceLevels = {};\n\n  private resetTimer = 0;\n\n  private ignoreNextKeyup: boolean | string = false;\n\n  private ignoreNextKeypress = false;\n\n  private nextExpectedAction: boolean | string = false;\n\n  private isActivate = true;\n\n  constructor(readonly viewName: string = 'global') {\n    this.mount(window);\n  }\n\n  activate(activate: boolean): void {\n    this.isActivate = activate;\n  }\n\n  mount(window: Window) {\n    const { document } = window;\n    const handleKeyEvent = this.handleKeyEvent.bind(this);\n    document.addEventListener('keypress', handleKeyEvent, false);\n    document.addEventListener('keydown', handleKeyEvent, false);\n    document.addEventListener('keyup', handleKeyEvent, false);\n    return () => {\n      document.removeEventListener('keypress', handleKeyEvent, false);\n      document.removeEventListener('keydown', handleKeyEvent, false);\n      document.removeEventListener('keyup', handleKeyEvent, false);\n    };\n  }\n\n  bind(combos: string[] | string, callback: IPublicTypeHotkeyCallback, action?: string): Hotkey {\n    this.bindMultiple(Array.isArray(combos) ? combos : [combos], callback, action);\n    return this;\n  }\n\n  unbind(combos: string[] | string, callback: IPublicTypeHotkeyCallback, action?: string) {\n    const combinations = Array.isArray(combos) ? combos : [combos];\n\n    combinations.forEach(combination => {\n      const info: KeyInfo = getKeyInfo(combination, action);\n      const { key, modifiers } = info;\n      const idx = this.callBacks[key].findIndex(info => {\n        return isEqual(info.modifiers, modifiers) && info.callback === callback;\n      });\n      if (idx !== -1) {\n        this.callBacks[key].splice(idx, 1);\n      }\n    });\n  }\n\n  /**\n   * resets all sequence counters except for the ones passed in\n   */\n  private resetSequences(doNotReset?: SequenceLevels): void {\n    // doNotReset = doNotReset || {};\n    let activeSequences = false;\n    let key = '';\n    for (key in this.sequenceLevels) {\n      if (doNotReset && doNotReset[key]) {\n        activeSequences = true;\n      } else {\n        this.sequenceLevels[key] = 0;\n      }\n    }\n    if (!activeSequences) {\n      this.nextExpectedAction = false;\n    }\n  }\n\n  /**\n   * finds all callbacks that match based on the keycode, modifiers,\n   * and action\n   */\n  private getMatches(\n    character: string,\n    modifiers: string[],\n    e: KeyboardEvent | ActionEvent,\n    sequenceName?: string,\n    combination?: string,\n    level?: number,\n  ): IPublicTypeHotkeyCallbackConfig[] {\n    let i: number;\n    let callback: IPublicTypeHotkeyCallbackConfig;\n    const matches: IPublicTypeHotkeyCallbackConfig[] = [];\n    const action: string = e.type;\n\n    // if there are no events related to this keycode\n    if (!this.callBacks[character]) {\n      return [];\n    }\n\n    // if a modifier key is coming up on its own we should allow it\n    if (action === 'keyup' && isModifier(character)) {\n      modifiers = [character];\n    }\n\n    // loop through all callbacks for the key that was pressed\n    // and see if any of them match\n    for (i = 0; i < this.callBacks[character].length; ++i) {\n      callback = this.callBacks[character][i];\n\n      // if a sequence name is not specified, but this is a sequence at\n      // the wrong level then move onto the next match\n      if (!sequenceName && callback.seq && this.sequenceLevels[callback.seq] !== callback.level) {\n        continue;\n      }\n\n      // if the action we are looking for doesn't match the action we got\n      // then we should keep going\n      if (action !== callback.action) {\n        continue;\n      }\n\n      // if this is a keypress event and the meta key and control key\n      // are not pressed that means that we need to only look at the\n      // character, otherwise check the modifiers as well\n      //\n      // chrome will not fire a keypress if meta or control is down\n      // safari will fire a keypress if meta or meta+shift is down\n      // firefox will fire a keypress if meta or control is down\n      if ((isPressEvent(e) && !e.metaKey && !e.ctrlKey) || modifiersMatch(modifiers, callback.modifiers)) {\n        const deleteCombo = !sequenceName && callback.combo === combination;\n        const deleteSequence = sequenceName && callback.seq === sequenceName && callback.level === level;\n        if (deleteCombo || deleteSequence) {\n          this.callBacks[character].splice(i, 1);\n        }\n\n        matches.push(callback);\n      }\n    }\n    return matches;\n  }\n\n  private handleKey(character: string, modifiers: string[], e: KeyboardEvent): void {\n    const callbacks: IPublicTypeHotkeyCallbackConfig[] = this.getMatches(character, modifiers, e);\n    let i: number;\n    const doNotReset: SequenceLevels = {};\n    let maxLevel = 0;\n    let processedSequenceCallback = false;\n\n    // Calculate the maxLevel for sequences so we can only execute the longest callback sequence\n    for (i = 0; i < callbacks.length; ++i) {\n      if (callbacks[i].seq) {\n        maxLevel = Math.max(maxLevel, callbacks[i].level || 0);\n      }\n    }\n\n    // loop through matching callbacks for this key event\n    for (i = 0; i < callbacks.length; ++i) {\n      // fire for all sequence callbacks\n      // this is because if for example you have multiple sequences\n      // bound such as \"g i\" and \"g t\" they both need to fire the\n      // callback for matching g cause otherwise you can only ever\n      // match the first one\n      if (callbacks[i].seq) {\n        // only fire callbacks for the maxLevel to prevent\n        // subsequences from also firing\n        //\n        // for example 'a option b' should not cause 'option b' to fire\n        // even though 'option b' is part of the other sequence\n        //\n        // any sequences that do not match here will be discarded\n        // below by the resetSequences call\n        if (callbacks[i].level !== maxLevel) {\n          continue;\n        }\n\n        processedSequenceCallback = true;\n\n        // keep a list of which sequences were matches for later\n        doNotReset[callbacks[i].seq || ''] = 1;\n        fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq);\n        continue;\n      }\n\n      // if there were no sequence matches but we are still here\n      // that means this is a regular match so we should fire that\n      if (!processedSequenceCallback) {\n        fireCallback(callbacks[i].callback, e, callbacks[i].combo);\n      }\n    }\n\n    const ignoreThisKeypress = e.type === 'keypress' && this.ignoreNextKeypress;\n    if (e.type === this.nextExpectedAction && !isModifier(character) && !ignoreThisKeypress) {\n      this.resetSequences(doNotReset);\n    }\n\n    this.ignoreNextKeypress = processedSequenceCallback && e.type === 'keydown';\n  }\n\n  private handleKeyEvent(e: KeyboardEvent): void {\n    if (!this.isActivate) {\n      return;\n    }\n    const character = characterFromEvent(e);\n\n    // no character found then stop\n    if (!character) {\n      return;\n    }\n\n    // need to use === for the character check because the character can be 0\n    if (e.type === 'keyup' && this.ignoreNextKeyup === character) {\n      this.ignoreNextKeyup = false;\n      return;\n    }\n\n    this.handleKey(character, eventModifiers(e), e);\n  }\n\n  private resetSequenceTimer(): void {\n    if (this.resetTimer) {\n      clearTimeout(this.resetTimer);\n    }\n    this.resetTimer = window.setTimeout(this.resetSequences, 1000);\n  }\n\n  private bindSequence(combo: string, keys: string[], callback: IPublicTypeHotkeyCallback, action?: string): void {\n    // const self: any = this;\n    this.sequenceLevels[combo] = 0;\n    const increaseSequence = (nextAction: string) => {\n      return () => {\n        this.nextExpectedAction = nextAction;\n        ++this.sequenceLevels[combo];\n        this.resetSequenceTimer();\n      };\n    };\n    const callbackAndReset = (e: KeyboardEvent): void => {\n      fireCallback(callback, e, combo);\n\n      if (action !== 'keyup') {\n        this.ignoreNextKeyup = characterFromEvent(e);\n      }\n\n      setTimeout(this.resetSequences, 10);\n    };\n    for (let i = 0; i < keys.length; ++i) {\n      const isFinal = i + 1 === keys.length;\n      const wrappedCallback = isFinal ? callbackAndReset : increaseSequence(action || getKeyInfo(keys[i + 1]).action);\n      this.bindSingle(keys[i], wrappedCallback, action, combo, i);\n    }\n  }\n\n  private bindSingle(\n    combination: string,\n    callback: IPublicTypeHotkeyCallback,\n    action?: string,\n    sequenceName?: string,\n    level?: number,\n  ): void {\n    // store a direct mapped reference for use with HotKey.trigger\n    this.directMap[`${combination}:${action}`] = callback;\n\n    // make sure multiple spaces in a row become a single space\n    combination = combination.replace(/\\s+/g, ' ');\n\n    const sequence: string[] = combination.split(' ');\n\n    // if this pattern is a sequence of keys then run through this method\n    // to reprocess each pattern one key at a time\n    if (sequence.length > 1) {\n      this.bindSequence(combination, sequence, callback, action);\n      return;\n    }\n\n    const info: KeyInfo = getKeyInfo(combination, action);\n\n    // make sure to initialize array if this is the first time\n    // a callback is added for this key\n    this.callBacks[info.key] = this.callBacks[info.key] || [];\n\n    // remove an existing match if there is one\n    this.getMatches(info.key, info.modifiers, { type: info.action }, sequenceName, combination, level);\n\n    // add this call back to the array\n    // if it is a sequence put it at the beginning\n    // if not put it at the end\n    //\n    // this is important because the way these are processed expects\n    // the sequence ones to come first\n    this.callBacks[info.key][sequenceName ? 'unshift' : 'push']({\n      callback,\n      modifiers: info.modifiers,\n      action: info.action,\n      seq: sequenceName,\n      level,\n      combo: combination,\n    });\n  }\n\n  private bindMultiple(combinations: string[], callback: IPublicTypeHotkeyCallback, action?: string) {\n    for (const item of combinations) {\n      this.bindSingle(item, callback, action);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/index.ts",
    "content": "export * from './intl';\nexport * from './editor';\nexport * from './utils';\nexport * from './di';\nexport * from './hotkey';\nexport * from './widgets';\nexport * from './config';\nexport * from './event-bus';\nexport * from './command';\n"
  },
  {
    "path": "packages/editor-core/src/intl/global-locale.ts",
    "content": "import { IEventBus, createModuleEventBus } from '../event-bus';\nimport { obx, computed } from '../utils/obx';\nimport { Logger } from '@alilc/lowcode-utils';\n\nconst logger = new Logger({ level: 'warn', bizName: 'globalLocale' });\n\nconst languageMap: { [key: string]: string } = {\n  en: 'en-US',\n  zh: 'zh-CN',\n  zt: 'zh-TW',\n  es: 'es-ES',\n  pt: 'pt-PT',\n  fr: 'fr-FR',\n  de: 'de-DE',\n  it: 'it-IT',\n  ru: 'ru-RU',\n  ja: 'ja-JP',\n  ko: 'ko-KR',\n  ar: 'ar-SA',\n  tr: 'tr-TR',\n  th: 'th-TH',\n  vi: 'vi-VN',\n  nl: 'nl-NL',\n  he: 'iw-IL',\n  id: 'in-ID',\n  pl: 'pl-PL',\n  hi: 'hi-IN',\n  uk: 'uk-UA',\n  ms: 'ms-MY',\n  tl: 'tl-PH',\n};\n\nconst LowcodeConfigKey = 'ali-lowcode-config';\n\nclass GlobalLocale {\n  private emitter: IEventBus = createModuleEventBus('GlobalLocale');\n\n  @obx.ref private _locale?: string;\n\n  @computed get locale() {\n    if (this._locale != null) {\n      return this._locale;\n    }\n\n    // TODO: store 1 & store 2 abstract out as custom implements\n\n    // store 1: config from storage\n    let result = null;\n    if (hasLocalStorage(window)) {\n      const store = window.localStorage;\n      let config: any;\n      try {\n        config = JSON.parse(store.getItem(LowcodeConfigKey) || '');\n      } catch (e) {\n        // ignore;\n      }\n      if (config?.locale) {\n        result = (config.locale || '').replace('_', '-');\n        logger.debug(`getting locale from localStorage: ${result}`);\n      }\n    }\n    if (!result) {\n      // store 2: config from window\n      let localeFromConfig: string = getConfig('locale');\n      if (localeFromConfig) {\n        result = languageMap[localeFromConfig] || localeFromConfig.replace('_', '-');\n        logger.debug(`getting locale from config: ${result}`);\n      }\n    }\n\n    if (!result) {\n      // store 3: config from system\n      const { navigator } = window as any;\n      if (navigator.language) {\n        const lang = (navigator.language as string);\n        return languageMap[lang] || lang.replace('_', '-');\n      } else if (navigator.browserLanguage) {\n        const it = navigator.browserLanguage.split('-');\n        let localeFromSystem = it[0];\n        if (it[1]) {\n          localeFromSystem += `-${it[1].toUpperCase()}`;\n        }\n        result = localeFromSystem;\n        logger.debug(`getting locale from system: ${result}`);\n      }\n    }\n    if (!result) {\n      logger.warn('something when wrong when trying to get locale, use zh-CN as default, please check it out!');\n      result = 'zh-CN';\n    }\n    this._locale = result;\n    return result;\n  }\n\n  constructor() {\n    this.emitter.setMaxListeners(0);\n  }\n\n  setLocale(locale: string) {\n    logger.info(`setting locale to ${locale}`);\n    if (locale === this.locale) {\n      return;\n    }\n    this._locale = locale;\n    if (hasLocalStorage(window)) {\n      const store = window.localStorage;\n      let config: any;\n      try {\n        config = JSON.parse(store.getItem(LowcodeConfigKey) || '');\n      } catch (e) {\n        // ignore;\n      }\n\n      if (config && typeof config === 'object') {\n        config.locale = locale;\n      } else {\n        config = { locale };\n      }\n\n      store.setItem(LowcodeConfigKey, JSON.stringify(config));\n    }\n    this.emitter.emit('localechange', locale);\n  }\n\n  getLocale() {\n    return this.locale;\n  }\n\n  onChangeLocale(fn: (locale: string) => void): () => void {\n    this.emitter.on('localechange', fn);\n    return () => {\n      this.emitter.removeListener('localechange', fn);\n    };\n  }\n}\n\nfunction getConfig(name: string) {\n  const win: any = window;\n  return (\n    win[name]\n    || (win.g_config || {})[name]\n    || (win.pageConfig || {})[name]\n  );\n}\n\nfunction hasLocalStorage(obj: any): obj is WindowLocalStorage {\n  return obj.localStorage;\n}\n\nlet globalLocale = new GlobalLocale();\n\nexport { globalLocale };\n"
  },
  {
    "path": "packages/editor-core/src/intl/index.ts",
    "content": "import { ReactNode, Component, createElement } from 'react';\nimport { IntlMessageFormat } from 'intl-messageformat';\nimport { globalLocale } from './global-locale';\nimport { isI18nData } from '@alilc/lowcode-utils';\nimport { observer } from '../utils';\nimport { IPublicTypeI18nData } from '@alilc/lowcode-types';\n\nfunction generateTryLocales(locale: string) {\n  const tries = [locale, locale.replace('-', '_')];\n  if (locale === 'zh-TW' || locale === 'en-US') {\n    tries.push('zh-CN');\n    tries.push('zh_CN');\n  } else {\n    tries.push('en-US');\n    tries.push('en_US');\n    if (locale !== 'zh-CN') {\n      tries.push('zh-CN');\n      tries.push('zh_CN');\n    }\n  }\n  return tries;\n}\n\nfunction injectVars(msg: string, params: any, locale: string): string {\n  if (!msg || !params) {\n    return msg;\n  }\n  const formater = new IntlMessageFormat(msg, locale);\n  return formater.format(params as any) as string;\n}\n\nexport function intl(data: IPublicTypeI18nData | string, params?: object): ReactNode {\n  if (!isI18nData(data)) {\n    return data;\n  }\n  if (data.intl) {\n    return data.intl;\n  }\n  const locale = globalLocale.getLocale();\n  const tries = generateTryLocales(locale);\n  let msg: string | undefined;\n  for (const lan of tries) {\n    msg = data[lan];\n    if (msg != null) {\n      break;\n    }\n  }\n  if (msg == null) {\n    return `##intl@${locale}##`;\n  }\n  return injectVars(msg, params, locale);\n}\n\nexport function shallowIntl(data: any): any {\n  if (!data || typeof data !== 'object') {\n    return data;\n  }\n  const maps: any = {};\n  Object.keys(data).forEach(key => {\n    maps[key] = intl(data[key]);\n  });\n  return maps;\n}\n\nexport function intlNode(data: any, params?: object): ReactNode {\n  if (isI18nData(data)) {\n    if (data.intlNode) {\n      return data.intlNode;\n    }\n\n    return createElement(IntlElement, { data, params });\n  }\n  return data;\n}\n\n@observer\nclass IntlElement extends Component<{ data: any; params?: object }> {\n  render() {\n    const { data, params } = this.props;\n    return intl(data, params);\n  }\n}\n\nexport function createIntl(\n  instance: string | object,\n): {\n    intlNode(id: string, params?: object): ReactNode;\n    intl(id: string, params?: object): string;\n    getLocale(): string;\n    setLocale(locale: string): void;\n  } {\n  // TODO: make reactive\n  const data = (() => {\n    const locale = globalLocale.getLocale();\n    if (typeof instance === 'string') {\n      if ((window as any)[instance]) {\n        return (window as any)[instance][locale] || {};\n      }\n      const key = `${instance}_${locale.toLocaleLowerCase()}`;\n      return (window as any)[key] || {};\n    }\n    if (instance && typeof instance === 'object') {\n      return (instance as any)[locale] || {};\n    }\n    return {};\n  })();\n\n  function intl(key: string, params?: object): string {\n    // TODO: tries lost language\n    const str = data[key];\n\n    if (str == null) {\n      return `##intl@${key}##`;\n    }\n\n    return injectVars(str, params, globalLocale.getLocale());\n  }\n\n  @observer\n  class IntlElement extends Component<{ id: string; params?: object }> {\n    render() {\n      const { id, params } = this.props;\n      return intl(id, params);\n    }\n  }\n\n  return {\n    intlNode(id: string, params?: object) {\n      return createElement(IntlElement, { id, params });\n    },\n    intl,\n    getLocale() {\n      return globalLocale.getLocale();\n    },\n    setLocale(locale: string) {\n      globalLocale.setLocale(locale);\n    },\n  };\n}\n\nexport { globalLocale };\n"
  },
  {
    "path": "packages/editor-core/src/utils/app-preset.ts",
    "content": "import store from 'store';\n\ndeclare global {\n  interface Window {\n    __isDebug?: boolean;\n    __newFunc?: (funcStr: string) => (...args: any[]) => any;\n  }\n}\n\n// 根据 url 参数设置 debug 选项\nconst debugRegRes = /_?debug=(.*?)(&|$)/.exec(location.search);\nif (debugRegRes && debugRegRes[1]) {\n  // eslint-disable-next-line no-underscore-dangle\n  window.__isDebug = true;\n  // @ts-ignore\n  store.storage.write('debug', debugRegRes[1] === 'true' ? '*' : debugRegRes[1]);\n} else {\n  // eslint-disable-next-line no-underscore-dangle\n  window.__isDebug = false;\n  store.remove('debug');\n}\n\n// 重要，用于矫正画布执行 new Function 的 window 对象上下文\n// eslint-disable-next-line no-underscore-dangle\nwindow.__newFunc = (funContext: string): ((...args: any[]) => any) => {\n  // eslint-disable-next-line no-new-func\n  return new Function(funContext) as (...args: any[]) => any;\n};\n\n// 关闭浏览器前提醒，只有产生过交互才会生效\nwindow.onbeforeunload = function (e: Event): string {\n  const ev = e || window.event;\n  // 本地调试不生效\n  if (location.href.indexOf('localhost') > 0) {\n    return '';\n  }\n  const msg = '您确定要离开此页面吗？';\n  ev.cancelBubble = true;\n  ev.returnValue = true;\n  if (e.stopPropagation) {\n    e.stopPropagation();\n    e.preventDefault();\n  }\n  return msg;\n};\n"
  },
  {
    "path": "packages/editor-core/src/utils/assets-transform.ts",
    "content": "/* eslint-disable no-param-reassign */\nimport { IPublicTypeAssetsJson, IPublicTypeComponentDescription, IPublicTypePackage, IPublicTypeRemoteComponentDescription } from '@alilc/lowcode-types';\n\n// TODO: 该转换逻辑未来需要消化掉\nexport function assetsTransform(assets: IPublicTypeAssetsJson) {\n  const { components, packages } = assets;\n  const packageMaps = (packages || []).reduce((acc: Record<string, IPublicTypePackage>, cur: IPublicTypePackage) => {\n    const key = cur.id || cur.package || '';\n    acc[key] = cur;\n    return acc;\n  }, {} as any);\n  components.forEach((componentDesc: IPublicTypeComponentDescription | IPublicTypeRemoteComponentDescription) => {\n    let { devMode, schema, reference } = componentDesc;\n    if ((devMode as string) === 'lowcode') {\n      devMode = 'lowCode';\n    } else if (devMode === 'proCode') {\n      devMode = 'proCode';\n    }\n    if (devMode) {\n      componentDesc.devMode = devMode;\n    }\n    if (devMode === 'lowCode' && !schema && reference) {\n      const referenceId = reference.id || '';\n      componentDesc.schema = packageMaps[referenceId].schema;\n    }\n  });\n  return assets;\n}"
  },
  {
    "path": "packages/editor-core/src/utils/control.ts",
    "content": "let globalEventOn = true;\n\nexport function setGlobalEventFlag(flag: boolean) {\n  globalEventOn = flag;\n}\n\nexport function switchGlobalEventOn() {\n  setGlobalEventFlag(true);\n}\n\nexport function switchGlobalEventOff() {\n  setGlobalEventFlag(false);\n}\n\nexport function isGlobalEventOn() {\n  return globalEventOn;\n}\n\nexport function runWithGlobalEventOff(fn: Function) {\n  switchGlobalEventOff();\n  fn();\n  switchGlobalEventOn();\n}\n\ntype ListenerFunc = (...args: any[]) => void;\nexport function wrapWithEventSwitch(fn: ListenerFunc): ListenerFunc {\n  return (...args: any[]) => {\n    if (isGlobalEventOn()) fn(...args);\n  };\n}"
  },
  {
    "path": "packages/editor-core/src/utils/focus-tracker.ts",
    "content": "export class FocusTracker {\n  private actives: Focusable[] = [];\n\n  private modals: Array<{ checkDown: (e: MouseEvent) => boolean; checkOpen: () => boolean }> = [];\n\n  mount(win: Window) {\n    const checkDown = (e: MouseEvent) => {\n      if (this.checkModalDown(e)) {\n        return;\n      }\n      const { first } = this;\n      if (first && !first.internalCheckInRange(e)) {\n        this.internalSuspenseItem(first);\n        first.internalTriggerBlur();\n      }\n    };\n    win.document.addEventListener('click', checkDown, true);\n    return () => {\n      win.document.removeEventListener('click', checkDown, true);\n    };\n  }\n\n  get first() {\n    return this.actives[0];\n  }\n\n  addModal(checkDown: (e: MouseEvent) => boolean, checkOpen: () => boolean) {\n    this.modals.push({\n      checkDown,\n      checkOpen,\n    });\n  }\n\n  private checkModalOpen(): boolean {\n    return this.modals.some((item) => item.checkOpen());\n  }\n\n  private checkModalDown(e: MouseEvent): boolean {\n    return this.modals.some((item) => item.checkDown(e));\n  }\n\n  execSave() {\n    // has Modal return;\n    if (this.checkModalOpen()) {\n      return;\n    }\n    // catch\n    if (this.first) {\n      this.first.internalTriggerSave();\n    }\n  }\n\n  execEsc() {\n    const { first } = this;\n    if (first) {\n      this.internalSuspenseItem(first);\n      first.internalTriggerEsc();\n    }\n  }\n\n  create(config: FocusableConfig) {\n    return new Focusable(this, config);\n  }\n\n  internalActiveItem(item: Focusable) {\n    const first = this.actives[0];\n    if (first === item) {\n      return;\n    }\n    const i = this.actives.indexOf(item);\n    if (i > -1) {\n      this.actives.splice(i, 1);\n    }\n    this.actives.unshift(item);\n    if (!item.isModal && first) {\n      // trigger Blur\n      first.internalTriggerBlur();\n    }\n    // trigger onActive\n    item.internalTriggerActive();\n  }\n\n  internalSuspenseItem(item: Focusable) {\n    const i = this.actives.indexOf(item);\n    if (i > -1) {\n      this.actives.splice(i, 1);\n      this.first?.internalTriggerActive();\n    }\n  }\n}\n\nexport interface FocusableConfig {\n  range: HTMLElement | ((e: MouseEvent) => boolean);\n  modal?: boolean; // 模态窗口级别\n  onEsc?: () => void;\n  onBlur?: () => void;\n  onSave?: () => void;\n  onActive?: () => void;\n}\n\nexport class Focusable {\n  readonly isModal: boolean;\n\n  constructor(private tracker: FocusTracker, private config: FocusableConfig) {\n    this.isModal = config.modal == null ? false : config.modal;\n  }\n\n  active() {\n    this.tracker.internalActiveItem(this);\n  }\n\n  suspense() {\n    this.tracker.internalSuspenseItem(this);\n  }\n\n  purge() {\n    this.tracker.internalSuspenseItem(this);\n  }\n\n  internalCheckInRange(e: MouseEvent) {\n    const { range } = this.config;\n    if (!range) {\n      return false;\n    }\n    if (typeof range === 'function') {\n      return range(e);\n    }\n    return range.contains(e.target as HTMLElement);\n  }\n\n  internalTriggerBlur() {\n    if (this.config.onBlur) {\n      this.config.onBlur();\n    }\n  }\n\n  internalTriggerSave() {\n    if (this.config.onSave) {\n      this.config.onSave();\n      return true;\n    }\n    return false;\n  }\n\n  internalTriggerEsc() {\n    if (this.config.onEsc) {\n      this.config.onEsc();\n    }\n  }\n\n  internalTriggerActive() {\n    if (this.config.onActive) {\n      this.config.onActive();\n    }\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/utils/get-public-path.ts",
    "content": "const publicPath = (document.currentScript as HTMLScriptElement)?.src.replace(/^(.*\\/)[^/]+$/, '$1');\n\nexport function getPublicPath(): string {\n  return publicPath || '';\n}\n"
  },
  {
    "path": "packages/editor-core/src/utils/index.ts",
    "content": "export * from './get-public-path';\nexport * from './obx';\nexport * from './request';\nexport * from './focus-tracker';\nexport * from './control';\nexport * from './preference';\n"
  },
  {
    "path": "packages/editor-core/src/utils/logger.ts",
    "content": "import { Logger, Level } from '@alilc/lowcode-utils';\n\nexport { Logger };\n\nexport function getLogger(config: { level: Level; bizName: string }): Logger {\n  return new Logger(config);\n}\n"
  },
  {
    "path": "packages/editor-core/src/utils/obx.ts",
    "content": "import { observer } from 'mobx-react';\nimport { configure } from 'mobx';\n\nconfigure({ enforceActions: 'never' });\n\n// 常用的直接导出，其他的以 mobx 命名空间导出\nexport {\n  observable as obx,\n  observable,\n  observe,\n  autorun,\n  makeObservable,\n  makeAutoObservable,\n  reaction,\n  computed,\n  action,\n  runInAction,\n  untracked,\n} from 'mobx';\nexport type { IReactionDisposer, IReactionPublic, IReactionOptions } from 'mobx';\n\nexport * as mobx from 'mobx';\nexport { observer };\n"
  },
  {
    "path": "packages/editor-core/src/utils/preference.ts",
    "content": "import store from 'store';\nimport { getLogger } from './logger';\nimport { IPublicModelPreference } from '@alilc/lowcode-types';\n\nconst logger = getLogger({ level: 'warn', bizName: 'Preference' });\nconst STORAGE_KEY_PREFIX = 'ale';\n\n/**\n * used to store user preferences, such as pinned status of a pannel.\n * save to local storage.\n */\nexport default class Preference implements IPublicModelPreference {\n  getStorageKey(key: string, module?: string): string {\n    const moduleKey = module || '__inner__';\n    return `${STORAGE_KEY_PREFIX}_${moduleKey}.${key}`;\n  }\n\n  set(key: string, value: any, module?: string): void {\n    if (!key || typeof key !== 'string' || key.length === 0) {\n      logger.error('Invalid key when setting preference', key);\n      return;\n    }\n    const storageKey = this.getStorageKey(key, module);\n    logger.debug('storageKey:', storageKey, 'set with value:', value);\n    store.set(storageKey, value);\n  }\n\n  get(key: string, module: string): any {\n    if (!key || typeof key !== 'string' || key.length === 0) {\n      logger.error('Invalid key when getting from preference', key);\n      return;\n    }\n    const storageKey = this.getStorageKey(key, module);\n    const result = store.get(storageKey);\n    logger.debug('storageKey:', storageKey, 'get with result:', result);\n    return result;\n  }\n\n  /**\n   * check if local storage contain certain key\n   *\n   * @param {string} key\n   * @param {string} module\n   */\n  contains(key: string, module: string): boolean {\n    if (!key || typeof key !== 'string' || key.length === 0) {\n      logger.error('Invalid key when getting from preference', key);\n      return false;\n    }\n    const storageKey = this.getStorageKey(key, module);\n    const result = store.get(storageKey);\n\n    return !(result === undefined || result === null);\n  }\n}"
  },
  {
    "path": "packages/editor-core/src/utils/request.ts",
    "content": "import Debug from 'debug';\n\nconst debug = Debug('request');\n\nexport function serialize(obj?: object): string {\n  if (!obj) {\n    return '';\n  }\n  const rst: string[] = [];\n  Object.entries(obj || {}).forEach(([key, val]): void => {\n    if (val === null || val === undefined || val === '') return;\n    if (typeof val === 'object') rst.push(`${key}=${encodeURIComponent(JSON.stringify(val))}`);\n    else rst.push(`${key}=${encodeURIComponent(val)}`);\n  });\n  return rst.join('&');\n}\n\nexport function buildUrl(dataAPI: string, params?: object): string {\n  const paramStr = serialize(params);\n  if (paramStr) {\n    return dataAPI.indexOf('?') > 0 ? `${dataAPI}&${paramStr}` : `${dataAPI}?${paramStr}`;\n  }\n  return dataAPI;\n}\n\nexport function get(dataAPI: string, params?: object, headers?: object, otherProps?: object): Promise<any> {\n  const fetchHeaders = {\n    Accept: 'application/json',\n    ...headers,\n  };\n  return request(buildUrl(dataAPI, params), 'GET', undefined, fetchHeaders, otherProps);\n}\n\nexport function post(dataAPI: string, params?: object, headers?: object, otherProps?: object): Promise<any> {\n  const fetchHeaders = {\n    Accept: 'application/json',\n    'Content-Type': 'application/x-www-form-urlencoded',\n    ...headers,\n  };\n  return request(\n    dataAPI,\n    'POST',\n    fetchHeaders['Content-Type'].indexOf('application/json') > -1 || Array.isArray(params)\n      ? JSON.stringify(params)\n      : serialize(params),\n    fetchHeaders,\n    otherProps,\n  );\n}\n\nexport function request(\n  dataAPI: string,\n  method = 'GET',\n  data?: object | string,\n  headers?: object,\n  otherProps?: any,\n): Promise<any> {\n  return new Promise((resolve, reject): void => {\n    if (otherProps && otherProps.timeout) {\n      setTimeout((): void => {\n        reject(new Error('timeout'));\n      }, otherProps.timeout);\n    }\n    fetch(dataAPI, {\n      method,\n      credentials: 'include',\n      headers,\n      body: data,\n      ...otherProps,\n    })\n      .then((response: Response): any => {\n        switch (response.status) {\n          case 200:\n          case 201:\n          case 202:\n            return response.json();\n          case 204:\n            if (method === 'DELETE') {\n              return {\n                success: true,\n              };\n            } else {\n              return {\n                __success: false,\n                code: response.status,\n              };\n            }\n          case 400:\n          case 401:\n          case 403:\n          case 404:\n          case 406:\n          case 410:\n          case 422:\n          case 500:\n            return response\n              .json()\n              .then((res: object): any => {\n                return {\n                  __success: false,\n                  code: response.status,\n                  data: res,\n                };\n              })\n              .catch((): object => {\n                return {\n                  __success: false,\n                  code: response.status,\n                };\n              });\n          default:\n            return null;\n        }\n      })\n      .then((json: any): void => {\n        if (json && json.__success !== false) {\n          resolve(json);\n        } else {\n          delete json.__success;\n          reject(json);\n        }\n      })\n      .catch((err: Error): void => {\n        debug(err);\n        reject(err);\n      });\n  });\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/index.ts",
    "content": "// TODO move another place\nexport * from './tip';\nexport * from './title';\n"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/help-tips.tsx",
    "content": "import { IPublicTypeHelpTipConfig, IPublicTypeTipConfig } from '@alilc/lowcode-types';\nimport { Tip } from './tip';\nimport { Icon } from '@alifd/next';\nimport { IconProps } from '@alifd/next/types/icon';\n\nexport function HelpTip({\n  help,\n  direction = 'top',\n  size = 'small',\n}: {\n  help: IPublicTypeHelpTipConfig;\n  direction?: IPublicTypeTipConfig['direction'];\n  size?: IconProps['size'];\n}) {\n  if (typeof help === 'string') {\n    return (\n      <div>\n        <Icon type=\"help\" size={size} className=\"lc-help-tip\" />\n        <Tip direction={direction}>{help}</Tip>\n      </div>\n    );\n  }\n\n  if (typeof help === 'object' && help.url) {\n    return (\n      <div>\n        <a href={help.url} target=\"_blank\" rel=\"noopener noreferrer\">\n          <Icon type=\"help\" size={size} className=\"lc-help-tip\" />\n        </a>\n        <Tip direction={direction}>{help.content}</Tip>\n      </div>\n    );\n  }\n  return (\n    <div>\n      <Icon type=\"help\" size=\"small\" className=\"lc-help-tip\" />\n      <Tip direction={direction}>{help.content}</Tip>\n    </div>\n  );\n}"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/index.ts",
    "content": "import './style.less';\n\nexport * from './tip';\nexport * from './tip-container';\nexport * from './help-tips';\n"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/style.less",
    "content": "@keyframes shake {\n  from,\n  to {\n    margin: 0;\n  }\n  20%,\n  60% {\n    margin: 0 10px 0 -10px;\n  }\n  40%,\n  80% {\n    margin: 0 -10px 0 10px;\n  }\n}\n\n@keyframes drop {\n  from {\n    transform: translateY(-100%);\n  }\n\n  to {\n    transform: translateY(0);\n  }\n}\n\n@keyframes appear-left {\n  from {\n    transform: translateX(8px);\n    opacity: 0.8;\n  }\n\n  to {\n    transform: translateX(0);\n    opacity: 1;\n  }\n}\n@keyframes appear-right {\n  from {\n    transform: translateX(-8px);\n    opacity: 0.8;\n  }\n\n  to {\n    transform: translateX(0);\n    opacity: 1;\n  }\n}\n@keyframes appear-top {\n  from {\n    transform: translateY(8px);\n    opacity: 0.8;\n  }\n\n  to {\n    transform: translateY(0);\n    opacity: 1;\n  }\n}\n@keyframes appear-bottom {\n  from {\n    transform: translateY(-8px);\n    opacity: 0.8;\n  }\n\n  to {\n    transform: translateY(0);\n    opacity: 1;\n  }\n}\n\n@keyframes scale {\n  from {\n    transform: scale(0.9);\n  }\n\n  to {\n    transform: scale(1);\n  }\n}\n\n@keyframes spining {\n  from {\n    transform: rotate(0deg);\n  }\n  to {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes pulse {\n  from,\n  to {\n    transform: scale(1);\n    opacity: 0.7;\n  }\n  50% {\n    transform: scale(1.02);\n    opacity: 1;\n  }\n}\n\n.lc-arrow {\n  position: absolute;\n  width: 36px;\n  height: 10px;\n  box-sizing: border-box;\n  overflow: hidden;\n  &:after {\n    content: '';\n    display: block;\n    width: 0;\n    height: 0;\n    margin: 0 auto;\n    border: 8px solid transparent;\n    border-top-color: var(--color-pane-background, rgb(255, 255, 255));\n  }\n  transform-origin: 0 0;\n}\n\n.lc-align-top > .lc-arrow {\n  bottom: 0;\n  left: 0;\n  transform: translateY(100%);\n}\n\n.lc-align-right > .lc-arrow {\n  left: 0;\n  top: 0;\n  transform: rotate(90deg);\n}\n\n.lc-align-left > .lc-arrow {\n  right: 0;\n  top: 0;\n  transform-origin: right top;\n  transform: rotate(-90deg);\n}\n\n.lc-align-bottom > .lc-arrow {\n  top: 0;\n  left: 0;\n  transform: scaleY(-1);\n}\n\n\n.lc-tip {\n  z-index: 2;\n  position: fixed;\n  box-sizing: border-box;\n  background: var(--color-layer-tooltip-background);\n  max-height: 400px;\n  color: var(--color-text-reverse, rgba(255, 255, 255, 0.8));\n  left: 0;\n  top: 0;\n  visibility: hidden;\n  opacity: 0;\n  border-radius: 3px;\n  padding: 6px 8px;\n  text-shadow: 0 -1px var(--color-field-label, rgba(0, 0, 0, 0.3));\n  font-size: var(--font-size-text);\n  line-height: 14px;\n  max-width: 200px;\n  pointer-events: none;\n  &.lc-align-top {\n    transform: translateY(8px);\n  }\n  &.lc-align-bottom {\n    transform: translateY(-8px);\n  }\n  &.lc-align-left {\n    transform: translateX(8px);\n  }\n  &.lc-align-right {\n    transform: translateX(-8px);\n  }\n  .lc-arrow {\n    width: 24px;\n    height: 8px;\n    &:after {\n      border: 6px solid transparent;\n      border-top-color: var(--color-layer-tooltip-background, rgba(0, 0, 0, 0.7));\n    }\n  }\n  &.lc-theme-black {\n    background: var(--color-icon-pane, rgba(0, 0, 0, 0.7));\n    .lc-arrow:after {\n      border-top-color: var(--color-layer-tooltip-background, rgba(0, 0, 0, 0.7));\n    }\n  }\n  &.lc-theme-green {\n    background: var(--color-success-dark, var(--color-function-success-dark, #57a672));\n    .lc-arrow:after {\n      border-top-color: var(--color-success-dark, var(--color-function-success-dark, #57a672));\n    }\n  }\n  &.lc-visible {\n    visibility: visible;\n  }\n  &.lc-visible-animate {\n    visibility: visible;\n    opacity: 1;\n    transition: transform ease-out 200ms, opacity ease-out 200ms;\n  }\n\n  will-change: transform, width, height, opacity, left, top;\n}\n\n.lc-tips-container {\n  pointer-events: none;\n  position: fixed;\n  top: 0;\n  left: 0;\n  overflow: visible;\n  z-index: 2000;\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/tip-container.tsx",
    "content": "import { Component } from 'react';\nimport ReactDOM from 'react-dom';\nimport { TipItem } from './tip-item';\nimport { tipHandler } from './tip-handler';\n\nexport class TipContainer extends Component {\n  private dispose?: () => void;\n  shouldComponentUpdate() {\n    return false;\n  }\n  componentDidMount() {\n    const over = (e: MouseEvent) => tipHandler.setTarget(e.target as any);\n    const down = () => tipHandler.hideImmediately();\n    document.addEventListener('mouseover', over, false);\n    document.addEventListener('mousedown', down, true);\n    this.dispose = () => {\n      document.removeEventListener('mouseover', over, false);\n      document.removeEventListener('mousedown', down, true);\n    };\n  }\n\n  UNSAFE_componentWillMount() {\n    if (this.dispose) {\n      this.dispose();\n    }\n  }\n\n  render() {\n    return ReactDOM.createPortal(\n      <div className=\"lc-tips-container\">\n        <TipItem />\n      </div>,\n      document.querySelector('body')!,\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/tip-handler.ts",
    "content": "import { IPublicTypeTipConfig } from '@alilc/lowcode-types';\nimport { IEventBus, createModuleEventBus } from '../../event-bus';\n\nexport interface TipOptions extends IPublicTypeTipConfig {\n  target: HTMLElement;\n}\n\nclass TipHandler {\n  tip: TipOptions | null = null;\n\n  private showDelay: number | null = null;\n\n  private hideDelay: number | null = null;\n\n  private emitter: IEventBus = createModuleEventBus('TipHandler');\n\n  setTarget(target: HTMLElement) {\n    const tip = findTip(target);\n    if (tip) {\n      if (this.tip) {\n        // the some target should return\n        if ((this.tip as any).target === (tip as any).target) {\n          this.tip = tip;\n          return;\n        }\n        // not show already, reset show delay\n        if (this.showDelay) {\n          clearTimeout(this.showDelay);\n          this.showDelay = null;\n          this.tip = null;\n        } else {\n          if (this.hideDelay) {\n            clearTimeout(this.hideDelay);\n            this.hideDelay = null;\n          }\n          this.tip = tip;\n          this.emitter.emit('tipchange');\n          return;\n        }\n      }\n\n      this.tip = tip;\n      if (this.hideDelay) {\n        clearTimeout(this.hideDelay);\n        this.hideDelay = null;\n        this.emitter.emit('tipchange');\n      } else {\n        this.showDelay = setTimeout(() => {\n          this.showDelay = null;\n          this.emitter.emit('tipchange');\n        }, 350) as any;\n      }\n    } else {\n      if (this.showDelay) {\n        clearTimeout(this.showDelay);\n        this.showDelay = null;\n      } else {\n        this.hideDelay = setTimeout(() => {\n          this.hideDelay = null;\n        }, 100) as any;\n      }\n      this.tip = null;\n\n      this.emitter.emit('tipchange');\n    }\n  }\n\n  hideImmediately() {\n    if (this.hideDelay) {\n      clearTimeout(this.hideDelay);\n      this.hideDelay = null;\n    }\n    if (this.showDelay) {\n      clearTimeout(this.showDelay);\n      this.showDelay = null;\n    }\n    this.tip = null;\n    this.emitter.emit('tipchange');\n  }\n\n  onChange(func: () => void) {\n    this.emitter.on('tipchange', func);\n    return () => {\n      this.emitter.removeListener('tipchange', func);\n    };\n  }\n}\n\nexport const tipHandler = new TipHandler();\n\nfunction findTip(target: HTMLElement | null): TipOptions | null {\n  if (!target) {\n    return null;\n  }\n  // optimize deep finding on mouseover\n  let loopupLimit = 10;\n  while (target && loopupLimit-- > 0) {\n    // get tip from target node\n    if (target.dataset && target.dataset.tip) {\n      return {\n        children: target.dataset.tip,\n        direction: (target.dataset.direction || target.dataset.dir) as any,\n        theme: target.dataset.theme,\n        target,\n      };\n    }\n\n    // or get tip from child nodes\n    let child: HTMLElement | null = target.lastElementChild as HTMLElement;\n\n    while (child) {\n      if (child.dataset && child.dataset.role === 'tip') {\n        const { tipId } = child.dataset;\n        if (!tipId) {\n          return null;\n        }\n        const tipProps = tipsMap.get(tipId);\n        if (!tipProps) {\n          return null;\n        }\n        return {\n          ...tipProps,\n          target,\n        };\n      }\n      child = child.previousElementSibling as HTMLElement;\n    }\n\n    target = target.parentNode as HTMLElement;\n  }\n\n  return null;\n}\n\nconst tipsMap = new Map<string, IPublicTypeTipConfig>();\nexport function postTip(id: string, props: IPublicTypeTipConfig | null) {\n  if (props) {\n    tipsMap.set(id, props);\n  } else {\n    tipsMap.delete(id);\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/tip-item.tsx",
    "content": "import { Component } from 'react';\nimport classNames from 'classnames';\nimport { IPublicTypeTipConfig } from '@alilc/lowcode-types';\nimport { intl } from '../../intl';\nimport { resolvePosition } from './utils';\nimport { tipHandler } from './tip-handler';\n\nexport class TipItem extends Component {\n  private dispose?: () => void;\n\n  constructor(props: any) {\n    super(props);\n    this.dispose = tipHandler.onChange(() => this.forceUpdate());\n  }\n\n  shouldComponentUpdate() {\n    return false;\n  }\n\n  componentDidMount() {\n    this.updateTip();\n  }\n\n  componentDidUpdate() {\n    this.updateTip();\n  }\n\n  componentWillUnmount() {\n    if (this.dispose) {\n      this.dispose();\n    }\n    this.clearTimer();\n  }\n\n  private timer: number | null = null;\n\n  clearTimer() {\n    if (this.timer) {\n      clearTimeout(this.timer);\n      this.timer = null;\n    }\n  }\n\n  private shell: HTMLDivElement | null = null;\n\n  private originClassName = '';\n\n  updateTip() {\n    if (!this.shell) {\n      return;\n    }\n    const { shell } = this;\n    const arrow = shell.querySelector('.lc-arrow') as HTMLElement;\n\n    // reset\n    shell.className = this.originClassName;\n    shell.style.cssText = '';\n    arrow.style.cssText = '';\n    this.clearTimer();\n\n    const { tip } = tipHandler;\n    if (!tip) {\n      return;\n    }\n\n    const { target, direction } = tip;\n    const targetRect = target.getBoundingClientRect();\n\n    if (targetRect.width === 0 || targetRect.height === 0) {\n      return;\n    }\n\n    const shellRect = shell.getBoundingClientRect();\n    const bounds = {\n      left: 1,\n      top: 1,\n      right: document.documentElement.clientWidth - 1,\n      bottom: document.documentElement.clientHeight - 1,\n    };\n\n    const arrowRect = arrow.getBoundingClientRect();\n    const { dir, left, top, arrowLeft, arrowTop } = resolvePosition(\n      shellRect,\n      targetRect,\n      arrowRect,\n      bounds,\n      direction,\n    );\n\n    shell.classList.add(`lc-align-${dir}`);\n    shell.style.top = `${top}px`;\n    shell.style.left = `${left}px`;\n    shell.style.width = `${shellRect.width}px`;\n    shell.style.height = `${shellRect.height}px`;\n\n    if (dir === 'top' || dir === 'bottom') {\n      arrow.style.left = `${arrowLeft}px`;\n    } else {\n      arrow.style.top = `${arrowTop}px`;\n    }\n    this.timer = window.setTimeout(() => {\n      shell.classList.add('lc-visible-animate');\n      shell.style.transform = 'none';\n    }, 10); /**/\n  }\n\n  render() {\n    const tip: IPublicTypeTipConfig = tipHandler.tip || ({} as any);\n    const className = classNames('lc-tip', tip.className, tip && tip.theme ? `lc-theme-${tip.theme}` : null);\n\n    this.originClassName = className;\n\n    return (\n      <div\n        className={className}\n        ref={(ref) => {\n          this.shell = ref;\n        }}\n      >\n        <i className=\"lc-arrow\" />\n        <div className=\"lc-tip-content\">{intl(tip.children)}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/tip.tsx",
    "content": "import { Component } from 'react';\nimport { IPublicTypeTipConfig } from '@alilc/lowcode-types';\nimport { uniqueId } from '@alilc/lowcode-utils';\nimport { postTip } from './tip-handler';\n\nexport class Tip extends Component<IPublicTypeTipConfig> {\n  private id = uniqueId('tips$');\n\n  componentWillUnmount() {\n    postTip(this.id, null);\n  }\n\n  render() {\n    postTip(this.id, this.props);\n    return <meta data-role=\"tip\" data-tip-id={this.id} />;\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/tip/utils.ts",
    "content": "function resolveEdge(popup: any, target: any, arrow: any, bounds: any) {\n  const sx = arrow.width > target.width ? (arrow.width - target.width) / 2 : 0;\n  const sy = arrow.width > target.height ? (arrow.width - target.height) / 2 : 0;\n\n  const top = Math.max(target.top - popup.height + arrow.width - sy, bounds.top);\n  const right = Math.min(target.right + popup.width - arrow.width + sx, bounds.right);\n  const bottom = Math.min(target.bottom + popup.height - arrow.width + sy, bounds.bottom);\n  const left = Math.max(target.left - popup.width + arrow.width - sx, bounds.left);\n\n  return { top, right, bottom, left };\n}\n\nfunction resolveDirection(popup: any, target: any, edge: any, bounds: any, prefers: any) {\n  if (prefers.forceDirection) {\n    return prefers.dir;\n  }\n  const extendWidth = popup.width + popup.extraOffset;\n  const extendHeight = popup.height + popup.extraOffset;\n  const SY = popup.width * extendHeight;\n  const SX = popup.height * extendWidth;\n  const mw = Math.min(edge.right - edge.left, popup.width);\n  const mh = Math.min(edge.bottom - edge.top, popup.height);\n\n  const mat: any = {\n    top: () => {\n      const s = mw * Math.min(target.top - bounds.top, extendHeight);\n      return { s, enough: s >= SY };\n    },\n    bottom: () => {\n      const s = mw * Math.min(bounds.bottom - target.bottom, extendHeight);\n      return { s, enough: s >= SY };\n    },\n    left: () => {\n      const s = mh * Math.min(target.left - bounds.left, extendWidth);\n      return { s, enough: s >= SX };\n    },\n    right: () => {\n      const s = mh * Math.min(bounds.right - target.right, extendWidth);\n      return { s, enough: s >= SX };\n    },\n  };\n\n  const orders = ['top', 'right', 'bottom', 'left'];\n  if (prefers.dir) {\n    const i = orders.indexOf(prefers.dir);\n    if (i > -1) {\n      orders.splice(i, 1);\n      orders.unshift(prefers.dir);\n    }\n  }\n  let ms = 0;\n  let prefer = orders[0];\n  for (let i = 0, l = orders.length; i < l; i++) {\n    const dir = orders[i];\n    const { s, enough } = mat[dir]();\n    if (enough) {\n      return dir;\n    }\n    if (s > ms) {\n      ms = s;\n      prefer = dir;\n    }\n  }\n  return prefer;\n}\n\nfunction resolvePrefer(prefer: any, targetRect: any, bounds: any) {\n  if (!prefer) {\n    if (targetRect.left - bounds.left < 10) {\n      return { dir: 'right' };\n    } else if (targetRect.top - bounds.top < 10) {\n      return { dir: 'bottom' };\n    } else if (bounds.bottom - targetRect.bottom < 10) {\n      return { dir: 'top' };\n    } else if (bounds.right - targetRect.right < 10) {\n      return { dir: 'left' };\n    }\n    return {};\n  }\n  const force = prefer[0] === '!';\n  if (force) {\n    prefer = prefer.slice(1);\n  }\n  let [dir, offset] = prefer.split(/\\s+/);\n  let forceDirection = false;\n  let forceOffset = false;\n  if (dir === 'center') {\n    dir = 'auto';\n    if (!offset) {\n      offset = 'center';\n    }\n  }\n\n  if (force) {\n    if (dir && dir !== 'auto') {\n      forceDirection = true;\n    }\n    if (offset && offset !== 'auto') {\n      forceOffset = true;\n    }\n  }\n\n  return { dir, offset, forceDirection, forceOffset };\n}\n\nexport function resolvePosition(popup: any, target: any, arrow: any, bounds: any, prefer: any) {\n  popup = {\n    extraOffset: arrow.height,\n    top: popup.top,\n    right: popup.right,\n    left: popup.left,\n    bottom: popup.bottom,\n    height: popup.height,\n    width: popup.width,\n  };\n\n  const prefers = resolvePrefer(prefer, target, bounds);\n\n  const edge = resolveEdge(popup, target, arrow, bounds);\n\n  // 选择方向\n  const dir = resolveDirection(popup, target, edge, bounds, prefers);\n\n  let top;\n  let left;\n  let arrowTop;\n  let arrowLeft;\n\n  // 或得该方位上横向 或 纵向的 偏移\n  if (dir === 'top' || dir === 'bottom') {\n    if (dir === 'top') {\n      top = target.top - popup.extraOffset - popup.height;\n    } else {\n      top = target.bottom + popup.extraOffset;\n    }\n\n    // 解决横向偏移\n    const offset = arrow.width > target.width ? (arrow.width - target.width) / 2 : 0;\n    const minLeft = target.left + arrow.width - offset - popup.width;\n    const maxLeft = target.right - arrow.width + offset;\n    const centerLeft = target.left - (popup.width - target.width) / 2;\n\n    if (prefers.offset === 'left') {\n      left = minLeft;\n    } else if (prefers.offset === 'right') {\n      left = maxLeft;\n    } else {\n      left = centerLeft;\n    }\n\n    if (!prefers.forceOffset) {\n      left = Math.max(Math.min(edge.right - popup.width, left), minLeft);\n      left = Math.min(Math.max(edge.left, left), maxLeft);\n    }\n\n    arrowLeft = Math.min(popup.width - arrow.width, Math.max(target.left - (arrow.width - target.width) / 2 - left, 0));\n  } else {\n    if (dir === 'left') {\n      left = target.left - popup.extraOffset - popup.width;\n    } else {\n      left = target.right + popup.extraOffset;\n    }\n\n    // 解决纵向偏移\n    const offset = arrow.width > target.height ? (arrow.width - target.height) / 2 : 0;\n    const minTop = target.top + arrow.width - offset - popup.height;\n    const maxTop = target.bottom - arrow.width + offset;\n    const centerTop = target.top - (popup.height - target.height) / 2;\n\n    if (prefers.offset === 'top') {\n      top = minTop;\n    } else if (prefers.offset === 'bottom') {\n      top = maxTop;\n    } else {\n      top = centerTop;\n    }\n\n    if (!prefers.forceOffset) {\n      top = Math.max(Math.min(edge.bottom - popup.height, top), minTop);\n      top = Math.min(Math.max(edge.top, top), maxTop);\n    }\n\n    arrowTop = Math.min(popup.height - arrow.height, Math.max(target.top - (arrow.width - target.height) / 2 - top, 0));\n  }\n\n  return { dir, left, top, arrowLeft, arrowTop };\n}\n\nconst percentPresets: any = {\n  right: 1,\n  left: 0,\n  top: 0,\n  bottom: 1,\n  center: 0.5,\n};\n\nfunction isPercent(val: any) {\n  return /^[\\d.]+%$/.test(val);\n}\n\nfunction resolveRelativeValue(val: any, offset: any, total: any) {\n  if (!val) {\n    val = 0;\n  } else if (isPercent(val)) {\n    val = (parseFloat(val) / 100) * total;\n  } else if (percentPresets.hasOwnProperty(val)) {\n    val = percentPresets[val] * total;\n  } else {\n    val = parseFloat(val);\n    if (isNaN(val)) {\n      val = 0;\n    }\n  }\n\n  return `${val + offset}px`;\n}\n\nexport function resolveRelativePosition(align: any, popup: any, bounds: any) {\n  if (!align) {\n    // return default position\n    return {\n      top: '38.2%',\n      left: 'calc(50% - 110px)',\n    };\n  }\n\n  let [xAlign, yAlign] = align.trim().split(/\\s+/);\n\n  if (xAlign === 'top' || xAlign === 'bottom' || yAlign === 'left' || yAlign === 'right') {\n    const tmp = xAlign;\n    xAlign = yAlign;\n    yAlign = tmp;\n  }\n\n  if (xAlign === 'center' && !yAlign) {\n    yAlign = 'center';\n  }\n\n  return {\n    left: resolveRelativeValue(xAlign, 0, bounds.right - bounds.left - popup.width),\n    top: resolveRelativeValue(yAlign, 0, bounds.bottom - bounds.top - popup.height),\n  };\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/title/index.tsx",
    "content": "import { Component, isValidElement, ReactNode } from 'react';\nimport classNames from 'classnames';\nimport { createIcon, isI18nData, isTitleConfig } from '@alilc/lowcode-utils';\nimport { IPublicTypeI18nData, IPublicTypeTitleConfig, IPublicTypeTitleProps } from '@alilc/lowcode-types';\nimport { intl } from '../../intl';\nimport { Tip } from '../tip';\nimport './title.less';\n\n/**\n * 根据 keywords 将 label 分割成文字片段\n * 示例：title = '自定义页面布局'，keywords = '页面'，返回结果为 ['自定义', '页面', '布局']\n * @param label title\n * @param keywords 关键字\n * @returns 文字片段列表\n */\n function splitLabelByKeywords(label: string, keywords: string): string[] {\n  const len = keywords.length;\n  const fragments = [];\n  let str = label;\n\n  while (str.length > 0) {\n    const index = str.indexOf(keywords);\n\n    if (index === 0) {\n      fragments.push(keywords);\n      str = str.slice(len);\n    } else if (index < 0) {\n      fragments.push(str);\n      str = '';\n    } else {\n      fragments.push(str.slice(0, index));\n      str = str.slice(index);\n    }\n  }\n\n  return fragments;\n}\n\nexport class Title extends Component<IPublicTypeTitleProps> {\n  constructor(props: any) {\n    super(props);\n    this.handleClick = this.handleClick.bind(this);\n  }\n\n  handleClick(e: React.MouseEvent) {\n    const { title, onClick } = this.props as any;\n    const url = title && (title.docUrl || title.url);\n    if (url) {\n      window.open(url);\n      // 防止触发行操作（如折叠面板）\n      e.stopPropagation();\n    }\n    // TODO: 操作交互冲突，目前 mixedSetter 仅有 2 个 setter 注册时用到了 onClick\n    onClick && onClick(e);\n  }\n\n  renderLabel = (label: string | IPublicTypeI18nData | ReactNode) => {\n    let { match, keywords } = this.props;\n\n    if (!label) {\n      return null;\n    }\n\n    const intlLabel = intl(label);\n\n    if (typeof intlLabel !== 'string') {\n      return <span className=\"lc-title-txt\">{intlLabel}</span>;\n    }\n\n    let labelToRender: ReactNode = intlLabel;\n\n    if (match && keywords) {\n      const fragments = splitLabelByKeywords(intlLabel as string, keywords);\n\n      labelToRender = fragments.map(f => <span style={{ color: f === keywords ? 'red' : 'inherit' }}>{f}</span>);\n    }\n\n    return (\n      <span className=\"lc-title-txt\">{labelToRender}</span>\n    );\n  };\n\n  render() {\n    // eslint-disable-next-line prefer-const\n    const { title, className } = this.props;\n    let _title: IPublicTypeTitleConfig;\n    if (title == null) {\n      return null;\n    }\n    if (isValidElement(title)) {\n      return title;\n    }\n    if (typeof title === 'string' || isI18nData(title)) {\n      _title = { label: title };\n    } else if (isTitleConfig(title)) {\n      _title = title;\n    } else {\n      _title = {\n        label: title,\n      };\n    }\n\n    const icon = _title.icon ? createIcon(_title.icon, { size: 20 }) : null;\n\n    let tip: any = null;\n    if (_title.tip) {\n      if (isValidElement(_title.tip) && _title.tip.type === Tip) {\n        tip = _title.tip;\n      } else {\n        const tipProps =\n          typeof _title.tip === 'object' && !(isValidElement(_title.tip) || isI18nData(_title.tip))\n            ? _title.tip\n            : { children: _title.tip };\n        tip = <Tip {...tipProps} />;\n      }\n    }\n\n    return (\n      <span\n        className={classNames('lc-title', className, _title.className, {\n          'has-tip': !!tip,\n          'only-icon': !_title.label,\n        })}\n        onClick={this.handleClick}\n      >\n        {icon ? <b className=\"lc-title-icon\">{icon}</b> : null}\n        {this.renderLabel(_title.label)}\n        {tip}\n      </span>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-core/src/widgets/title/title.less",
    "content": ".lc-title {\n  display: inline-flex;\n  align-items: center;\n  color: var(--color-text);\n  .lc-title-icon {\n    display: flex;\n    align-items: center;\n    margin-right: 4px;\n    img {\n      width: 16px;\n      height: 16px;\n      filter: brightness(0) invert(1);\n    }\n  }\n  &.only-icon {\n    .lc-title-icon {\n      margin-right: 0;\n    }\n  }\n  &.has-tip {\n    cursor: help;\n    text-decoration-line: underline;\n    text-decoration-style: dashed;\n    text-decoration-color: var(--color-text-light, rgba(31, 56, 88, .3));\n  }\n  line-height: initial !important;\n  word-break: break-all;\n}\n\n.actived .lc-title {\n  color: var(--color-actived);\n}\n"
  },
  {
    "path": "packages/editor-core/test/command.test.ts",
    "content": "import { Command } from '../src/command';\n\ndescribe('Command', () => {\n  let commandInstance;\n  let mockHandler;\n\n  beforeEach(() => {\n    commandInstance = new Command();\n    mockHandler = jest.fn();\n  });\n\n  describe('registerCommand', () => {\n    it('should register a command successfully', () => {\n      const command = {\n        name: 'testCommand',\n        handler: mockHandler,\n      };\n      commandInstance.registerCommand(command, { commandScope: 'testScope' });\n\n      const registeredCommand = commandInstance.listCommands().find(c => c.name === 'testScope:testCommand');\n      expect(registeredCommand).toBeDefined();\n      expect(registeredCommand.name).toBe('testScope:testCommand');\n    });\n\n    it('should throw an error if commandScope is not provided', () => {\n      const command = {\n        name: 'testCommand',\n        handler: mockHandler,\n      };\n\n      expect(() => {\n        commandInstance.registerCommand(command);\n      }).toThrow('plugin meta.commandScope is required.');\n    });\n\n    it('should throw an error if command is already registered', () => {\n      const command = {\n        name: 'testCommand',\n        handler: mockHandler,\n      };\n      commandInstance.registerCommand(command, { commandScope: 'testScope' });\n\n      expect(() => {\n        commandInstance.registerCommand(command, { commandScope: 'testScope' });\n      }).toThrow(`Command 'testCommand' is already registered.`);\n    });\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n});\n\ndescribe('unregisterCommand', () => {\n  let commandInstance;\n  let mockHandler;\n\n  beforeEach(() => {\n    commandInstance = new Command();\n    mockHandler = jest.fn();\n    // 先注册一个命令以便之后注销\n    const command = {\n      name: 'testCommand',\n      handler: mockHandler,\n    };\n    commandInstance.registerCommand(command, { commandScope: 'testScope' });\n  });\n\n  it('should unregister a command successfully', () => {\n    const commandName = 'testScope:testCommand';\n    expect(commandInstance.listCommands().find(c => c.name === commandName)).toBeDefined();\n\n    commandInstance.unregisterCommand(commandName);\n\n    expect(commandInstance.listCommands().find(c => c.name === commandName)).toBeUndefined();\n  });\n\n  it('should throw an error if the command is not registered', () => {\n    const nonExistingCommandName = 'testScope:nonExistingCommand';\n    expect(() => {\n      commandInstance.unregisterCommand(nonExistingCommandName);\n    }).toThrow(`Command '${nonExistingCommandName}' is not registered.`);\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n});\n\ndescribe('executeCommand', () => {\n  let commandInstance;\n  let mockHandler;\n\n  beforeEach(() => {\n    commandInstance = new Command();\n    mockHandler = jest.fn();\n    // 注册一个带参数校验的命令\n    const command = {\n      name: 'testCommand',\n      handler: mockHandler,\n      parameters: [\n        { name: 'param1', propType: 'string' },\n        { name: 'param2', propType: 'number' }\n      ],\n    };\n    commandInstance.registerCommand(command, { commandScope: 'testScope' });\n  });\n\n  it('should execute a command successfully', () => {\n    const commandName = 'testScope:testCommand';\n    const args = { param1: 'test', param2: 42 };\n\n    commandInstance.executeCommand(commandName, args);\n\n    expect(mockHandler).toHaveBeenCalledWith(args);\n  });\n\n  it('should throw an error if the command is not registered', () => {\n    const nonExistingCommandName = 'testScope:nonExistingCommand';\n    expect(() => {\n      commandInstance.executeCommand(nonExistingCommandName, {});\n    }).toThrow(`Command '${nonExistingCommandName}' is not registered.`);\n  });\n\n  it('should throw an error if arguments are invalid', () => {\n    const commandName = 'testScope:testCommand';\n    const invalidArgs = { param1: 'test', param2: 'not-a-number' }; // param2 should be a number\n\n    expect(() => {\n      commandInstance.executeCommand(commandName, invalidArgs);\n    }).toThrow(`Command '${commandName}' arguments param2 is invalid.`);\n  });\n\n  it('should handle errors thrown by the command handler', () => {\n    const commandName = 'testScope:testCommand';\n    const args = { param1: 'test', param2: 42 };\n    const errorMessage = 'Command handler error';\n    mockHandler.mockImplementation(() => {\n      throw new Error(errorMessage);\n    });\n\n    expect(() => {\n      commandInstance.executeCommand(commandName, args);\n    }).toThrow(errorMessage);\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n});\n\ndescribe('batchExecuteCommand', () => {\n  let commandInstance;\n  let mockHandler;\n  let mockExecuteTransaction;\n  let mockPluginContext;\n\n  beforeEach(() => {\n    commandInstance = new Command();\n    mockHandler = jest.fn();\n    mockExecuteTransaction = jest.fn(callback => callback());\n    mockPluginContext = {\n      common: {\n        utils: {\n          executeTransaction: mockExecuteTransaction\n        }\n      }\n    };\n\n    // 注册几个命令\n    const command1 = {\n      name: 'testCommand1',\n      handler: mockHandler,\n    };\n    const command2 = {\n      name: 'testCommand2',\n      handler: mockHandler,\n    };\n    commandInstance.registerCommand(command1, { commandScope: 'testScope' });\n    commandInstance.registerCommand(command2, { commandScope: 'testScope' });\n  });\n\n  it('should execute a batch of commands', () => {\n    const commands = [\n      { name: 'testScope:testCommand1', args: { param: 'value1' } },\n      { name: 'testScope:testCommand2', args: { param: 'value2' } },\n    ];\n\n    commandInstance.batchExecuteCommand(commands, mockPluginContext);\n\n    expect(mockExecuteTransaction).toHaveBeenCalledTimes(1);\n    expect(mockHandler).toHaveBeenCalledWith({ param: 'value1' });\n    expect(mockHandler).toHaveBeenCalledWith({ param: 'value2' });\n  });\n\n  it('should not execute anything if commands array is empty', () => {\n    commandInstance.batchExecuteCommand([], mockPluginContext);\n\n    expect(mockExecuteTransaction).not.toHaveBeenCalled();\n    expect(mockHandler).not.toHaveBeenCalled();\n  });\n\n  it('should handle errors thrown during command execution', () => {\n    const errorMessage = 'Command handler error';\n    mockHandler.mockImplementation(() => {\n      throw new Error(errorMessage);\n    });\n\n    const commands = [\n      { name: 'testScope:testCommand1', args: { param: 'value1' } },\n      { name: 'testScope:testCommand2', args: { param: 'value2' } },\n    ];\n\n    expect(() => {\n      commandInstance.batchExecuteCommand(commands, mockPluginContext);\n    }).toThrow(errorMessage);\n\n    expect(mockExecuteTransaction).toHaveBeenCalledTimes(1); // Still called once\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n});\n\ndescribe('listCommands', () => {\n  let commandInstance;\n  let mockHandler;\n\n  beforeEach(() => {\n    commandInstance = new Command();\n    mockHandler = jest.fn();\n  });\n\n  it('should list all registered commands', () => {\n    // 注册几个命令\n    const command1 = {\n      name: 'testCommand1',\n      handler: mockHandler,\n      description: 'Test Command 1',\n      parameters: [{ name: 'param1', propType: 'string' }]\n    };\n    const command2 = {\n      name: 'testCommand2',\n      handler: mockHandler,\n      description: 'Test Command 2',\n      parameters: [{ name: 'param2', propType: 'number' }]\n    };\n    commandInstance.registerCommand(command1, { commandScope: 'testScope' });\n    commandInstance.registerCommand(command2, { commandScope: 'testScope' });\n\n    const listedCommands = commandInstance.listCommands();\n\n    expect(listedCommands.length).toBe(2);\n    expect(listedCommands).toEqual(expect.arrayContaining([\n      expect.objectContaining({\n        name: 'testScope:testCommand1',\n        description: 'Test Command 1',\n        parameters: [{ name: 'param1', propType: 'string' }]\n      }),\n      expect.objectContaining({\n        name: 'testScope:testCommand2',\n        description: 'Test Command 2',\n        parameters: [{ name: 'param2', propType: 'number' }]\n      })\n    ]));\n  });\n\n  it('should return an empty array if no commands are registered', () => {\n    const listedCommands = commandInstance.listCommands();\n    expect(listedCommands).toEqual([]);\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n});\n\ndescribe('onCommandError', () => {\n  let commandInstance;\n  let mockHandler;\n  let mockErrorHandler1;\n  let mockErrorHandler2;\n\n  beforeEach(() => {\n    commandInstance = new Command();\n    mockHandler = jest.fn();\n    mockErrorHandler1 = jest.fn();\n    mockErrorHandler2 = jest.fn();\n\n    // 注册一个命令，该命令会抛出错误\n    const command = {\n      name: 'testCommand',\n      handler: () => {\n        throw new Error('Command execution failed');\n      },\n    };\n    commandInstance.registerCommand(command, { commandScope: 'testScope' });\n  });\n\n  it('should call all registered error handlers when a command throws an error', () => {\n    const commandName = 'testScope:testCommand';\n    commandInstance.onCommandError(mockErrorHandler1);\n    commandInstance.onCommandError(mockErrorHandler2);\n\n    expect(() => {\n      commandInstance.executeCommand(commandName, {});\n    }).not.toThrow();\n\n    // 确保所有错误处理函数都被调用，并且传递了正确的参数\n    expect(mockErrorHandler1).toHaveBeenCalledWith(commandName, expect.any(Error));\n    expect(mockErrorHandler2).toHaveBeenCalledWith(commandName, expect.any(Error));\n  });\n\n  it('should throw the error if no error handlers are registered', () => {\n    const commandName = 'testScope:testCommand';\n\n    expect(() => {\n      commandInstance.executeCommand(commandName, {});\n    }).toThrow('Command execution failed');\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n});\n"
  },
  {
    "path": "packages/editor-core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"./src/\"]\n}\n"
  },
  {
    "path": "packages/editor-skeleton/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"build-plugin-fusion\",\n    [\"build-plugin-moment-locales\", {\n      \"locales\": [\"zh-cn\"]\n    }]\n  ]\n}\n"
  },
  {
    "path": "packages/editor-skeleton/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ],\n  \"babelPlugins\": [\n    [\"@babel/plugin-proposal-private-property-in-object\", { \"loose\": true }]\n  ]\n}\n"
  },
  {
    "path": "packages/editor-skeleton/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  // transform: {\n  //   '^.+\\\\.[jt]sx?$': 'babel-jest',\n  //   // '^.+\\\\.(ts|tsx)$': 'ts-jest',\n  //   // '^.+\\\\.(js|jsx)$': 'babel-jest',\n  // },\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: false,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    '!src/**/*.d.ts',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/editor-skeleton/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-editor-skeleton\",\n  \"version\": \"1.3.2\",\n  \"description\": \"alibaba lowcode editor skeleton\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"stylePath\": \"style.js\",\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"scripts\": {\n    \"test\": \"build-scripts test --config build.test.json\",\n    \"build\": \"build-scripts build\"\n  },\n  \"keywords\": [\n    \"lowcode\",\n    \"editor\"\n  ],\n  \"dependencies\": {\n    \"@alifd/next\": \"^1.20.12\",\n    \"@alilc/lowcode-designer\": \"1.3.2\",\n    \"@alilc/lowcode-editor-core\": \"1.3.2\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"react\": \"^16.8.1\",\n    \"react-dom\": \"^16.8.1\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.3\",\n    \"@types/react\": \"^16.9.13\",\n    \"@types/react-dom\": \"^16.9.4\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/editor-skeleton\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/area.ts",
    "content": "/* eslint-disable max-len */\nimport { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';\nimport { Logger } from '@alilc/lowcode-utils';\nimport { IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types';\nimport { WidgetContainer } from './widget/widget-container';\nimport { ISkeleton } from './skeleton';\nimport { IWidget } from './widget/widget';\n\nconst logger = new Logger({ level: 'warn', bizName: 'skeleton:area' });\nexport interface IArea<C, T> {\n  isEmpty(): boolean;\n  add(config: T | C): T;\n  remove(config: T | string): number;\n  setVisible(flag: boolean): void;\n  hide(): void;\n  show(): void;\n}\n\nexport class Area<C extends IPublicTypeWidgetBaseConfig = any, T extends IWidget = IWidget> implements IArea<C, T> {\n  @obx private _visible = true;\n\n  @computed get visible() {\n    if (this.exclusive) {\n      return this.container.current != null;\n    }\n    return this._visible;\n  }\n\n  get current() {\n    if (this.exclusive) {\n      return this.container.current;\n    }\n    return null;\n  }\n\n  readonly container: WidgetContainer<T, C>;\n\n  private lastCurrent: T | null = null;\n\n  constructor(readonly skeleton: ISkeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) {\n    makeObservable(this);\n    this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent);\n  }\n\n  isEmpty(): boolean {\n    return this.container.items.length < 1;\n  }\n\n  add(config: T | C): T {\n    const item = this.container.get(config.name);\n    if (item) {\n      logger.warn(`The ${config.name} has already been added to skeleton.`);\n      return item;\n    }\n    return this.container.add(config);\n  }\n\n  remove(config: T | string): number {\n    return this.container.remove(config);\n  }\n\n  setVisible(flag: boolean) {\n    if (this.exclusive) {\n      const { current } = this.container;\n      if (flag && !current) {\n        this.container.active(this.lastCurrent || this.container.getAt(0));\n      } else if (current) {\n        this.lastCurrent = current;\n        this.container.unactive(current);\n      }\n      return;\n    }\n    this._visible = flag;\n  }\n\n  hide() {\n    this.setVisible(false);\n  }\n\n  show() {\n    this.setVisible(true);\n  }\n\n  // ========== compatible for vision ========\n  /**\n   * @deprecated\n   */\n  removeAction(config: string): number {\n    return this.remove(config);\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/draggable-line/index.less",
    "content": ".lc-draggable-line-vertical {\n  position: absolute;\n  width: 4px;\n  height: 100%;\n  background-color: transparent;\n  cursor: col-resize;\n}\n\n.lc-draggable-line-horizontal {\n  position: absolute;\n  width: 100%;\n  height: 4px;\n  background-color: transparent;\n  cursor: row-resize;\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/draggable-line/index.tsx",
    "content": "import { Component } from 'react';\nimport classNames from 'classnames';\nimport './index.less';\n\nexport interface DraggableLineProps {\n  onDrag: (l: number, e: any) => any;\n  onDragStart?: () => any;\n  onDragEnd?: () => any;\n  position?: 'right' | 'left' | 'top';\n  className?: string;\n  maxIncrement?: number;\n  maxDecrement?: number;\n}\n\nexport default class DraggableLine extends Component<DraggableLineProps> {\n  static displayName = 'DraggableLine';\n\n  static defaultProps = {\n    onDrag() {},\n    position: 'right',\n    className: '',\n    maxIncrement: 100,\n    maxDecrement: 0,\n  };\n\n  private startDrag: boolean;\n  private canDrag: boolean;\n  private offset: number;\n  private currentOffset: number;\n  private offEvent: any;\n  private offDragEvent: any;\n  private startOffset: any;\n  private shell: HTMLElement | null = null;\n\n  constructor(props: DraggableLineProps) {\n    super(props);\n    this.startDrag = false;\n    this.canDrag = false;\n    this.offset = 0;\n    this.currentOffset = 0;\n  }\n\n  componentDidMount() {\n    this.offEvent = this.initEvent();\n  }\n\n  componentWillUnmount() {\n    if (this.offEvent) {\n      this.offEvent();\n    }\n  }\n\n  onSelectStart(e: any) {\n    if (this.startDrag) {\n      e.preventDefault();\n    }\n  }\n\n  onStartMove(e: any) {\n    const { onDragStart } = this.props;\n    if (!this.startDrag) {\n      onDragStart && onDragStart();\n    }\n    this.startDrag = true;\n    this.canDrag = true;\n    this.currentOffset = 0;\n    this.offDragEvent = this.initDragEvent();\n    this.startOffset = this.getClientPosition(e);\n  }\n\n  onEndMove() {\n    const { onDragEnd } = this.props;\n    if (this.startDrag) {\n      if (this.offDragEvent) {\n        this.offDragEvent();\n      }\n      this.startDrag = false;\n      this.offset = this.currentOffset;\n    }\n    onDragEnd && onDragEnd();\n  }\n\n  onDrag(e: any) {\n    const { position, onDrag, maxIncrement = 100, maxDecrement = 0 } = this.props;\n    if (this.startDrag) {\n      if (position === 'left' || position === 'top') {\n        this.currentOffset = this.offset + this.startOffset - this.getClientPosition(e);\n      } else {\n        this.currentOffset = this.offset + this.getClientPosition(e) - this.startOffset;\n      }\n\n      if (this.currentOffset < -maxDecrement) {\n        this.currentOffset = -maxDecrement;\n      } else if (this.currentOffset > maxIncrement) {\n        this.currentOffset = maxIncrement;\n      }\n\n      onDrag(this.currentOffset, e);\n    }\n  }\n\n  getClientPosition(e: any) {\n    const { position } = this.props;\n    return position === 'left' || position === 'right' ? e.clientX : e.clientY;\n  }\n\n  initEvent() {\n    const selectStart = this.onSelectStart.bind(this);\n    document.addEventListener('selectstart', selectStart);\n    return () => document.removeEventListener('selectstart', selectStart);\n  }\n\n  initDragEvent() {\n    const onDrag = this.onDrag.bind(this);\n    const onEndMove = this.onEndMove.bind(this);\n    document.addEventListener('mousemove', onDrag);\n    document.addEventListener('mouseup', onEndMove);\n    return () => {\n      document.removeEventListener('mousemove', onDrag);\n      document.removeEventListener('mouseup', onEndMove);\n    };\n  }\n\n  getParent() {\n    return this.shell?.parentElement;\n  }\n\n  render() {\n    const { className = '', position } = this.props;\n\n    return (\n      <div\n        ref={(ref) => { this.shell = ref; }}\n        className={classNames(\n          position === 'left' || position === 'right'\n            ? 'lc-draggable-line-vertical'\n            : 'lc-draggable-line-horizontal',\n          {\n            [className]: !!className,\n          },\n        )}\n        onMouseDown={(e) => this.onStartMove(e)}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/field/fields.tsx",
    "content": "/* eslint-disable react/no-unused-prop-types */\nimport { Component, ErrorInfo, MouseEvent } from 'react';\nimport { isObject } from 'lodash';\nimport classNames from 'classnames';\nimport { Icon } from '@alifd/next';\nimport { Title } from '@alilc/lowcode-editor-core';\nimport { IPublicModelEditor, IPublicTypeTitleContent } from '@alilc/lowcode-types';\nimport { PopupPipe, PopupContext } from '../popup';\nimport './index.less';\nimport InlineTip from './inlinetip';\nimport { intl } from '../../locale';\nimport { Logger } from '@alilc/lowcode-utils';\n\nconst logger = new Logger({ level: 'warn', bizName: 'skeleton:field' });\n\nexport interface FieldProps {\n  className?: string;\n  meta?: { package: string; componentName: string } | string;\n  title?: IPublicTypeTitleContent | null;\n  editor?: IPublicModelEditor;\n  defaultDisplay?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry';\n  collapsed?: boolean;\n  valueState?: number;\n  name?: string;\n  tip?: any;\n  onExpandChange?: (expandState: boolean) => void;\n  onClear?: () => void;\n}\n\nexport class Field extends Component<FieldProps> {\n  state = {\n    collapsed: this.props.collapsed,\n    display: this.props.defaultDisplay || 'inline',\n    hasError: false,\n  };\n\n  private body: HTMLDivElement | null = null;\n\n  private dispose?: () => void;\n\n  constructor(props: any) {\n    super(props);\n    this.handleClear = this.handleClear.bind(this);\n    this.clickHandler = this.clickHandler.bind(this);\n  }\n\n  private toggleExpand = () => {\n    const { onExpandChange } = this.props;\n    // eslint-disable-next-line react/no-access-state-in-setstate\n    const collapsed = !this.state.collapsed;\n    this.setState({\n      collapsed,\n    });\n    onExpandChange && onExpandChange(!collapsed);\n  };\n\n  private deployBlockTesting() {\n    if (this.dispose) {\n      this.dispose();\n    }\n    const { body } = this;\n    if (!body) {\n      return;\n    }\n    const check = () => {\n      const setter = body.firstElementChild;\n      if (setter && setter.classList.contains('lc-block-setter')) {\n        this.setState({\n          display: 'block',\n        });\n      } else {\n        this.setState({\n          display: 'inline',\n        });\n      }\n    };\n    const observer = new MutationObserver(check);\n    check();\n    observer.observe(body, {\n      childList: true,\n      subtree: true,\n      attributes: true,\n      attributeFilter: ['class'],\n    });\n    this.dispose = () => observer.disconnect();\n  }\n\n  private handleClear(e: React.MouseEvent) {\n    e.stopPropagation();\n    this.props.onClear && this.props.onClear();\n  }\n\n  componentDidMount() {\n    const { defaultDisplay } = this.props;\n    if (!defaultDisplay || defaultDisplay === 'inline') {\n      this.deployBlockTesting();\n    }\n  }\n\n  componentWillUnmount() {\n    if (this.dispose) {\n      this.dispose();\n    }\n  }\n\n  static getDerivedStateFromError() {\n    return {\n      hasError: true,\n    };\n  }\n\n  componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n    logger.error(`${this.props.title} has error`, error, errorInfo);\n  }\n\n  getTipContent(propName: string, tip?: any): any {\n    let tipContent = (\n      <div>\n        <div>{intl('Attribute: ')}{propName}</div>\n      </div>\n    );\n\n    if (isObject(tip)) {\n      tipContent = (\n        <div>\n          <div>{intl('Attribute: ')}{propName}</div>\n          <div>{intl('Description: ')}{(tip as any).content}</div>\n        </div>\n      );\n    } else if (tip) {\n      tipContent = (\n        <div>\n          <div>{intl('Attribute: ')}{propName}</div>\n          <div>{intl('Description: ')}{tip}</div>\n        </div>\n      );\n    }\n    return tipContent;\n  }\n\n  clickHandler(event?: MouseEvent) {\n    const { editor, name, title, meta } = this.props;\n    editor?.eventBus.emit('setting.setter.field.click', { name, title, meta, event });\n  }\n\n  render() {\n    const { hasError } = this.state;\n    if (hasError) {\n      return null;\n    }\n\n    const { className, children, meta, title, valueState, name: propName, tip } = this.props;\n    const { display, collapsed } = this.state;\n    const isAccordion = display === 'accordion';\n    let hostName = '';\n    if (typeof meta === 'object') {\n      hostName = `${meta?.package || ''}-${meta.componentName || ''}`;\n    } else if (typeof meta === 'string') {\n      hostName = meta;\n    }\n    const id = `${hostName}-${propName || (title as any)['en-US'] || (title as any)['zh-CN']}`;\n    const tipContent = this.getTipContent(propName!, tip);\n    return (\n      <div\n        className={classNames(`lc-field lc-${display}-field`, className, {\n          'lc-field-is-collapsed': isAccordion && collapsed,\n        })}\n        id={id}\n      >\n        {\n          display !== 'plain' && (\n            <div className=\"lc-field-head\" onClick={isAccordion ? this.toggleExpand : undefined}>\n              <div className=\"lc-field-title\">\n                {createValueState(valueState, this.handleClear)}\n                <Title\n                  title={title || ''}\n                  onClick={this.clickHandler}\n                />\n                <InlineTip position=\"top\">{tipContent}</InlineTip>\n              </div>\n              {isAccordion && <Icon className=\"lc-field-icon\" type=\"arrow-up\" size=\"xs\" />}\n            </div>\n          )\n        }\n        <div key=\"body\" ref={(shell) => { this.body = shell; }} className=\"lc-field-body\">\n          {children}\n        </div>\n      </div>\n    );\n  }\n}\n\n/**\n * **交互专利点**\n *\n * -1 多种值\n * 0 | null 无值\n * 1 类似值，比如数组长度一样\n * 2 单一植\n * 10 必填\n *\n * TODO: turn number to enum\n */\nfunction createValueState(/* valueState?: number, onClear?: (e: React.MouseEvent) => void */) {\n  return null;\n}\n\nexport interface PopupFieldProps extends FieldProps {\n  width?: number;\n}\n\nexport class PopupField extends Component<PopupFieldProps> {\n  static contextType = PopupContext;\n\n  private pipe: any;\n\n  static defaultProps: PopupFieldProps = {\n    width: 300,\n  };\n\n  render() {\n    const { className, children, title, width } = this.props;\n    if (!this.pipe) {\n      this.pipe = (this.context as PopupPipe).create({ width });\n    }\n\n    const titleElement = title && (\n      <div className=\"lc-field-title\">\n        <Title title={title} />\n      </div>\n    );\n\n    this.pipe.send(<div className=\"lc-field-body\">{children}</div>, titleElement);\n\n    return (\n      <div className={classNames('lc-field lc-popup-field', className)}>\n        {title && (\n          <div\n            className=\"lc-field-head\"\n            onClick={(e) => {\n              this.pipe.show((e as any).target);\n            }}\n          >\n            <div className=\"lc-field-title\">\n              <Title title={title} />\n            </div>\n            <Icon className=\"lc-field-icon\" type=\"arrow-left\" size=\"xs\" />\n          </div>\n        )}\n      </div>\n    );\n  }\n}\n\nexport interface EntryFieldProps extends FieldProps {\n  stageName?: string;\n}\n\nexport class EntryField extends Component<EntryFieldProps> {\n  render() {\n    const { title, className, stageName } = this.props;\n    const classNameList = classNames('lc-field', 'lc-entry-field', className);\n\n    return (\n      <div className={classNameList}>\n        <div className=\"lc-field-head\" data-stage-target={stageName}>\n          <div className=\"lc-field-title\">\n            <Title title={title || ''} />\n          </div>\n          <Icon className=\"lc-field-icon\" type=\"arrow-right\" size=\"xs\" />\n        </div>\n      </div>\n    );\n  }\n}\n\nexport class PlainField extends Component<FieldProps> {\n  render() {\n    const { className, children } = this.props;\n    return (\n      <div className={classNames('lc-field lc-plain-field', className)}>\n        <div className=\"lc-field-body\">{children}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/field/index.less",
    "content": "@x-gap: 12px;\n@y-gap: 8px;\n\n.lc-settings-content > .lc-field:first-child > .lc-field-head {\n  border-top: none !important;\n}\n\n.lc-field {\n  .lc-field-head {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n\n    .lc-field-title {\n      display: flex;\n      align-items: center;\n    }\n    .lc-field-icon {\n      transform-origin: center;\n      transition: transform 0.1s;\n    }\n  }\n\n  &.lc-inline-field {\n    display: flex;\n    align-items: center;\n    margin: 12px;\n\n    > .lc-field-head {\n      width: 70px;\n      margin-right: 1px;\n      .lc-title-label {\n        width: 70px;\n        word-break: break-all;\n      }\n    }\n    > .lc-field-body {\n      flex: 1;\n      min-width: 0;\n      display: flex;\n      align-items: center;\n    }\n  }\n\n  &.lc-block-field, &.lc-accordion-field, &.lc-entry-field {\n    display: block;\n\n    > .lc-field-head {\n      height: 32px;\n      display: flex;\n      align-items: center;\n      font-weight: 500;\n      background: var(--color-block-background-shallow, rgba(31,56,88,.06));\n      border-top: 1px solid var(--color-line-normal,rgba(31,56,88,.1));\n      border-bottom: 1px solid var(--color-line-normal,rgba(31,56,88,.1));\n      color: var(--color-title);\n      padding: 0 12px;\n      user-select: none;\n\n      > .lc-field-icon {\n        color: var(--color-icon-normal, #8f9bb3);\n      }\n    }\n\n    > .lc-field-body {\n      padding: 12px;\n\n      .lc-inline-field {\n        margin: 12px 0;\n\n        &:first-child {\n          margin-top: 0;\n        }\n        &:last-child {\n          margin-bottom: 0;\n        }\n      }\n    }\n  }\n\n  &.lc-entry-field {\n    margin-bottom: 6px;\n\n    > .lc-field-head {\n      cursor: pointer;\n    }\n  }\n\n  .lc-setter-actions {\n    display: flex;\n    align-items: center;\n  }\n\n  &.lc-block-field {\n    position: relative;\n    >.lc-field-body>.lc-block-setter>.lc-setter-actions {\n      position: absolute;\n      right: 10px;\n      top: 0;\n      height: 32px;\n    }\n  }\n\n  &.lc-accordion-field {\n    position: relative;\n\n    > .lc-field-head {\n      cursor: pointer;\n    }\n\n    &.lc-field-is-collapsed {\n      margin-bottom: 6px;\n    }\n\n    &.lc-field-is-collapsed {\n      > .lc-field-head .lc-field-icon {\n        transform: rotate(180deg);\n      }\n      > .lc-field-body {\n        display: none;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/field/index.ts",
    "content": "import { ReactNode, createElement } from 'react';\nimport { IPublicTypeTitleContent } from '@alilc/lowcode-types';\nimport './index.less';\nimport { Field, PopupField, EntryField, PlainField } from './fields';\n\nexport interface FieldProps {\n  className?: string;\n  title?: IPublicTypeTitleContent | null;\n  display?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry';\n  collapsed?: boolean;\n  valueState?: number;\n  onExpandChange?: (collapsed: boolean) => void;\n  onClear?: () => void;\n  [extra: string]: any;\n}\n\nexport function createField(props: FieldProps, children: ReactNode, type?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry'): ReactNode {\n  if (type === 'popup') {\n    return createElement(PopupField, props, children);\n  }\n  if (type === 'entry') {\n    return createElement(EntryField, props, children);\n  }\n  if (type === 'plain' || !props.title) {\n    return createElement(PlainField, props, children);\n  }\n  return createElement(Field, { ...props, defaultDisplay: type }, children);\n}\n\nexport { Field, PopupField, EntryField, PlainField };\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/field/inlinetip.tsx",
    "content": "import * as React from 'react';\n\nexport interface InlineTipProps {\n  position: string;\n  theme?: 'green' | 'black';\n  children: React.ReactNode;\n}\n\nexport default class InlineTip extends React.Component<InlineTipProps> {\n  static displayName = 'InlineTip';\n\n  static defaultProps = {\n    position: 'auto',\n    theme: 'black',\n  };\n\n  render(): React.ReactNode {\n    const { position, theme, children } = this.props;\n    return (\n      <div style={{ display: 'none' }} data-role=\"tip\" data-position={position} data-theme={theme}>\n        {children}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/popup/index.tsx",
    "content": "import { createContext, ReactNode, Component, PureComponent } from 'react';\nimport { Drawer, ConfigProvider } from '@alifd/next';\nimport { uniqueId } from '@alilc/lowcode-utils';\nimport { IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport './style.less';\n\nexport interface PopupExtProps {\n  width?: number;\n  hasMask?: boolean;\n  trigger?: ReactNode;\n  canCloseByOutSideClick?: boolean\n  className?: string;\n  safeNode?: string[];\n}\n\ninterface PopupProps extends PopupExtProps{\n  content?: ReactNode,\n  title?: ReactNode,\n  actionKey?: string\n}\n\n\nexport const PopupContext = createContext<PopupPipe>({} as any);\n\nexport class PopupPipe {\n  private emitter: IEventBus = createModuleEventBus('PopupPipe');\n\n  private currentId?: string;\n\n  create(props?: PopupExtProps): {\n    send: (content: ReactNode, title: ReactNode) => void;\n    show: (target: Element) => void;\n  } {\n    let sendContent: ReactNode = null;\n    let sendTitle: ReactNode = null;\n    const id = uniqueId('popup');\n    return {\n      send: (content: ReactNode, title: ReactNode) => {\n        sendContent = content;\n        sendTitle = title;\n        if (this.currentId === id) {\n          this.popup({\n            ...props,\n            content,\n            title,\n          });\n        }\n      },\n      show: (target: Element, actionKey?: string) => {\n        this.currentId = id;\n        this.popup(\n          {\n            ...props,\n            actionKey,\n            content: sendContent,\n            title: sendTitle,\n          },\n          target,\n        );\n      },\n    };\n  }\n\n  private popup(props: PopupProps, target?: Element) {\n    Promise.resolve().then(() => {\n      this.emitter.emit('popupchange', props, target);\n    });\n  }\n\n  onPopupChange(fn: (props: PopupProps, target?: Element) => void): () => void {\n    this.emitter.on('popupchange', fn);\n    return () => {\n      this.emitter.removeListener('popupchange', fn);\n    };\n  }\n\n  purge() {\n    this.emitter.removeAllListeners();\n  }\n}\n\nexport default class PopupService extends Component<{\n  popupPipe?: PopupPipe;\n  actionKey?: string;\n  safeId?: string;\n  popupContainer?: string;\n}> {\n  private popupPipe = this.props.popupPipe || new PopupPipe();\n\n  componentWillUnmount() {\n    this.popupPipe.purge();\n  }\n\n  render() {\n    const { children, actionKey, safeId, popupContainer } = this.props;\n    return (\n      <PopupContext.Provider value={this.popupPipe}>\n        {children}\n        <PopupContent key={`pop${actionKey}`} safeId={safeId} popupContainer={popupContainer} />\n      </PopupContext.Provider>\n    );\n  }\n}\n\ninterface StateType extends PopupProps {\n  visible?: boolean, \n  offsetX?: number, \n  pos?: {top: number, height: number}\n}\nexport class PopupContent extends PureComponent<{ safeId?: string; popupContainer?: string }> {\n  static contextType = PopupContext;\n\n  popupContainerId = uniqueId('popupContainer');\n\n  state: StateType = {\n    visible: false,\n    offsetX: -300,\n  };\n\n  private dispose = (this.context as PopupPipe).onPopupChange((props, target) => {\n    const state: StateType = {\n      ...props,\n      visible: true,\n    };\n    if (target) {\n      const rect = target.getBoundingClientRect();\n      state.pos = {\n        top: rect.top,\n        height: rect.height,\n      };\n      // todo: compute the align method\n    }\n    this.setState(state);\n  });\n\n  componentDidMount() {\n    const clientWidth = document.documentElement.clientWidth || document.body.clientWidth;\n    if (clientWidth >= 1860) {\n      this.setState({\n        offsetX: -400,\n      });\n    }\n  }\n\n  componentWillUnmount() {\n    this.dispose();\n  }\n\n  onClose = () => {\n    this.setState({\n      visible: false,\n    });\n  };\n\n  render() {\n    const { content, visible, title, actionKey, pos, offsetX, width = 360, hasMask = false, canCloseByOutSideClick = true, safeNode = [] } = this.state;\n    if (!visible) {\n      return null;\n    }\n\n    let avoidLaterHidden = true;\n    setTimeout(() => {\n      avoidLaterHidden = false;\n    }, 10);\n\n    const id = uniqueId('ball');\n\n    return (\n      <Drawer\n        width={width}\n        visible={visible}\n        offset={[offsetX, 0]}\n        hasMask={hasMask}\n        onVisibleChange={(_visible, type) => {\n          if (avoidLaterHidden) {\n            return;\n          }\n          if (!_visible && type === 'closeClick') {\n            this.setState({ visible: false });\n          }\n        }}\n        trigger={<div className=\"lc-popup-placeholder\" style={pos} />}\n        triggerType=\"click\"\n        canCloseByOutSideClick={canCloseByOutSideClick}\n        animation={false}\n        onClose={this.onClose}\n        id={this.props.safeId}\n        safeNode={[id, ...safeNode]}\n        closeable\n        container={this.props.popupContainer}\n      >\n        <div className=\"lc-ballon-title\">{title}</div>\n        <div className=\"lc-ballon-content\">\n          <PopupService actionKey={actionKey} safeId={id} popupContainer={this.popupContainerId}>\n            <ConfigProvider popupContainer={this.popupContainerId}>\n              {content}\n            </ConfigProvider>\n          </PopupService>\n        </div>\n        <div id={this.popupContainerId} />\n        <div id=\"engine-variable-setter-dialog\" />\n        <div id=\"engine-popup-container\" />\n      </Drawer>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/popup/style.less",
    "content": ".lc-popup-placeholder {\n  position: fixed;\n  width: 100%;\n  pointer-events: none;\n}\n\n.lc-ballon {\n  padding: 10px;\n  max-width: 640px;\n  width: 640px;\n  .lc-ballon-title {\n    font-size: 14px;\n  }\n  .lc-ballon-content {\n    margin-top: 10px;\n    // FIXME: popup position is bad\n    max-height: calc(60vh);\n    overflow-x: hidden;\n    overflow-y: auto;\n  }\n  &.next-balloon-closable {\n    padding: 10px !important;\n  }\n  .next-balloon-close {\n    top: 4px !important;\n    right: 4px !important;\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/settings/index.ts",
    "content": "import './style.less';\n\nexport * from './settings-primary-pane';\nexport * from './settings-pane';\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/settings/main.ts",
    "content": "import { Node, Designer, Selection, SettingTopEntry } from '@alilc/lowcode-designer';\nimport { Editor, obx, computed, makeObservable, action, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\n\nfunction generateSessionId(nodes: Node[]) {\n  return nodes\n    .map((node) => node.id)\n    .sort()\n    .join(',');\n}\n\nexport class SettingsMain {\n  private emitter: IEventBus = createModuleEventBus('SettingsMain');\n\n  private _sessionId = '';\n\n  @obx.ref private _settings?: SettingTopEntry;\n\n  @computed get length(): number | undefined {\n    return this._settings?.nodes.length;\n  }\n\n  @computed get componentMeta() {\n    return this._settings?.componentMeta;\n  }\n\n  @computed get settings() {\n    return this._settings;\n  }\n\n  private disposeListener: () => void;\n\n  private designer?: Designer;\n\n  constructor(readonly editor: Editor) {\n    makeObservable(this);\n    this.init();\n  }\n\n  private async init() {\n    const setupSelection = (selection?: Selection) => {\n      if (selection) {\n        this.setup(selection.getNodes());\n      } else {\n        this.setup([]);\n      }\n    };\n    this.editor.eventBus.on('designer.selection.change', setupSelection);\n    this.disposeListener = () => {\n      this.editor.removeListener('designer.selection.change', setupSelection);\n    };\n    const designer = await this.editor.onceGot('designer');\n    this.designer = designer;\n    setupSelection(designer.currentSelection);\n  }\n\n  @action\n  private setup(nodes: Node[]) {\n    // check nodes change\n    const sessionId = generateSessionId(nodes);\n    if (sessionId === this._sessionId) {\n      return;\n    }\n    this._sessionId = sessionId;\n    if (nodes.length < 1) {\n      this._settings = undefined;\n      return;\n    }\n\n    if (!this.designer) {\n      this.designer = nodes[0].document.designer;\n    }\n    // 当节点只有一个时，复用 node 上挂载的 settingEntry，不会产生平行的两个实例，这样在整个系统中对\n    // 某个节点操作的 SettingTopEntry 只有一个实例，后续的 getProp() 也会拿到相同的 SettingField 实例\n    if (nodes.length === 1) {\n      this._settings = nodes[0].settingEntry;\n    } else {\n      this._settings = this.designer.createSettingEntry(nodes);\n    }\n  }\n\n  purge() {\n    this.disposeListener();\n    this.emitter.removeAllListeners();\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/settings/settings-pane.tsx",
    "content": "import { Component, MouseEvent, Fragment, ReactNode } from 'react';\nimport { shallowIntl, observer, obx, engineConfig, runInAction } from '@alilc/lowcode-editor-core';\nimport { createContent, isJSSlot, isSetterConfig, shouldUseVariableSetter } from '@alilc/lowcode-utils';\nimport { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton';\nimport { IPublicApiSetters, IPublicTypeCustomView, IPublicTypeDynamicProps } from '@alilc/lowcode-types';\nimport { ISettingEntry, IComponentMeta, ISettingField, isSettingField, ISettingTopEntry } from '@alilc/lowcode-designer';\nimport { createField } from '../field';\nimport PopupService, { PopupPipe } from '../popup';\nimport { SkeletonContext } from '../../context';\nimport { intl } from '../../locale';\n\nfunction isStandardComponent(componentMeta: IComponentMeta | null) {\n  if (!componentMeta) return false;\n  const { prototype } = componentMeta;\n  return prototype == null;\n}\n\n/**\n * 判断 initialValue 是否为非空，非空条件：\n *  1. 当为 slot 结构时，value 为有长度的数组且 visible 不为 false\n *  2. 不为 slot 结构，为非 undefined / null 值\n * @param initialValue\n * @returns\n */\nfunction isInitialValueNotEmpty(initialValue: any) {\n  if (isJSSlot(initialValue)) {\n    // @ts-ignore visible 为 false 代表默认不展示\n    return initialValue.visible !== false && Array.isArray(initialValue.value) && initialValue.value.length > 0;\n  }\n  return (initialValue !== undefined && initialValue !== null);\n}\n\ntype SettingFieldViewProps = { field: ISettingField };\ntype SettingFieldViewState = { fromOnChange: boolean; value: any };\n\n@observer\nclass SettingFieldView extends Component<SettingFieldViewProps, SettingFieldViewState> {\n  static contextType = SkeletonContext;\n\n  stageName: string | undefined;\n\n  setters?: IPublicApiSetters;\n\n  constructor(props: SettingFieldViewProps) {\n    super(props);\n\n    const { field } = this.props;\n    const { extraProps } = field;\n    const { display } = extraProps;\n\n    const editor = field.designer?.editor;\n    const skeleton = editor?.get('skeleton') as Skeleton;\n    const { stages } = skeleton || {};\n    this.setters = editor?.get('setters');\n    let stageName;\n    if (display === 'entry') {\n      runInAction(() => {\n        stageName = `${field.getNode().id}_${field.name?.toString()}`;\n        // 清除原 stage，不然 content 引用的一直是老的 field，导致数据无法得到更新\n        stages.container.remove(stageName);\n        stages.add({\n          type: 'Widget',\n          name: stageName,\n          content: <Fragment>{field.items.map((item, index) => createSettingFieldView(item, field, index))}</Fragment>,\n          props: {\n            title: field.title,\n          },\n        });\n      });\n    }\n    this.stageName = stageName;\n  }\n\n  get field() {\n    return this.props.field;\n  }\n\n  get visible() {\n    const { extraProps } = this.field;\n    const { condition } = extraProps;\n    try {\n      return typeof condition === 'function' ? condition(this.field.internalToShellField()) !== false : true;\n    } catch (error) {\n      console.error('exception when condition (hidden) is excuted', error);\n    }\n\n    return true;\n  }\n\n  get ignoreDefaultValue(): boolean {\n    const { extraProps } = this.field;\n    const { ignoreDefaultValue } = extraProps;\n    try {\n      if (typeof ignoreDefaultValue === 'function') {\n        return ignoreDefaultValue(this.field.internalToShellField());\n      }\n      return false;\n    } catch (error) {\n      console.error('exception when ignoreDefaultValue is excuted', error);\n    }\n\n    return false;\n  }\n\n  get setterInfo(): {\n    setterProps: any;\n    initialValue: any;\n    setterType: any;\n  } {\n    const { extraProps, componentMeta } = this.field;\n    const { defaultValue } = extraProps;\n\n    const { setter } = this.field;\n    let setterProps: {\n      setters?: (ReactNode | string)[];\n    } & Record<string, unknown> | IPublicTypeDynamicProps = {};\n    let setterType: any;\n    let initialValue: any = null;\n\n    if (Array.isArray(setter)) {\n      setterType = 'MixedSetter';\n      setterProps = {\n        setters: setter,\n      };\n    } else if (isSetterConfig(setter)) {\n      setterType = setter.componentName;\n      if (setter.props) {\n        setterProps = setter.props;\n        if (typeof setterProps === 'function') {\n          setterProps = setterProps(this.field.internalToShellField());\n        }\n      }\n      if (setter.initialValue != null) {\n        initialValue = setter.initialValue;\n      }\n    } else if (setter) {\n      setterType = setter;\n    }\n\n    if (defaultValue != null && !('defaultValue' in setterProps)) {\n      setterProps.defaultValue = defaultValue;\n      if (initialValue == null) {\n        initialValue = defaultValue;\n      }\n    }\n\n    if (this.field.valueState === -1) {\n      setterProps.multiValue = true;\n      if (!('placeholder' in setterProps)) {\n        setterProps.placeholder = intl('Multiple Value');\n      }\n    }\n\n    // 根据是否支持变量配置做相应的更改\n    const supportVariable = this.field.extraProps?.supportVariable;\n    // supportVariableGlobally 只对标准组件生效，vc 需要单独配置\n    const supportVariableGlobally = engineConfig.get('supportVariableGlobally', false) && isStandardComponent(componentMeta);\n    const isUseVariableSetter = shouldUseVariableSetter(supportVariable, supportVariableGlobally);\n    if (isUseVariableSetter === false) {\n      return {\n        setterProps,\n        initialValue,\n        setterType,\n      };\n    }\n\n    if (setterType === 'MixedSetter') {\n      // VariableSetter 不单独使用\n      if (Array.isArray(setterProps.setters) && !setterProps.setters.includes('VariableSetter')) {\n        setterProps.setters.push('VariableSetter');\n      }\n    } else {\n      setterType = 'MixedSetter';\n      setterProps = {\n        setters: [\n          setter,\n          'VariableSetter',\n        ],\n      };\n    }\n    return {\n      setterProps,\n      initialValue,\n      setterType,\n    };\n  }\n\n  get value() {\n    return this.field.valueState === -1 ? null : this.field.getValue();\n  }\n\n  initDefaultValue() {\n    const { initialValue } = this.setterInfo;\n    if (this.state?.fromOnChange ||\n      !isInitialValueNotEmpty(initialValue) ||\n      this.ignoreDefaultValue ||\n      this.value !== undefined\n    ) {\n      return;\n    }\n    // 当前 field 没有 value 值时，将 initialValue 写入 field\n    // 之所以用 initialValue，而不是 defaultValue 是为了保持跟 props.onInitial 的逻辑一致\n    const _initialValue = typeof initialValue === 'function' ? initialValue(this.field.internalToShellField()) : initialValue;\n    this.field.setValue(_initialValue);\n  }\n\n  componentDidMount() {\n    this.initDefaultValue();\n  }\n\n  render() {\n    const field = this.field;\n    const { extraProps } = field;\n    const visible = this.visible;\n\n    if (!visible) {\n      return null;\n    }\n\n    const {\n      setterProps = {},\n      setterType,\n      initialValue = null,\n    } = this.setterInfo;\n\n    const value = this.value;\n\n    let onChangeAPI = extraProps?.onChange;\n    let stageName = this.stageName;\n\n    return createField(\n      {\n        meta: field?.componentMeta?.npm || field?.componentMeta?.componentName || '',\n        title: field.title,\n        // editor: field.editor,\n        collapsed: !field.expanded,\n        valueState: field.isRequired ? 10 : field.valueState,\n        onExpandChange: (expandState) => field.setExpanded(expandState),\n        onClear: () => field.clearValue(),\n        // field: field,\n        // stages,\n        stageName,\n        ...extraProps,\n      },\n      !stageName &&\n      this.setters?.createSetterContent(setterType, {\n        ...shallowIntl(setterProps),\n        forceInline: extraProps.forceInline,\n        key: field.id,\n        // === injection\n        prop: field.internalToShellField(), // for compatible vision\n        selected: field.top?.getNode()?.internalToShellNode(),\n        field: field.internalToShellField(),\n        // === IO\n        value, // reaction point\n        initialValue,\n        onChange: (value: any) => {\n          this.setState({\n            fromOnChange: true,\n            // eslint-disable-next-line react/no-unused-state\n            value,\n          });\n          field.setValue(value, true);\n          if (onChangeAPI) onChangeAPI(value, field.internalToShellField());\n        },\n        onInitial: () => {\n          if (initialValue == null) {\n            return;\n          }\n          const value = typeof initialValue === 'function' ? initialValue(field.internalToShellField()) : initialValue;\n          this.setState({\n            // eslint-disable-next-line react/no-unused-state\n            value,\n          });\n          field.setValue(value, true);\n        },\n\n        removeProp: () => {\n          if (field.name) {\n            field.parent.clearPropValue(field.name);\n          }\n        },\n      }),\n      extraProps.forceInline ? 'plain' : extraProps.display,\n    );\n  }\n}\n\ntype SettingGroupViewProps = SettingFieldViewProps;\n@observer\nclass SettingGroupView extends Component<SettingGroupViewProps> {\n  static contextType = SkeletonContext;\n\n  stageName: string | undefined;\n\n  constructor(props: SettingGroupViewProps) {\n    super(props);\n    const { field } = this.props;\n    const { extraProps } = field;\n    const { display } = extraProps;\n    const editor = this.props.field.designer?.editor;\n    const { stages } = editor?.get('skeleton') as Skeleton;\n    // const items = field.items;\n\n    let stageName;\n    if (display === 'entry') {\n      runInAction(() => {\n        stageName = `${field.getNode().id}_${field.name?.toString()}`;\n        // 清除原 stage，不然 content 引用的一直是老的 field，导致数据无法得到更新\n        stages.container.remove(stageName);\n        stages.add({\n          type: 'Widget',\n          name: stageName,\n          content: <Fragment>{field.items.map((item, index) => createSettingFieldView(item, field, index))}</Fragment>,\n          props: {\n            title: field.title,\n          },\n        });\n      });\n    }\n    this.stageName = stageName;\n  }\n\n  render() {\n    const { field } = this.props;\n    const { extraProps } = field;\n    const { condition, display } = extraProps;\n    const visible = field.isSingle && typeof condition === 'function' ? condition(field.internalToShellField()) !== false : true;\n\n    if (!visible) {\n      return null;\n    }\n\n    // todo: split collapsed state | field.items for optimize\n    return createField(\n      {\n        meta: field.componentMeta?.npm || field.componentMeta?.componentName || '',\n        title: field.title,\n        // editor: field.editor,\n        collapsed: !field.expanded,\n        onExpandChange: (expandState) => field.setExpanded(expandState),\n        // field: field,\n        // stages,\n        stageName: this.stageName,\n      },\n      field.items.map((item, index) => createSettingFieldView(item, field, index)),\n      display,\n    );\n  }\n}\n\nexport function createSettingFieldView(field: ISettingField | IPublicTypeCustomView, fieldEntry: ISettingEntry, index?: number) {\n  if (isSettingField(field)) {\n    if (field.isGroup) {\n      return <SettingGroupView field={field} key={field.id} />;\n    } else {\n      return <SettingFieldView field={field} key={field.id} />;\n    }\n  } else {\n    return createContent(field, { key: index, field: fieldEntry });\n  }\n}\n\nexport type SettingsPaneProps = {\n  target: ISettingTopEntry | ISettingField;\n  usePopup?: boolean;\n};\n\n@observer\nexport class SettingsPane extends Component<SettingsPaneProps> {\n  static contextType = SkeletonContext;\n\n  @obx private currentStage?: Stage;\n\n  private popupPipe = new PopupPipe();\n\n  private pipe = this.popupPipe.create();\n\n  private handleClick = (e: MouseEvent) => {\n    // compatiable vision stageBox\n    // TODO: optimize these codes\n    const { usePopup = true } = this.props;\n    if (!usePopup) return;\n    const pane = e.currentTarget as HTMLDivElement;\n    function getTarget(node: any): any {\n      if (!pane.contains(node) || (node.nodeName === 'A' && node.getAttribute('href'))) {\n        return null;\n      }\n\n      const target = node.dataset ? node.dataset.stageTarget : null;\n      if (target) {\n        return target;\n      }\n      return getTarget(node.parentNode);\n    }\n    const target = getTarget(e.target);\n    if (!target) {\n      return;\n    }\n\n    const skeleton = this.context as Skeleton;\n    if (!skeleton || !skeleton.stages) {\n      return;\n    }\n    const stage = skeleton.stages.container.get(target);\n    if (stage) {\n      if (this.currentStage) {\n        stage.setPrevious(this.currentStage);\n      }\n      this.currentStage = stage;\n    }\n  };\n\n  private popStage() {\n    this.currentStage = this.currentStage?.getPrevious();\n  }\n\n  render() {\n    const { target } = this.props;\n    const { items } = target;\n\n    return (\n      <div className=\"lc-settings-pane\" onClick={this.handleClick}>\n        {/* todo: add head for single use */}\n        <PopupService popupPipe={this.popupPipe}>\n          <div className=\"lc-settings-content\">\n            {items.map((item, index) => createSettingFieldView(item, target, index))}\n          </div>\n        </PopupService>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx",
    "content": "import React, { Component } from 'react';\nimport { Tab, Breadcrumb } from '@alifd/next';\nimport { Title, observer, Editor, obx, globalContext, engineConfig, makeObservable } from '@alilc/lowcode-editor-core';\nimport { Node, SettingField, isSettingField, INode } from '@alilc/lowcode-designer';\nimport classNames from 'classnames';\nimport { SettingsMain } from './main';\nimport { SettingsPane } from './settings-pane';\nimport { StageBox } from '../stage-box';\nimport { SkeletonContext } from '../../context';\nimport { intl } from '../../locale';\nimport { createIcon } from '@alilc/lowcode-utils';\n\ninterface ISettingsPrimaryPaneProps {\n  engineEditor: Editor;\n  config: any;\n}\n\n@observer\nexport class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { shouldIgnoreRoot: boolean }> {\n  state = {\n    shouldIgnoreRoot: false,\n  };\n  private main = new SettingsMain(this.props.engineEditor);\n\n  @obx.ref private _activeKey?: any;\n\n  constructor(props: ISettingsPrimaryPaneProps) {\n    super(props);\n    makeObservable(this);\n  }\n\n  componentDidMount() {\n    this.setShouldIgnoreRoot();\n\n    const editor = this.props.engineEditor;\n\n    editor.eventBus.on('designer.selection.change', () => {\n      if (!engineConfig.get('stayOnTheSameSettingTab', false)) {\n        this._activeKey = null;\n      }\n    });\n  }\n\n  async setShouldIgnoreRoot() {\n    const designMode = await globalContext.get('editor').get('designMode');\n    this.setState({\n      shouldIgnoreRoot: designMode === 'live',\n    });\n  }\n\n  componentWillUnmount() {\n    this.main.purge();\n  }\n\n  renderBreadcrumb() {\n    const { settings, editor } = this.main;\n    // const shouldIgnoreRoot = config.props?.ignoreRoot;\n    const { shouldIgnoreRoot } = this.state;\n    if (!settings) {\n      return null;\n    }\n    if (settings.isMultiple) {\n      return (\n        <div className=\"lc-settings-navigator\">\n          {createIcon(settings.componentMeta?.icon, {\n            className: 'lc-settings-navigator-icon',\n          })}\n          <div style={{ marginLeft: '5px' }}>\n            <Title title={settings.componentMeta!.title} />\n            <span> x {settings.nodes.length}</span>\n          </div>\n        </div>\n      );\n    }\n\n    const designer = editor.get('designer');\n    const current = designer?.currentSelection?.getNodes()?.[0];\n    let node: INode | null = settings.first;\n    const focusNode = node.document?.focusNode;\n\n    const items = [];\n    let l = 3;\n    while (l-- > 0 && node) {\n      const _node = node;\n      // dirty code: should remove\n      if (shouldIgnoreRoot && node.isRoot()) {\n        break;\n      }\n      if (focusNode && node.contains(focusNode)) {\n        l = 0;\n      }\n      const props =\n        l === 2\n          ? {}\n          : {\n            onMouseOver: hoverNode.bind(null, _node, true),\n            onMouseOut: hoverNode.bind(null, _node, false),\n            onClick: () => {\n              if (!_node) {\n                return;\n              }\n              selectNode.call(null, _node);\n              const getName = (node: any) => {\n                const npm = node?.componentMeta?.npm;\n                return [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||\n                  node?.componentMeta?.componentName ||\n                  '';\n              };\n              const selected = getName(current);\n              const target = getName(_node);\n              editor?.eventBus.emit('skeleton.settingsPane.Breadcrumb', {\n                selected,\n                target,\n              });\n            },\n          };\n      items.unshift(\n        <Breadcrumb.Item {...props} key={node.id}>\n          <Title title={node.title} />\n        </Breadcrumb.Item>,\n      );\n      node = node.parent;\n    }\n\n    return (\n      <div className=\"lc-settings-navigator\">\n        {createIcon(this.main.componentMeta?.icon, {\n          className: 'lc-settings-navigator-icon',\n          class: 'lc-settings-navigator-icon',\n        })}\n        <Breadcrumb className=\"lc-settings-node-breadcrumb\">{items}</Breadcrumb>\n      </div>\n    );\n  }\n\n  render() {\n    const { settings } = this.main;\n    const editor = this.props.engineEditor;\n    if (!settings) {\n      // 未选中节点，提示选中 或者 显示根节点设置\n      return (\n        <div className=\"lc-settings-main\">\n          <div className=\"lc-settings-notice\">\n            <p>{intl('Please select a node in canvas')}</p>\n          </div>\n        </div>\n      );\n    }\n\n    // 当节点被锁定，且未开启锁定后容器可设置属性\n    if (settings.isLocked && !engineConfig.get('enableLockedNodeSetting', false)) {\n      return (\n        <div className=\"lc-settings-main\">\n          <div className=\"lc-settings-notice\">\n            <p>{intl('Current node is locked')}</p>\n          </div>\n        </div>\n      );\n    }\n    if (Array.isArray(settings.items) && settings.items.length === 0) {\n      return (\n        <div className=\"lc-settings-main\">\n          <div className=\"lc-settings-notice\">\n            <p>{intl('No config found for this type of component')}</p>\n          </div>\n        </div>\n      );\n    }\n\n    if (!settings.isSameComponent) {\n      // TODO: future support 获取设置项交集编辑\n      return (\n        <div className=\"lc-settings-main\">\n          <div className=\"lc-settings-notice\">\n            <p>{intl('Please select same kind of components')}</p>\n          </div>\n        </div>\n      );\n    }\n\n    const { items } = settings;\n    if (items.length > 5 || items.some((item) => !isSettingField(item) || !item.isGroup)) {\n      return (\n        <div className=\"lc-settings-main\">\n          {this.renderBreadcrumb()}\n          <div className=\"lc-settings-body\">\n            <SkeletonContext.Consumer>\n              {(skeleton) => {\n                if (skeleton) {\n                  return (\n                    <StageBox skeleton={skeleton} target={settings} key={settings.id}>\n                      <SettingsPane target={settings} usePopup={false} />\n                    </StageBox>\n                  );\n                }\n                return null;\n              }}\n            </SkeletonContext.Consumer>\n          </div>\n        </div>\n      );\n    }\n\n    let matched = false;\n    const tabs = (items as SettingField[]).map((field) => {\n      if (this._activeKey === field.name) {\n        matched = true;\n      }\n      return (\n        <Tab.Item\n          className=\"lc-settings-tab-item\"\n          title={<Title title={field.title} />}\n          key={field.name}\n          onClick={\n            () => {\n              editor?.eventBus.emit('skeleton.settingsPane.change', {\n                name: field.name,\n                title: field.title,\n              });\n            }\n          }\n        >\n          <SkeletonContext.Consumer>\n            {(skeleton) => {\n              if (skeleton) {\n                return (\n                  <StageBox skeleton={skeleton} target={field} key={field.id}>\n                    <SettingsPane target={field} key={field.id} usePopup={false} />\n                  </StageBox>\n                );\n              }\n              return null;\n            }}\n          </SkeletonContext.Consumer>\n        </Tab.Item>\n      );\n    });\n    const activeKey = matched ? this._activeKey : (items[0] as SettingField).name;\n\n    const className = classNames('lc-settings-main', {\n      'lc-settings-hide-tabs':\n        items.length === 1 && engineConfig.get('hideSettingsTabsWhenOnlyOneItem', false),\n    });\n    return (\n      <div className={className}>\n        { this.renderBreadcrumb() }\n        <Tab\n          activeKey={activeKey}\n          onChange={(tabKey) => {\n            this._activeKey = tabKey;\n          }}\n          navClassName=\"lc-settings-tabs\"\n          animation={false}\n          excessMode=\"dropdown\"\n          contentClassName=\"lc-settings-tabs-content\"\n        >\n          {tabs}\n        </Tab>\n      </div>\n    );\n  }\n}\n\nfunction hoverNode(node: Node, flag: boolean) {\n  node.hover(flag);\n}\nfunction selectNode(node: Node) {\n  node?.select();\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/settings/style.less",
    "content": ".lc-settings-main {\n  position: relative;\n  height: 100%;\n  overflow: hidden;\n\n  ul {\n    margin: 0;\n  }\n\n  .lc-settings-content {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    width: 100%;\n    overflow-y: auto;\n  }\n\n  .lc-setting-stage-back + .lc-settings-content {\n    top: 38px;\n  }\n\n  .lc-setting-stage-back {\n    height: 32px;\n    width: 100%;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    font-weight: 500;\n    background: var(--color-block-background-shallow, rgba(31,56,88,.06));\n    color: var(--color-title);\n    padding: 0 16px;\n    user-select: none;\n    position: relative;\n    margin-bottom: 4px;\n    position: absolute;\n  }\n\n  .lc-settings-notice {\n    text-align: center;\n    font-size: 12px;\n    font-family: PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica, Arial, sans-serif;\n    color: var(--color-text ,rgba(0,0,0,.6));\n    padding: 50px 15px 0;\n  }\n\n  .lc-settings-navigator {\n    height: 30px;\n    display: flex;\n    align-items: center;\n    padding: 0 16px;\n    border-bottom: 1px solid var(--color-line-normal);\n    .lc-settings-navigator-icon {\n      width: 16px;\n      height: 16px;\n      * {\n        fill: var(--color-icon-normal, rgba(31, 56, 88, 0.4));\n      }\n    }\n    .lc-settings-node-breadcrumb {\n      margin-left: 5px;\n      .next-breadcrumb {\n        display: inline-flex;\n        align-items: stretch;\n        height: 24px;\n      }\n      .next-breadcrumb-item {\n        display: inline-flex;\n        align-items: center;\n        cursor: default;\n        &:not(:last-child):hover {\n          cursor: pointer;\n        }\n        .next-breadcrumb-text {\n          font-size: 12px;\n        }\n      }\n    }\n  }\n\n  .lc-settings-body {\n    position: absolute;\n    top: 30px;\n    right: 0;\n    left: 0;\n    bottom: 0;\n    overflow-y: auto;\n  }\n\n  // ====== reset fusion-tabs =====\n  .lc-settings-tabs {\n    position: relative;\n    overflow: visible;\n    > .next-tabs-nav-extra {\n      position: absolute !important;\n      top: 40px !important;\n      left: 0 !important;\n      height: 30px;\n      right: 0;\n      transform: none !important;\n\n    }\n    .next-tabs-nav-container {\n      .next-tabs-nav {\n        display: flex;\n        .next-tabs-tab.lc-settings-tab-item {\n          flex: 1;\n          min-width: 0;\n          outline: none;\n          .next-tabs-tab-inner {\n            text-align: center;\n            padding: 12px 0;\n          }\n        }\n      }\n    }\n  }\n\n  .lc-settings-tabs-content {\n    position: absolute;\n    top: 70px;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    .next-tabs-tabpane {\n      position: absolute;\n      top: 0;\n      right: 0;\n      left: 0;\n      bottom: 0;\n      overflow-y: auto;\n      outline: none !important;\n      box-shadow: none !important;\n    }\n  }\n  .lc-outline-pane {\n    position: absolute;\n    z-index: 100;\n    top: 0;\n    bottom: 0;\n    display: none;\n  }\n}\n\n.lc-workbench .lc-workbench-body .lc-right-area .lc-settings-hide-tabs {\n  .lc-settings-tabs {\n    display: none;\n  }\n\n  .lc-settings-tabs-content {\n    top: 30px;\n  }\n}\n\n.lc-settings-pane {\n  padding-bottom: 50px;\n  .next-btn {\n    line-height: 1 !important;\n  }\n}\n\nhtml.lc-cursor-dragging:not(.lowcode-has-fixed-tree) {\n  .lc-settings-main .lc-outline-pane {\n    display: block;\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/settings/utils.ts",
    "content": "function getHotterFromSetter(setter) {\n  return setter && (setter.Hotter || (setter.type && setter.type.Hotter)) || []; // eslint-disable-line\n}\n\nfunction getTransducerFromSetter(setter) {\n  return setter && (\n    setter.transducer || setter.Transducer\n      || (setter.type && (setter.type.transducer || setter.type.Transducer))\n    ) || null; // eslint-disable-line\n}\n\nfunction combineTransducer(transducer, arr, context) {\n  if (!transducer && Array.isArray(arr)) {\n    const [toHot, toNative] = arr;\n    transducer = { toHot, toNative };\n  }\n\n  return {\n    toHot: (transducer && transducer.toHot || (x => x)).bind(context), // eslint-disable-line\n    toNative: (transducer && transducer.toNative || (x => x)).bind(context), // eslint-disable-line\n  };\n}\n\nexport class Transducer {\n  constructor(context, config) {\n    this.setterTransducer = combineTransducer(\n      getTransducerFromSetter(config.setter),\n      getHotterFromSetter(config.setter),\n      context,\n    );\n    this.context = context;\n  }\n\n  toHot(data) {\n    return this.setterTransducer.toHot(data);\n  }\n\n  toNative(data) {\n    return this.setterTransducer.toNative(data);\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/stage-box/index.less",
    "content": "@import '../../less-variables.less';\n\n.skeleton-stagebox {\n  overflow-x: hidden;\n  overflow-y: auto;\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  .skeleton-stagebox-stage {\n    height: auto;\n    overflow: hidden;\n\n    transition: transform 0.2s;\n\n    &.skeleton-stagebox-refer {\n      position: absolute;\n      top: 0;\n      left: 0;\n      right: 0;\n      height: auto;\n    }\n\n    &.skeleton-stagebox-stageout-left, &.skeleton-stagebox-stagein-right {\n      transform: translateX(-100%);\n    }\n\n    &.skeleton-stagebox-stageout-right, &.skeleton-stagebox-stagein-left {\n      transform: translateX(100%);\n    }\n\n    .skeleton-stagebox-stagebacker {\n      cursor: pointer;\n      height: 30px;\n      display: flex;\n      align-items: center;\n      background: var(--color-block-background-light, @normal-alpha-9);\n      justify-content: center;\n      position: relative;\n\n      .skeleton-stagebox-stage-arrow {\n        position: absolute;\n        left: 8px;\n        top: 50%;\n        transform: translateY(-50%) rotate(90deg);\n        opacity: 0.6;\n        width: 12px;\n      }\n      .skeleton-stagebox-stage-title {\n        font-weight: bold;\n      }\n      &:hover {\n        background: var(--color-block-background-dark, @normal-alpha-7);\n        .skeleton-stagebox-stage-arrow {\n          opacity: 1;\n        }\n      }\n      .skeleton-stagebox-stage-exit {\n        position: absolute;\n        right: 8px;\n        top: 50%;\n        transform: translateY(-50%);\n        opacity: 0.6;\n      }\n    }\n\n    .skeleton-stagebox-stage-content {\n      overflow: hidden;\n      box-sizing: border-box;\n    }\n\n    &.skeleton-stagebox-has-backer {\n      .skeleton-stagebox-stage-content {\n        padding-top: 30px;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/stage-box/index.ts",
    "content": "import StageBox from './stage-box';\nimport './index.less';\n\nexport { StageBox };\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/stage-box/stage-box.tsx",
    "content": "import React, { Component } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport StageChain from './stage-chain';\nimport Stage from './stage';\nimport { ISkeleton } from '../../skeleton';\nimport PopupService, { PopupPipe } from '../popup';\nimport { Stage as StageWidget } from '../../widget/stage';\n\nexport const StageBoxDefaultProps = {};\n\nexport type StageBoxProps = typeof StageBoxDefaultProps & {\n  stageChain?: StageChain;\n  className?: string;\n  children: React.ReactNode;\n  skeleton: ISkeleton;\n};\n\ntype WillDetachMember = () => void;\n\n@observer\nexport default class StageBox extends Component<StageBoxProps> {\n  static defaultProps = StageBoxDefaultProps;\n\n  static displayName = 'StageBox';\n\n  private stageChain: StageChain;\n\n  private willDetach: WillDetachMember[] = [];\n\n  private shell: HTMLElement | null;\n\n  private popupPipe = new PopupPipe();\n\n  private pipe = this.popupPipe.create();\n\n  constructor(props: StageBoxProps) {\n    super(props);\n    const { stageChain, children, skeleton } = this.props;\n    if (stageChain) {\n      this.stageChain = stageChain;\n    } else {\n      const stateName = skeleton.createStage({\n        content: children,\n        isRoot: true,\n      });\n      this.stageChain = new StageChain(skeleton.getStage(stateName as string) as StageWidget);\n    }\n    this.willDetach.push(this.stageChain.onStageChange(() => this.forceUpdate()));\n  }\n\n  componentDidMount() {\n    const { shell } = this;\n\n    /**\n     * 向上层递归寻找 target\n     * @param node 节点\n     * @returns 节点的 dataset.stageTarget 信息\n     */\n    const getTarget = (node: HTMLElement | null): null | string => {\n      if (!node || !shell?.contains(node) || (node.nodeName === 'A' && node.getAttribute('href'))) {\n        return null;\n      }\n\n      const target = node.dataset ? node.dataset.stageTarget : null;\n      if (target) {\n        return target;\n      }\n      return getTarget(node.parentNode as HTMLElement);\n    };\n\n    const click = (e: MouseEvent) => {\n      const target = getTarget(e.target as HTMLElement);\n      if (!target) {\n        return;\n      }\n\n      if (target === 'stageback') {\n        this.stageChain.stageBack();\n      } else if (target === 'stageexit') {\n        this.stageChain.stageBackToRoot();\n      } else {\n        const { skeleton } = this.props;\n        this.stageChain.stagePush(skeleton.getStage(target));\n      }\n    };\n\n    shell?.addEventListener('click', click, false);\n    this.willDetach.push(() => shell?.removeEventListener('click', click, false));\n  }\n\n  componentWillUnmount() {\n    if (this.willDetach) {\n      this.willDetach.forEach((off: () => void) => off());\n    }\n  }\n\n  render() {\n    const className = classNames('skeleton-stagebox', this.props.className);\n    const stage = this.stageChain.getCurrentStage();\n    const refer = stage?.getRefer();\n\n    let contentCurrent = null;\n    let contentRefer = null;\n\n    if (refer) {\n      contentCurrent = <Stage key={stage.getId()} stage={stage} direction={refer.direction} current />;\n      contentRefer = <Stage key={refer?.stage?.getId()} stage={refer?.stage} direction={refer.direction} />;\n    } else {\n      contentCurrent = <Stage key={stage.getId()} stage={stage} current />;\n    }\n\n    return (\n      <div\n        ref={(ref) => {\n          this.shell = ref;\n        }}\n        className={className}\n      >\n\n        <PopupService popupPipe={this.popupPipe}>\n\n          {contentRefer}\n          {contentCurrent}\n\n        </PopupService>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/stage-box/stage-chain.ts",
    "content": "import { Stage as StageWidget } from '../../widget/stage';\nimport { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';\n\nexport default class StageChain {\n  private emitter: IEventBus;\n\n  private stage: StageWidget;\n\n  constructor(stage: StageWidget) {\n    this.emitter = createModuleEventBus('StageChain');\n    this.stage = stage;\n  }\n\n  stagePush(stage: StageWidget | null) {\n    if (!stage) return;\n    stage.setPrevious(this.stage);\n    stage.setReferLeft(this.stage);\n    this.stage = stage;\n    this.emitter.emit('stagechange');\n  }\n\n  stageBack() {\n    const stage = this.stage.getPrevious();\n    if (!stage) return;\n    stage.setReferRight(this.stage);\n    this.stage = stage;\n    this.emitter.emit('stagechange');\n  }\n\n  /**\n   * 回到最开始\n   */\n  stageBackToRoot() {\n    let rootStage = this.stage.getPrevious();\n    while (rootStage && !rootStage.isRoot) {\n      rootStage = rootStage.getPrevious();\n    }\n    if (!rootStage) return;\n    rootStage.setReferRight(this.stage);\n    this.stage = rootStage;\n    this.emitter.emit('stagechange');\n  }\n\n  getCurrentStage() {\n    return this.stage;\n  }\n\n  onStageChange(func: () => void) {\n    this.emitter.on('stagechange', func);\n    return () => {\n      this.emitter.removeListener('stagechange', func);\n    };\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/stage-box/stage.tsx",
    "content": "// @todo 改成 hooks\nimport React, { Component } from 'react';\nimport classNames from 'classnames';\nimport { IconArrow } from '../../icons/arrow';\nimport { IconExit } from '../../icons/exit';\nimport { Stage as StageWidget } from '../../widget/stage';\nimport { isTitleConfig } from '@alilc/lowcode-utils';\n\nexport const StageDefaultProps = {\n  current: false,\n};\n\nexport type StageProps = typeof StageDefaultProps & {\n  stage?: StageWidget;\n  current: boolean;\n  direction?: string;\n};\n\nexport default class Stage extends Component<StageProps> {\n  static defaultProps = StageDefaultProps;\n\n  private timer: number;\n\n  private additionClassName: string | null;\n\n  private shell: any;\n\n  componentDidMount() {\n    this.doSkate();\n  }\n\n  componentDidUpdate() {\n    this.doSkate();\n  }\n\n  componentWillUnmount() {\n    window.clearTimeout(this.timer);\n  }\n\n  doSkate() {\n    window.clearTimeout(this.timer);\n    if (this.additionClassName) {\n      this.timer = window.setTimeout(() => {\n        const elem = this.shell;\n        if (elem) {\n          if (this.props.current) {\n            elem.classList.remove(this.additionClassName);\n          } else {\n            elem.classList.add(this.additionClassName);\n          }\n          this.additionClassName = null;\n        }\n      }, 15);\n    }\n  }\n\n  render() {\n    const { stage, current, direction } = this.props;\n    const content = stage?.getContent();\n    const { title } = stage!;\n    const newTitle = isTitleConfig(title) ? title.label : title;\n\n    if (current) {\n      if (direction) {\n        this.additionClassName = `skeleton-stagebox-stagein-${direction}`;\n      }\n    } else if (direction) {\n      this.additionClassName = `skeleton-stagebox-stageout-${direction}`;\n    }\n\n    const className = classNames(\n      'skeleton-stagebox-stage',\n      {\n        'skeleton-stagebox-refer': !current,\n      },\n      this.additionClassName,\n    );\n\n    const stageBacker = stage?.hasBack() ? (\n      <div className=\"skeleton-stagebox-stagebacker\">\n        <IconArrow className=\"skeleton-stagebox-stage-arrow\" size=\"medium\" data-stage-target=\"stageback\" />\n        <span className=\"skeleton-stagebox-stage-title\">{newTitle}</span>\n        <IconExit className=\"skeleton-stagebox-stage-exit\" size=\"medium\" data-stage-target=\"stageexit\" />\n      </div>\n    ) : null;\n\n    return (\n      <div\n        ref={(ref) => {\n          this.shell = ref;\n        }}\n        className={className}\n      >\n        {stageBacker}\n        <div className=\"skeleton-stagebox-stage-content\">{content}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/widget-views/index.less",
    "content": ".lc-widget-view-container {\n  height: 100%;\n  width: 100%;\n\n  &.hidden {\n    display: none;\n  }\n}\n\n.lc-widget-disabled {\n  pointer-events: none;\n  opacity: 0.4;\n}\n\n.lc-draggable-line-vertical {\n  position: absolute;\n  width: 4px;\n  height: 100%;\n  top: 0;\n  background-color: transparent;\n  cursor: col-resize;\n  right: -2px;\n  z-index: 99;\n}\n\n.lc-engine-slate-draggable-line-right {\n  right: -2px;\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/widget-views/index.tsx",
    "content": "import { Component, ReactElement } from 'react';\nimport classNames from 'classnames';\nimport { Title, observer, HelpTip } from '@alilc/lowcode-editor-core';\nimport { DockProps } from '../../types';\nimport { PanelDock } from '../../widget/panel-dock';\nimport { composeTitle } from '../../widget/utils';\nimport { WidgetContainer } from '../../widget/widget-container';\nimport { Panel } from '../../widget/panel';\nimport { IWidget } from '../../widget/widget';\nimport { SkeletonEvents } from '../../skeleton';\nimport DraggableLine from '../draggable-line';\nimport PanelOperationRow from './panel-operation-row';\n\nimport './index.less';\n\nexport function DockView({ title, icon, description, size, className, onClick }: DockProps) {\n  return (\n    <Title\n      title={composeTitle(title, icon, description)}\n      className={classNames('lc-dock', className, {\n        [`lc-dock-${size}`]: size,\n      })}\n      onClick={onClick}\n    />\n  );\n}\n\n@observer\nexport class PanelDockView extends Component<DockProps & { dock: PanelDock }> {\n  private lastActived = false;\n\n  componentDidMount() {\n    this.checkActived();\n  }\n\n  componentDidUpdate() {\n    this.checkActived();\n  }\n\n  checkActived() {\n    const { dock } = this.props;\n    if (dock.actived !== this.lastActived) {\n      this.lastActived = dock.actived;\n      if (this.lastActived) {\n        dock.skeleton.postEvent(SkeletonEvents.PANEL_DOCK_ACTIVE, dock.name, dock);\n      } else {\n        dock.skeleton.postEvent(SkeletonEvents.PANEL_DOCK_UNACTIVE, dock.name, dock);\n      }\n    }\n  }\n\n  render() {\n    const { dock, className, onClick, ...props } = this.props;\n    return DockView({\n      ...props,\n      className: classNames(className, {\n        actived: dock.actived,\n      }),\n      onClick: () => {\n        onClick && onClick();\n        dock.togglePanel();\n      },\n    });\n  }\n}\n\nexport class DialogDockView extends Component {}\n\nexport class DraggableLineView extends Component<{ panel: Panel }> {\n  private shell: any;\n  private defaultWidth: number;\n\n  private getDefaultWidth() {\n    const configWidth = this.props.panel?.config.props?.width;\n    if (configWidth) {\n      return configWidth;\n    }\n    if (this.defaultWidth) {\n      return this.defaultWidth;\n    }\n    const containerRef = this.shell?.getParent();\n    if (containerRef) {\n      this.defaultWidth = containerRef.offsetWidth;\n      return this.defaultWidth;\n    }\n    return 300;\n  }\n\n  onDrag(value: number) {\n    const defaultWidth = this.getDefaultWidth();\n    const width = defaultWidth + value;\n\n    const containerRef = this.shell?.getParent();\n    if (containerRef) {\n      containerRef.style.width = `${width}px`;\n    }\n\n    // 抛出事件，对于有些需要 panel 插件随着 度变化进行再次渲染的，由panel插件内部监听事件实现\n    const editor = this.props.panel.skeleton.editor;\n    editor?.eventBus.emit('dockpane.drag', width);\n  }\n\n  onDragChange(type: 'start' | 'end') {\n    const editor = this.props.panel.skeleton.editor;\n    editor?.eventBus.emit('dockpane.dragchange', type);\n    // builtinSimulator 屏蔽掉 鼠标事件\n    editor?.eventBus.emit('designer.builtinSimulator.disabledEvents', type === 'start');\n  }\n\n  render() {\n    // left fixed 下不允许改变宽度\n    // 默认 关闭，通过配置开启\n    const enableDrag = this.props.panel.config.props?.enableDrag;\n    const isRightArea = this.props.panel.config?.area === 'rightArea';\n    if (isRightArea || !enableDrag || this.props.panel?.parent?.name === 'leftFixedArea') {\n      return null;\n    }\n    return (\n      <DraggableLine\n        ref={(ref) => {\n          this.shell = ref;\n        }}\n        position=\"right\"\n        className=\"lc-engine-slate-draggable-line-right\"\n        onDrag={(e) => this.onDrag(e)}\n        onDragStart={() => this.onDragChange('start')}\n        onDragEnd={() => this.onDragChange('end')}\n        maxIncrement={500}\n        maxDecrement={0}\n        // TODO: 优化\n        // maxIncrement={dock.getMaxWidth() - this.cachedSize.width}\n        // maxDecrement={this.cachedSize.width - dock.getWidth()}\n      />\n    );\n  }\n}\n\n@observer\nexport class TitledPanelView extends Component<{ panel: Panel; area?: string }> {\n  private lastVisible = false;\n\n  componentDidMount() {\n    this.checkVisible();\n  }\n\n  componentDidUpdate() {\n    this.checkVisible();\n  }\n\n  checkVisible() {\n    const { panel } = this.props;\n    const currentVisible = panel.inited && panel.visible;\n    if (currentVisible !== this.lastVisible) {\n      this.lastVisible = currentVisible;\n      if (this.lastVisible) {\n        panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel);\n      } else {\n        panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel);\n      }\n    }\n  }\n\n  render() {\n    const { panel, area } = this.props;\n    if (!panel.inited) {\n      return null;\n    }\n    const editor = panel.skeleton.editor;\n    const panelName = area ? `${area}-${panel.name}` : panel.name;\n    editor?.eventBus.emit('skeleton.panel.toggle', {\n      name: panelName || '',\n      status: panel.visible ? 'show' : 'hide',\n    });\n    return (\n      <div\n        className={classNames('lc-titled-panel', {\n          hidden: !panel.visible,\n        })}\n        id={panelName}\n        data-keep-visible-while-dragging={panel.config.props?.keepVisibleWhileDragging}\n      >\n        <PanelOperationRow panel={panel} />\n        <PanelTitle panel={panel} />\n        <div className=\"lc-panel-body\">{panel.body}</div>\n        <DraggableLineView panel={panel} />\n      </div>\n    );\n  }\n}\n\n@observer\nexport class PanelView extends Component<{\n  panel: Panel;\n  area?: string;\n  hideOperationRow?: boolean;\n  hideDragLine?: boolean;\n}> {\n  private lastVisible = false;\n\n  componentDidMount() {\n    this.checkVisible();\n  }\n\n  componentDidUpdate() {\n    this.checkVisible();\n  }\n\n  checkVisible() {\n    const { panel } = this.props;\n    const currentVisible = panel.inited && panel.visible;\n    if (currentVisible !== this.lastVisible) {\n      this.lastVisible = currentVisible;\n      if (this.lastVisible) {\n        panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel);\n      } else {\n        panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel);\n      }\n    }\n  }\n\n  render() {\n    const { panel, area, hideOperationRow, hideDragLine } = this.props;\n    if (!panel.inited) {\n      return null;\n    }\n    const editor = panel.skeleton.editor;\n    const panelName = area ? `${area}-${panel.name}` : panel.name;\n    editor?.eventBus.emit('skeleton.panel.toggle', {\n      name: panelName || '',\n      status: panel.visible ? 'show' : 'hide',\n    });\n    return (\n      <div\n        className={classNames('lc-panel', {\n          hidden: !panel.visible,\n        })}\n        id={panelName}\n        data-keep-visible-while-dragging={panel.config.props?.keepVisibleWhileDragging}\n      >\n        {!hideOperationRow && <PanelOperationRow panel={panel} />}\n        {panel.body}\n        {!hideDragLine && <DraggableLineView panel={panel} />}\n      </div>\n    );\n  }\n}\n\n@observer\nexport class TabsPanelView extends Component<{\n  container: WidgetContainer<Panel>;\n  // shouldHideSingleTab: 一个布尔值，用于控制当 Tabs 组件只有一个标签时是否隐藏该标签。\n  shouldHideSingleTab?: boolean;\n}> {\n  render() {\n    const { container } = this.props;\n    const titles: ReactElement[] = [];\n    const contents: ReactElement[] = [];\n    // 如果只有一个标签且 shouldHideSingleTab 为 true，则不显示 Tabs\n    if (this.props.shouldHideSingleTab && container.items.length === 1) {\n      contents.push(<PanelView key={container.items[0].id} panel={container.items[0]} hideOperationRow hideDragLine />);\n    } else {\n      container.items.forEach((item: any) => {\n        titles.push(<PanelTitle key={item.id} panel={item} className=\"lc-tab-title\" />);\n        contents.push(<PanelView key={item.id} panel={item} hideOperationRow hideDragLine />);\n      });\n    }\n\n    if (!titles.length) {\n      return contents;\n    }\n\n    return (\n      <div className=\"lc-tabs\">\n        <div\n          className=\"lc-tabs-title\"\n          onClick={(e) => {\n            const shell = e.currentTarget;\n            const t = e.target as Element;\n            let elt = shell.firstElementChild;\n            while (elt) {\n              if (elt.contains(t)) {\n                break;\n              }\n              elt = elt.nextElementSibling;\n            }\n            if (elt) {\n              container.active((elt as any).dataset.name);\n            }\n          }}\n        >\n          {titles}\n        </div>\n        <div className=\"lc-tabs-content\">{contents}</div>\n      </div>\n    );\n  }\n}\n\n@observer\nclass PanelTitle extends Component<{ panel: Panel; className?: string }> {\n  render() {\n    const { panel, className } = this.props;\n    return (\n      <div\n        className={classNames('lc-panel-title', className, {\n          actived: panel.actived,\n        })}\n        data-name={panel.name}\n      >\n        <Title title={panel.title || panel.name} />\n        {panel.help ? <HelpTip help={panel.help} /> : null}\n      </div>\n    );\n  }\n}\n\n@observer\nexport class WidgetView extends Component<{ widget: IWidget }> {\n  private lastVisible = false;\n  private lastDisabled: boolean | undefined = false;\n\n  componentDidMount() {\n    this.checkVisible();\n    this.checkDisabled();\n  }\n\n  componentDidUpdate() {\n    this.checkVisible();\n    this.checkDisabled();\n  }\n\n  checkVisible() {\n    const { widget } = this.props;\n    const currentVisible = widget.visible;\n    if (currentVisible !== this.lastVisible) {\n      this.lastVisible = currentVisible;\n      if (this.lastVisible) {\n        widget.skeleton.postEvent(SkeletonEvents.WIDGET_SHOW, widget.name, widget);\n      } else {\n        widget.skeleton.postEvent(SkeletonEvents.WIDGET_SHOW, widget.name, widget);\n      }\n    }\n  }\n\n  checkDisabled() {\n    const { widget } = this.props;\n    const currentDisabled = widget.disabled;\n    if (currentDisabled !== this.lastDisabled) {\n      this.lastDisabled = currentDisabled;\n      if (this.lastDisabled) {\n        widget.skeleton.postEvent(SkeletonEvents.WIDGET_DISABLE, widget.name, widget);\n      } else {\n        widget.skeleton.postEvent(SkeletonEvents.WIDGET_ENABLE, widget.name, widget);\n      }\n    }\n  }\n\n  render() {\n    const { widget } = this.props;\n    if (!widget.visible) {\n      return null;\n    }\n    if (widget.disabled) {\n      return <div className=\"lc-widget-disabled\">{widget.body}</div>;\n    }\n    return widget.body;\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport { Button, Icon } from '@alifd/next';\nimport { action, makeObservable } from '@alilc/lowcode-editor-core';\nimport { IconFix } from '../../icons/fix';\nimport { IconFloat } from '../../icons/float';\nimport { Panel } from '../../widget/panel';\n\nexport default class PanelOperationRow extends Component<{ panel: Panel }> {\n  constructor(props) {\n    super(props);\n    makeObservable(this);\n  }\n  // fix or float\n  @action\n  setDisplay() {\n    const { panel } = this.props;\n    const current = panel;\n    if (!current) {\n      return;\n    }\n\n    panel.skeleton.toggleFloatStatus(panel);\n  }\n\n  render() {\n    const { panel } = this.props;\n    const isRightArea = this.props.panel.config?.area === 'rightArea';\n    if (isRightArea) {\n      return null;\n    }\n    // \bcan be set fixed by default\n    let canSetFixed = true;\n    if (panel?.config.props?.canSetFixed === false) {\n      canSetFixed = false;\n    }\n\n    const hideTitleBar = panel?.config.props?.hideTitleBar;\n\n    const areaName = panel?.parent?.name;\n    const area = panel.skeleton[areaName];\n\n    return (\n      <Fragment>\n        {!hideTitleBar && (\n          <Fragment>\n            {canSetFixed && (\n              // eslint-disable-next-line react/jsx-no-bind\n              <Button text className=\"lc-pane-icon-fix\" onClick={this.setDisplay.bind(this)}>\n                {areaName === 'leftFloatArea' ? <IconFix /> : <IconFloat />}\n              </Button>\n            )}\n            <Button\n              text\n              className=\"lc-pane-icon-close\"\n              onClick={() => {\n                area && area.setVisible(false);\n              }}\n            >\n              <Icon type=\"close\" />\n            </Button>\n          </Fragment>\n        )}\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/context.ts",
    "content": "import { createContext } from 'react';\nimport { ISkeleton } from './skeleton';\n\nexport const SkeletonContext = createContext<ISkeleton>({} as any);\n"
  },
  {
    "path": "packages/editor-skeleton/src/icons/arrow.tsx",
    "content": "\nimport { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconArrow(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M512.002047 771.904425c-10.152221 0.518816-20.442588-2.800789-28.202319-10.598382L77.902254 315.937602c-14.548344-14.618952-14.548344-38.318724 0-52.933583 14.544251-14.614859 38.118156-14.614859 52.662407 0l381.437385 418.531212L893.432269 263.004019c14.544251-14.614859 38.125319-14.614859 52.662407 0 14.552437 14.614859 14.552437 38.314631 0 52.933583L540.205389 761.307066C532.451798 769.103636 522.158361 772.424264 512.002047 771.904425z\" />\n    </SVGIcon>\n  );\n}\nIconArrow.displayName = 'Arrow';"
  },
  {
    "path": "packages/editor-skeleton/src/icons/clear.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconClear(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M761.6 701.44a21.333333 21.333333 0 0 1 0 30.293333l-29.866667 29.866667a21.333333 21.333333 0 0 1-30.293333 0L512 572.16l-189.44 189.44a21.333333 21.333333 0 0 1-30.293333 0l-29.866667-29.866667a21.333333 21.333333 0 0 1 0-30.293333L451.84 512 262.4 322.56a21.333333 21.333333 0 0 1 0-30.293333l29.866667-29.866667a21.333333 21.333333 0 0 1 30.293333 0L512 451.84l189.44-189.44a21.333333 21.333333 0 0 1 30.293333 0l29.866667 29.866667a21.333333 21.333333 0 0 1 0 30.293333L572.16 512z\" />\n    </SVGIcon>\n  );\n}\n\nIconClear.displayName = 'Clear';\n"
  },
  {
    "path": "packages/editor-skeleton/src/icons/convert.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconConvert(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M620.8 256c-12.8-12.8-32-12.8-44.8 0s-12.8 32 0 44.8l83.2 83.2H288c-19.2 0-32 12.8-32 32s12.8 32 32 32h448c6.4 0 32 0 32-32 0-19.2-6.4-25.6-6.4-25.6L620.8 256zM736 576H288c-6.4 0-32 0-32 32 0 19.2 6.4 25.6 6.4 25.6L403.2 768c12.8 12.8 32 12.8 44.8 0s12.8-32 0-44.8L364.8 640H736c19.2 0 32-12.8 32-32s-12.8-32-32-32zM512 64C262.4 64 64 262.4 64 512s198.4 448 448 448 448-198.4 448-448S761.6 64 512 64z m0 832c-211.2 0-384-172.8-384-384s172.8-384 384-384 384 172.8 384 384-172.8 384-384 384z\" />\n    </SVGIcon>\n  );\n}\n\nIconConvert.displayName = 'Convert';\n"
  },
  {
    "path": "packages/editor-skeleton/src/icons/exit.tsx",
    "content": "\nimport { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconExit(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M723.872 478.4l-81.12-81.152L688 352l135.776 135.776L846.4 510.4 688 668.8l-45.248-45.28 81.12-81.12H384v-64h339.872zM576 896H256.192A64.16 64.16 0 0 1 192 831.84V192.16c0-35.424 28.704-64.16 64.192-64.16H576v64H288.224A31.968 31.968 0 0 0 256 223.744v576.512C256 817.44 270.4 832 288.224 832H576v64z\" />\n    </SVGIcon>\n  );\n}\nIconExit.displayName = 'Exit';"
  },
  {
    "path": "packages/editor-skeleton/src/icons/fix.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconFix(props: IconProps) {\n  const rect = {\n    width: 13,\n    height: 13,\n  };\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props} {...rect}>\n      <path d=\"M750.848 28.928l245.248 242.944a66.048 66.048 0 1 1-93.184 93.184l-25.6-19.456-249.6 353.792 78.336 78.336a66.048 66.048 0 0 1-93.184 92.672l-460.8-464.64a66.048 66.048 0 0 1 93.184-93.184l76.8 78.336 354.048-249.856-18.176-18.944a66.048 66.048 0 1 1 93.184-93.184zM380.672 732.416l-91.904-90.88c-74.24 89.6-191.488 219.904-212.736 247.04a419.84 419.84 0 0 0-70.656 128 419.84 419.84 0 0 0 128-70.144c27.136-21.248 157.44-138.496 246.528-214.016z\" />\n    </SVGIcon>\n  );\n}\n\nIconFix.displayName = 'Fix';\n"
  },
  {
    "path": "packages/editor-skeleton/src/icons/float.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconFloat(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M160.256 816.64C116.224 872.448 102.4 921.6 102.4 921.6s49.152-13.824 104.96-57.856c22.016-17.408 128-112.64 200.704-174.08l-73.728-73.728c-61.44 72.704-157.184 178.688-174.08 200.704zM648.704 209.408L442.368 355.328l226.304 226.304 145.92-206.336 15.872 15.872c20.992 20.992 54.784 20.992 75.776 0s20.992-54.784 0-75.776l-197.12-197.12c-20.992-20.992-54.784-20.992-75.776 0-20.992 20.992-20.992 54.784 0 75.776l15.36 15.36zM247.808 334.848c-9.728 2.048-18.944 6.656-26.624 14.336-20.992 20.992-20.992 54.784 0 75.776l377.856 377.856c20.992 20.992 54.784 20.992 75.776 0 7.68-7.68 12.288-16.896 14.336-26.624L247.808 334.848z\" />\n      <path d=\"M840.704 879.104c-9.728 0-19.456-3.584-27.136-11.264L155.648 210.432c-14.848-14.848-14.848-39.424 0-54.272 14.848-14.848 39.424-14.848 54.272 0L867.84 814.08c14.848 14.848 14.848 39.424 0 54.272-7.168 7.168-16.896 10.752-27.136 10.752z\" />\n    </SVGIcon>\n  );\n}\n\nIconFloat.displayName = 'Float';\n"
  },
  {
    "path": "packages/editor-skeleton/src/icons/slot.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconSlot(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M682.325333 135.509333V204.8H819.2v613.376h-614.741333V204.8h136.874666v-69.290667h-206.165333v752.298667h754.346667V135.509333z\" c=\"Q29weXJpZ2h0IChjKSAyMDIwLXByZXNlbnQgQWxpYmFiYSBJbmMu\" />\n      <path d=\"M512 512m-170.325333 0a170.325333 170.325333 0 1 0 340.650666 0 170.325333 170.325333 0 1 0-340.650666 0Z\" />\n    </SVGIcon>\n  );\n}\n\nIconSlot.displayName = 'IconSlot';\n"
  },
  {
    "path": "packages/editor-skeleton/src/icons/variable.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconVariable(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M596.32 263.392c18.048 6.56 27.328 26.496 20.8 44.512l-151.04 414.912a34.72 34.72 0 1 1-65.28-23.744l151.04-414.912a34.72 34.72 0 0 1 44.48-20.768zM220.64 192H273.6v55.488H233.024c-26.112 0-38.464 14.4-38.464 44.544v134.304c0 42.496-19.936 71.264-59.104 85.664 39.168 16.448 59.104 44.544 59.104 85.664v134.976c0 28.8 12.352 43.84 38.464 43.84H273.6V832H220.672c-30.24 0-53.6-10.272-70.08-29.44-15.136-17.856-22.72-42.496-22.72-72.64v-128.832c0-19.872-4.096-34.24-12.352-43.2-9.6-10.944-26.784-16.416-51.52-17.792v-56.192c24.736-1.376 41.92-7.52 51.52-17.824 8.256-9.6 12.384-24 12.384-43.168V294.784c0-30.848 7.552-55.488 22.688-73.312C167.04 201.6 190.4 192 220.672 192z m529.792 0h52.896c30.24 0 53.6 9.6 70.08 29.44 15.136 17.856 22.72 42.496 22.72 73.344v128.128c0 19.2 4.096 34.24 13.024 43.84 8.96 9.6 26.112 15.776 50.848 17.152v56.192c-24.736 1.376-41.92 6.848-51.52 17.824-8.256 8.896-12.384 23.296-12.384 43.168v128.8c0 30.176-7.552 54.816-22.688 72.64-16.48 19.2-39.84 29.472-70.08 29.472h-52.896v-55.488h40.544c25.408 0 38.464-15.104 38.464-43.84v-135.04c0-41.088 19.232-69.184 59.104-85.632-39.872-14.4-59.104-43.168-59.104-85.664V292.032c0-30.144-13.056-44.544-38.464-44.544H750.4V192z\" />\n    </SVGIcon>\n  );\n}\n\nIconVariable.displayName = 'Variable';\n"
  },
  {
    "path": "packages/editor-skeleton/src/index.ts",
    "content": "export * from './area';\nexport { Workbench } from './layouts/workbench';\nexport * from './skeleton';\nexport * from './types';\nexport * from './components/settings';\nexport * from './components/field';\nexport * from './components/popup';\nexport * from './context';\nexport * from './register-defaults';\nexport * from './widget';\nexport * from './layouts';\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/bottom-area.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\nimport { Panel } from '../widget/panel';\n\n@observer\nexport default class BottomArea extends Component<{ area: Area<any, Panel> }> {\n  render() {\n    const { area } = this.props;\n    if (area.isEmpty()) {\n      return null;\n    }\n    return (\n      <div className={classNames('lc-bottom-area', {\n        'lc-area-visible': area.visible,\n      })}\n      >\n        <Contents area={area} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area<any, Panel> }> {\n  render() {\n    const { area } = this.props;\n    return (\n      <Fragment>\n        {area.container.items.map((item) => item.content)}\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/index.ts",
    "content": "export { default as LeftArea } from './left-area';\nexport { default as LeftFloatPane } from './left-float-pane';\nexport { default as LeftFixedPane } from './left-fixed-pane';\nexport { default as MainArea } from './main-area';\nexport { default as BottomArea } from './bottom-area';\nexport { default as TopArea } from './top-area';\nexport { default as SubTopArea } from './sub-top-area';"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/left-area.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\n\n@observer\nexport default class LeftArea extends Component<{ area: Area; className?: string }> {\n  render() {\n    const { area, className = 'lc-left-area' } = this.props;\n    if (area.isEmpty()) {\n      return null;\n    }\n    return (\n      <div className={classNames(className, {\n        'lc-area-visible': area.visible,\n      })}\n      >\n        <Contents area={area} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area }> {\n  render() {\n    const { area } = this.props;\n    const top: any[] = [];\n    const bottom: any[] = [];\n    area.container.items.slice().sort((a, b) => {\n      const index1 = a.config?.index || 0;\n      const index2 = b.config?.index || 0;\n      return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);\n    }).forEach((item) => {\n      const content = <div key={`left-area-${item.name}`}>{item.content}</div>;\n      if (item.align === 'bottom') {\n        bottom.push(content);\n      } else {\n        top.push(content);\n      }\n    });\n    return (\n      <Fragment>\n        <div className=\"lc-left-area-top\">{top}</div>\n        <div className=\"lc-left-area-bottom\">{bottom}</div>\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/left-fixed-pane.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\nimport { Panel } from '../widget/panel';\nimport { IPublicTypePanelConfig } from '@alilc/lowcode-types';\n\n@observer\nexport default class LeftFixedPane extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> {\n  componentDidUpdate() {\n    // FIXME: dirty fix, need deep think\n    this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver();\n  }\n\n  render() {\n    const { area } = this.props;\n    const width = area.current?.config.props?.width;\n    const style = width\n      ? {\n        width,\n      }\n      : undefined;\n\n    return (\n      <div\n        className={classNames('lc-left-fixed-pane', {\n          'lc-area-visible': area.visible,\n        })}\n        style={style}\n      >\n        <Contents area={area} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> {\n  render() {\n    const { area } = this.props;\n    return <Fragment>{area.container.items.map((panel) => panel.content)}</Fragment>;\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/left-float-pane.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer, Focusable } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\nimport { Panel } from '../widget/panel';\nimport { IPublicApiProject, IPublicTypePanelConfig } from '@alilc/lowcode-types';\n\n@observer\nexport default class LeftFloatPane extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> {\n  private dispose?: () => void;\n\n  private focusing?: Focusable;\n\n  private shell: HTMLElement | null = null;\n\n  componentDidMount() {\n    const { area } = this.props;\n    const triggerClose = (e: any) => {\n      if (!area.visible) return;\n      // 当 MouseEvent 的 target 为「插入占位符」时，不关闭当前 panel\n      if (e.originalEvent?.target?.classList.contains('insertion')) return;\n      // 假如当前操作 target 祖先节点中有属性 data-keep-visible-while-dragging=\"true\" 代表该 target 所属 panel\n      // 不希望 target 在 panel 范围内拖拽时关闭 panel\n      const panelElem = e.originalEvent?.target.closest('div[data-keep-visible-while-dragging=\"true\"]');\n      if (panelElem) return;\n      area.setVisible(false);\n    };\n    area.skeleton.editor.eventBus.on('designer.drag', triggerClose);\n\n    this.dispose = () => {\n      area.skeleton.editor.removeListener('designer.drag', triggerClose);\n    };\n\n    const project: IPublicApiProject | undefined = area.skeleton.editor.get('project');\n\n    this.focusing = area.skeleton.focusTracker.create({\n      range: (e) => {\n        const target = e.target as HTMLElement;\n        if (!target) {\n          return false;\n        }\n        if (this.shell?.contains(target)) {\n          return true;\n        }\n        // 点击了 iframe 内容，算失焦\n        if ((document.querySelector('.lc-simulator-content-frame') as HTMLIFrameElement)?.contentWindow?.document.documentElement.contains(target)) {\n          return false;\n        }\n        if (project?.simulatorHost?.contentWindow?.document.documentElement.contains(target)) {\n          return false;\n        }\n        // 点击设置区\n        if (document.querySelector('.lc-right-area')?.contains(target)) {\n          return false;\n        }\n        // 点击非编辑区域的popup/dialog,插件栏左侧等不触发失焦\n        if (!document.querySelector('.lc-workbench')?.contains(target)) {\n          return true;\n        }\n        // 排除设置区，iframe 之后，都不算失焦\n        if (document.querySelector('.lc-workbench-body')?.contains(target)) {\n          return true;\n        }\n        const docks = area.current?.getAssocDocks();\n        if (docks && docks?.length) {\n          return docks.some(dock => dock.getDOMNode()?.contains(target));\n        }\n        return false;\n      },\n      onEsc: () => {\n        this.props.area.setVisible(false);\n      },\n      onBlur: () => {\n        this.props.area.setVisible(false);\n      },\n    });\n\n    this.onEffect();\n  }\n\n  onEffect() {\n    const { area } = this.props;\n    if (area.visible) {\n      this.focusing?.active();\n      // 关闭当前fixed区域的面板\n      // TODO: 看看有没有更合适的地方\n      const fixedContainer = area?.skeleton?.leftFixedArea?.container;\n      const currentFixed = fixedContainer?.current;\n      if (currentFixed) {\n        fixedContainer.unactive(currentFixed);\n      }\n    } else {\n      this.focusing?.suspense();\n    }\n  }\n\n  componentDidUpdate() {\n    this.onEffect();\n  }\n\n  componentWillUnmount() {\n    this.focusing?.purge();\n    this.dispose?.();\n  }\n\n  render() {\n    const { area } = this.props;\n    const width = area.current?.config.props?.width;\n\n    const style = width ? {\n      width,\n    } : undefined;\n    return (\n      <div\n        ref={(ref) => { this.shell = ref; }}\n        className={classNames('lc-left-float-pane', {\n          'lc-area-visible': area.visible,\n        })}\n        style={style}\n      >\n        <Contents area={area} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area<any, Panel> }> {\n  render() {\n    const { area } = this.props;\n    return (\n      <Fragment>\n        {area.container.items.map((panel) => panel.content)}\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/main-area.tsx",
    "content": "import { Component } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\nimport { Panel } from '../widget/panel';\nimport { Widget } from '../widget/widget';\n\n@observer\nexport default class MainArea extends Component<{ area: Area<any, Panel | Widget> }> {\n  render() {\n    const { area } = this.props;\n    return (\n      <div className={classNames('lc-main-area engine-workspacepane')}>\n        {area.container.items.map((item) => item.content)}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/right-area.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\nimport { Panel } from '../widget/panel';\n\n@observer\nexport default class RightArea extends Component<{ area: Area<any, Panel> }> {\n  render() {\n    const { area } = this.props;\n    if (area.isEmpty()) {\n      return null;\n    }\n    return (\n      <div className={classNames('lc-right-area engine-tabpane', {\n        'lc-area-visible': area.visible,\n      })}\n      >\n        <Contents area={area} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area<any, Panel> }> {\n  render() {\n    const { area } = this.props;\n\n    return (\n      <Fragment>\n        {\n          area.container.items\n            .slice()\n            .sort((a, b) => {\n              const index1 = a.config?.index || 0;\n              const index2 = b.config?.index || 0;\n              return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);\n            })\n            .map((item) => item.content)\n        }\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/sub-top-area.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '@alilc/lowcode-editor-skeleton';\n\n@observer\nexport default class SubTopArea extends Component<{ area: Area; itemClassName?: string }> {\n  render() {\n    const { area, itemClassName } = this.props;\n\n    if (area.isEmpty()) {\n      return null;\n    }\n\n    return (\n      <div className={classNames('lc-workspace-sub-top-area lc-sub-top-area engine-actionpane', {\n        'lc-area-visible': area.visible,\n      })}\n      >\n        <Contents area={area} itemClassName={itemClassName} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area; itemClassName?: string }> {\n  render() {\n    const { area, itemClassName } = this.props;\n    const left: any[] = [];\n    const center: any[] = [];\n    const right: any[] = [];\n    area.container.items.slice().sort((a, b) => {\n      const index1 = a.config?.index || 0;\n      const index2 = b.config?.index || 0;\n      return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);\n    }).forEach(item => {\n      const content = (\n        <div className={itemClassName || ''} key={`top-area-${item.name}`}>\n          {item.content}\n        </div>\n      );\n      if (item.align === 'center') {\n        center.push(content);\n      } else if (item.align === 'left') {\n        left.push(content);\n      } else {\n        right.push(content);\n      }\n    });\n    let children = [];\n    if (left && left.length) {\n      children.push(<div className=\"lc-workspace-sub-top-area-left lc-sub-top-area-left\">{left}</div>);\n    }\n    if (center && center.length) {\n      children.push(<div className=\"lc-workspace-sub-top-area-center lc-sub-top-area-center\">{center}</div>);\n    }\n    if (right && right.length) {\n      children.push(<div className=\"lc-workspace-sub-top-area-right lc-sub-top-area-right\">{right}</div>);\n    }\n    return (\n      <Fragment>\n        {children}\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/theme.less",
    "content": "@import '../less-variables.less';\n\n/*\n * Theme Colors\n *\n * 乐高设计器的主要主题色变量\n */\n:root {\n  --color-brand: @brand-color-1;\n  --color-brand-light: @brand-color-2;\n  --color-brand-dark: @brand-color-3;\n\n  --color-canvas-background: @normal-alpha-8;\n\n  --color-icon-normal: @normal-alpha-4;\n  --color-icon-hover: @normal-alpha-3;\n  --color-icon-light: @normal-alpha-5;\n  --color-icon-active: @brand-color-1;\n  --color-icon-reverse: @white-alpha-1;\n  --color-icon-disabled: @normal-alpha-6;\n  --color-icon-pane: @dark-alpha-3;\n\n  --color-line-normal: @normal-alpha-7;\n  --color-line-darken: darken(@normal-alpha-7, 10%);\n\n  --color-title: @dark-alpha-2;\n  --color-text: @dark-alpha-3;\n  --color-text-dark: darken(@dark-alpha-3, 10%);\n  --color-text-light: lighten(@dark-alpha-3, 10%);\n  --color-text-reverse: @white-alpha-2;\n  --color-text-disabled: @gray-light;\n\n  --color-field-label: @dark-alpha-4;\n  --color-field-text: @dark-alpha-3;\n  --color-field-placeholder: @normal-alpha-5;\n  --color-field-border: @normal-alpha-5;\n  --color-field-border-hover: @normal-alpha-4;\n  --color-field-border-active: @normal-alpha-3;\n  --color-field-background: @white-alpha-1;\n\n  --color-success: @brand-success;\n  --colo-success-dark: darken(@brand-success, 10%);\n  --color-success-light: lighten(@brand-success, 10%);\n  --color-warning: @brand-warning;\n  --color-warning-dark: darken(@brand-warning, 10%);\n  --color-warning-light: lighten(@brand-warning, 10%);\n  --color-information: @brand-link-hover;\n  --color-information-dark: darken(@brand-link-hover, 10%);\n  --color-information-light: lighten(@brand-link-hover, 10%);\n  --color-error: @brand-danger;\n  --color-error-dark: darken(@brand-danger, 10%);\n  --color-error-light: lighten(@brand-danger, 10%);\n  --color-purple: rgb(144, 94, 190);\n  --color-brown: #7b605b;\n\n  --color-pane-background: @white-alpha-1;\n  --color-block-background-normal: @white-alpha-1;\n  --color-block-background-light: @normal-alpha-9;\n  --color-block-background-dark: @normal-alpha-7;\n  --color-block-background-shallow: @normal-alpha-8;\n  --color-block-background-disabled: @normal-alpha-6;\n  --color-block-background-active: @brand-color-1;\n  --color-block-background-active-light: @brand-color-1-7;\n  --color-block-background-warning: @brand-warning-alpha-7;\n  --color-block-background-error: @brand-danger-alpha-7;\n  --color-block-background-success: @brand-success-alpha-7;\n  --color-block-background-deep-dark: @normal-5;\n  --color-layer-mask-background: @dark-alpha-7;\n  --color-layer-tooltip-background: rgba(44,47,51,0.8);\n  --color-background: #edeff3;\n\n  --color-canvas-detecting-background: rgba(0,121,242,.04);\n\n  --pane-title-bg-color: rgba(31,56,88,.04);\n}\n\n// @deprecated 变量\n:root {\n  --color-function-success: @brand-success;\n  --color-function-success-dark: darken(@brand-success, 10%);\n  --color-function-success-light: lighten(@brand-success, 10%);\n  --color-function-warning: @brand-warning;\n  --color-function-warning-dark: darken(@brand-warning, 10%);\n  --color-function-warning-light: lighten(@brand-warning, 10%);\n  --color-function-information: @brand-link-hover;\n  --color-function-information-dark: darken(@brand-link-hover, 10%);\n  --color-function-information-light: lighten(@brand-link-hover, 10%);\n  --color-function-error: @brand-danger;\n  --color-function-error-dark: darken(@brand-danger, 10%);\n  --color-function-error-light: lighten(@brand-danger, 10%);\n  --color-function-purple: rgb(144, 94, 190);\n  --color-function-brown: #7b605b;\n  --color-text-regular: @normal-alpha-2;\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/toolbar.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\n\n@observer\nexport default class Toolbar extends Component<{ area: Area }> {\n  render() {\n    const { area } = this.props;\n    if (area.isEmpty()) {\n      return null;\n    }\n    return (\n      <div\n        className={classNames('lc-toolbar', {\n          'lc-area-visible': area.visible,\n        })}\n      >\n        <Contents area={area} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area }> {\n  render() {\n    const { area } = this.props;\n    const left: any[] = [];\n    const center: any[] = [];\n    const right: any[] = [];\n    area.container.items.forEach((item) => {\n      if (item.align === 'center') {\n        center.push(item.content);\n      } else if (item.align === 'right') {\n        right.push(item.content);\n      } else {\n        left.push(item.content);\n      }\n    });\n    return (\n      <Fragment>\n        <div className=\"lc-toolbar-left\">{left}</div>\n        <div className=\"lc-toolbar-center\">{center}</div>\n        <div className=\"lc-toolbar-right\">{right}</div>\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/top-area.tsx",
    "content": "import { Component, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { Area } from '../area';\n\n@observer\nexport default class TopArea extends Component<{ area: Area; itemClassName?: string; className?: string }> {\n  render() {\n    const { area, itemClassName, className } = this.props;\n    if (area.isEmpty()) {\n      return null;\n    }\n    return (\n      <div className={classNames(className, 'lc-top-area engine-actionpane', {\n        'lc-area-visible': area.visible,\n      })}\n      >\n        <Contents area={area} itemClassName={itemClassName} />\n      </div>\n    );\n  }\n}\n\n@observer\nclass Contents extends Component<{ area: Area; itemClassName?: string }> {\n  render() {\n    const { area, itemClassName } = this.props;\n    const left: any[] = [];\n    const center: any[] = [];\n    const right: any[] = [];\n    area.container.items.slice().sort((a, b) => {\n      const index1 = a.config?.index || 0;\n      const index2 = b.config?.index || 0;\n      return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);\n    }).forEach(item => {\n      const content = (\n        <div className={itemClassName || ''} key={`top-area-${item.name}`}>\n          {item.content}\n        </div>\n      );\n      if (item.align === 'center') {\n        center.push(content);\n      } else if (item.align === 'left') {\n        left.push(content);\n      } else {\n        right.push(content);\n      }\n    });\n    return (\n      <Fragment>\n        <div className=\"lc-top-area-left\">{left}</div>\n        <div className=\"lc-top-area-center\">{center}</div>\n        <div className=\"lc-top-area-right\">{right}</div>\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/workbench.less",
    "content": "@import './theme.less';\n\n:root {\n  --font-family: @font-family;\n  --font-size-label: @fontSize-4;\n  --font-size-text: @fontSize-5;\n  --font-size-btn-large: @fontSize-3;\n  --font-size-btn-medium: @fontSize-4;\n  --font-size-btn-small: @fontSize-5;\n\n  --global-border-radius: @global-border-radius;\n  --input-border-radius: @input-border-radius;\n  --popup-border-radius: @popup-border-radius;\n\n  --left-area-width: 48px;\n  --workspace-left-area-width: 48px;\n  --right-area-width: 300px;\n  --top-area-height: 48px;\n  --toolbar-height: 36px;\n  --dock-pane-width: 300px;\n  --dock-fixed-pane-width: 300px;\n}\n\n@media (min-width: 1860px) {\n  :root {\n    --right-area-width: 400px;\n    --dock-pane-width: 452px;\n    --dock-fixed-pane-width: 350px;\n  }\n}\n\nhtml,\nbody {\n  height: 100%;\n  overflow: hidden;\n  padding: 0;\n  margin: 0;\n  position: relative;\n  font-family: var(--font-family);\n  font-size: var(--font-size-text);\n  color: var(--color-text);\n  background-color: var(--color-background);\n}\n\n* {\n  box-sizing: border-box;\n}\n\n.lc-titled-panel {\n  width: 100%;\n  height: 100%;\n  position: relative;\n  &.hidden {\n    display: none;\n  }\n  .lc-panel-title {\n    display: flex;\n    align-items: center;\n    justify-content: flex-start;\n    padding: 0 15px;\n\n    .lc-help-tip {\n      margin-left: 4px;\n      color: var(--color-icon-normal, rgba(0, 0, 0, 0.4));\n      cursor: pointer;\n    }\n  }\n  > .lc-panel-title {\n    height: var(--pane-title-height, 48px);\n    font-size: var(--pane-title-font-size, 16px);\n    padding: var(--pane-title-padding, 0 15px);\n    color: var(--color-title, #0f1726);\n    font-weight: bold;\n  }\n\n  .lc-panel-body {\n    position: absolute;\n    top: var(--pane-title-height, 48px);\n    bottom: 0;\n    left: 0;\n    right: 0;\n    overflow: visible;\n  }\n  .lc-outline-tree-container {\n    border-top: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1));\n  }\n}\n.lc-panel {\n  height: 100%;\n  width: 100%;\n  position: relative;\n  &.hidden {\n    display: none;\n  }\n}\n\n.workspace-engine-main {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  background-color: var(--color-background);\n  position: absolute;\n  left: 0;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  z-index: -1;\n  overflow: hidden;\n\n  &.active {\n    z-index: 999;\n  }\n\n  .lc-workbench {\n\n  }\n\n  .engine-editor-view {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    display: flex;\n    flex-direction: column;\n\n    &.active {\n      z-index: 999;\n      background: var(--color-background);\n    }\n  }\n}\n\n.lc-workbench, .lc-workspace-workbench {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  background-color: var(--color-background);\n\n  &.engine-main {\n    height: 100%;\n    display: flex;\n    flex-direction: column;\n    background-color: var(--color-background);\n  }\n  .lc-top-area, .lc-workspace-sub-top-area {\n    width: 100%;\n    display: none;\n    margin-bottom: 2px;\n    padding: 8px 12px 8px 16px;\n\n    &.lc-top-area {\n      background-color: var(--color-top-area-background, var(--color-pane-background));\n      height: var(--top-area-height);\n    }\n\n    &.lc-workspace-top-area {\n      background-color: var(--color-workspace-top-area-background, var(--color-pane-background));\n    }\n\n    &.lc-workspace-sub-top-area {\n      background-color: var(--color-workspace-sub-top-area-background, var(--color-pane-background));\n      height: var(--workspace-sub-top-area-height, var(--top-area-height));\n      margin: var(--workspace-sub-top-area-margin, 0px 0px 2px 0px);\n      padding: var(--workspace-sub-top-area-padding, 8px 12px 8px 16px);\n    }\n\n    &.lc-area-visible {\n      display: flex;\n    }\n\n    .lc-top-area-left, .lc-workspace-sub-top-area-left {\n      display: flex;\n      align-items: center;\n      max-width: 100%;\n    }\n\n    .lc-top-area-center, .lc-workspace-sub-top-area-center {\n      flex: 1;\n      display: flex;\n      justify-content: center;\n      margin: 0 8px;\n    }\n    .lc-top-area-right, .lc-workspace-sub-top-area-right {\n      display: flex;\n      align-items: center;\n      > * {\n        margin-left: 4px;\n        margin-right: 4px;\n      }\n      .ve-quick-search-trigger {\n        display: flex;\n      }\n    }\n  }\n  .lc-workbench-body, .lc-workspace-workbench-body {\n    flex: 1;\n    display: flex;\n    min-height: 0;\n    position: relative;\n\n    .lc-tabs-title {\n      width: 100%;\n      height: 32px;\n      position: relative;\n      display: center;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n      border-bottom: 1px solid var(--color-line-normal, #edeff3);\n      .lc-tab-title {\n        flex: 1;\n        height: 32px;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        border-bottom: 2px solid transparent;\n        cursor: pointer;\n        font-size: 12px;\n        &.actived {\n          color: var(--color-brand, #0079f2);\n          border-bottom-color: var(--color-brand, #0079f2);\n        }\n      }\n    }\n\n    .lc-tabs-content {\n      position: absolute;\n      top: 32px;\n      bottom: 0;\n      left: 0;\n      right: 0;\n    }\n\n    .lc-pane-icon-close {\n      position: absolute;\n      right: 16px;\n      top: calc(var(--pane-title-height, 48px) / 2 - 10px);\n      height: auto;\n      z-index: 2;\n      .next-icon {\n        line-height: 1;\n        color: var(--color-icon-pane);\n      }\n    }\n\n    .lc-pane-icon-fix,\n    .lc-pane-icon-float {\n      position: absolute;\n      right: 38px;\n      top: calc(var(--pane-title-height, 48px) / 2 - 10px);\n      height: auto;\n      z-index: 2;\n      svg {\n        vertical-align: middle;\n        color: var(--color-icon-pane);\n      }\n    }\n\n    .lc-left-float-pane {\n      position: absolute;\n      top: 0;\n      bottom: 0;\n      width: var(--dock-pane-width);\n      // min-width: var(--dock-fixed-pane-width);\n      left: calc(var(--left-area-width) + 1px);\n      background-color: var(--color-left-float-pane-background, var(--color-pane-background));\n      box-shadow: 4px 6px 6px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.08));\n      z-index: 820;\n      display: none;\n      // padding-top: 36px;\n      &.lc-area-visible {\n        display: block;\n      }\n    }\n    .lc-left-area, .lc-workspace-left-area {\n      height: 100%;\n      width: var(--workspace-left-area-width, --left-area-width);\n      display: none;\n      flex-shrink: 0;\n      flex-direction: column;\n      justify-content: space-between;\n      overflow: hidden;\n      background-color: var(--color-left-area-background, var(--color-pane-background));\n\n      &.lc-workspace-left-area {\n        background-color: var(--color-workspace-left-area-background, var(--color-pane-background));\n      }\n      &.lc-area-visible {\n        display: flex;\n      }\n      .lc-left-area-top,\n      .lc-left-area-bottom {\n        width: 100%;\n        display: flex;\n        flex-direction: column;\n        justify-content: flex-start;\n        align-items: center;\n        color: var(--color-text);\n\n        .lc-title {\n          flex-direction: column;\n          width: calc(var(--left-area-width) - 2px);\n          height: 46px;\n          display: flex;\n          align-items: center;\n          justify-content: center;\n          cursor: pointer;\n\n          &.has-tip {\n            cursor: pointer;\n          }\n          &.actived {\n            color: var(--color-brand, #0079f2);\n          }\n          &.disabled {\n            opacity: 0.4;\n          }\n          .lc-title-icon {\n            height: 20px;\n            width: 20px;\n            margin: 0;\n            .next-icon:before {\n              line-height: 1 !important;\n            }\n          }\n        }\n      }\n      .lc-left-area-top {\n        padding-top: 12px;\n      }\n      .lc-left-area-bottom {\n        padding-bottom: 12px;\n      }\n    }\n    .lc-left-fixed-pane {\n      width: var(--dock-fixed-pane-width);\n      background-color: var(--color-pane-background);\n      height: 100%;\n      display: none;\n      flex-shrink: 0;\n      position: relative;\n      z-index: 820;\n      &.lc-area-visible {\n        display: block;\n      }\n    }\n    .lc-left-area.lc-area-visible ~ .lc-left-fixed-pane {\n      margin-left: 1px;\n    }\n    .lc-left-area.lc-area-visible ~ .lc-workbench-center {\n      margin-left: 2px;\n    }\n    .lc-workspace-left-area.lc-area-visible ~ .lc-workspace-workbench-center {\n      margin-left: 2px;\n    }\n    .lc-outline-pane {\n      .lc-outline-tree .tree-node .tree-node-title {\n        border-bottom: none;\n      }\n    }\n    .lc-workbench-center {\n      flex: 1;\n      display: flex;\n      flex-direction: column;\n\n      .lc-toolbar {\n        display: flex;\n        height: var(--toolbar-height);\n        background-color: var(--color-toolbar-background, var(--color-pane-background));\n        padding: var(--toolbar-padding, 8px 16px);\n        .lc-toolbar-center {\n          display: flex;\n          justify-content: center;\n          align-items: center;\n          flex: 1;\n        }\n      }\n      .lc-main-area {\n        flex: 1;\n        background-color: var(--color-background);\n      }\n      .lc-bottom-area {\n        height: var(--bottom-area-height);\n        background-color: var(--color-pane-background);\n        display: none;\n        &.lc-area-visible {\n          display: block;\n        }\n      }\n    }\n    .lc-right-area {\n      height: 100%;\n      width: var(--right-area-width);\n      background-color: var(--color-right-area-background, var(--color-pane-background));\n      display: none;\n      flex-shrink: 0;\n      margin-left: 2px;\n      position: relative;\n      > .lc-panel {\n        position: absolute;\n        background-color: var(--color-right-area-background, var(--color-pane-background, #fff));\n        left: 0;\n        top: 0;\n        z-index: 1;\n      }\n      &.lc-area-visible {\n        display: block;\n      }\n      .lc-settings-tabs {\n        > .next-tabs-nav-extra {\n          top: 36px !important;\n        }\n        .lc-settings-tab-item {\n          .next-tabs-tab-inner {\n            font-size: 12px;\n            line-height: 12px;\n          }\n        }\n        .lc-title {\n          color: inherit;\n          line-height: inherit !important;\n        }\n      }\n      .lc-settings-tabs-content {\n        top: 66px;\n      }\n    }\n  }\n  .engine-actionitem {\n    max-width: 100%;\n    color: var(--color-text);\n  }\n}\n\n.lc-workspace-workbench {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  background-color: var(--color-background);\n  .lc-workspace-workbench-body {\n    flex: 1;\n    display: flex;\n    min-height: 0;\n    position: relative;\n\n    > .lc-left-float-pane {\n      left: calc(var(--workspace-left-area-width, var(--left-area-width)) + 1px);\n    }\n\n    .lc-workspace-workbench-center {\n      flex: 1;\n      display: flex;\n      flex-direction: column;\n      z-index: 10;\n      position: relative;\n      .lc-toolbar {\n        display: flex;\n        height: var(--toolbar-height);\n        background-color: var(--color-toolbar-background, var(--color-pane-background));\n        padding: var(--toolbar-padding, 8px 16px);\n        .lc-toolbar-center {\n          display: flex;\n          justify-content: center;\n          align-items: center;\n          flex: 1;\n        }\n      }\n      .lc-main-area {\n        flex: 1;\n      }\n      .lc-bottom-area {\n        height: var(--bottom-area-height);\n        background-color: var(--color-pane-background);\n        display: none;\n        &.lc-area-visible {\n          display: block;\n        }\n      }\n    }\n\n    .lc-workspace-workbench-center-content {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      flex-direction: column;\n      display: flex;\n      align-content: stretch;\n    }\n\n    .lc-workspace-workbench-window {\n      position: relative;\n      height: 100%;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/layouts/workbench.tsx",
    "content": "import { Component } from 'react';\nimport { TipContainer, observer } from '@alilc/lowcode-editor-core';\nimport classNames from 'classnames';\nimport { ISkeleton } from '../skeleton';\nimport TopArea from './top-area';\nimport LeftArea from './left-area';\nimport LeftFixedPane from './left-fixed-pane';\nimport LeftFloatPane from './left-float-pane';\nimport Toolbar from './toolbar';\nimport MainArea from './main-area';\nimport BottomArea from './bottom-area';\nimport RightArea from './right-area';\nimport './workbench.less';\nimport { SkeletonContext } from '../context';\nimport { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';\n\n@observer\nexport class Workbench extends Component<{\n  skeleton: ISkeleton;\n  config?: EditorConfig;\n  components?: PluginClassSet;\n  className?: string;\n  topAreaItemClassName?: string;\n}> {\n  constructor(props: any) {\n    super(props);\n    const { config, components, skeleton } = this.props;\n    skeleton.buildFromConfig(config, components);\n  }\n\n  render() {\n    const {\n      skeleton,\n      className,\n      topAreaItemClassName,\n    } = this.props;\n    return (\n      <div className={classNames('lc-workbench', className)}>\n        <SkeletonContext.Provider value={this.props.skeleton}>\n          <TopArea area={skeleton.topArea} itemClassName={topAreaItemClassName} />\n          <div className=\"lc-workbench-body\">\n            <LeftArea area={skeleton.leftArea} />\n            <LeftFloatPane area={skeleton.leftFloatArea} />\n            <LeftFixedPane area={skeleton.leftFixedArea} />\n            <div className=\"lc-workbench-center\">\n              <Toolbar area={skeleton.toolbar} />\n              <MainArea area={skeleton.mainArea} />\n              <BottomArea area={skeleton.bottomArea} />\n            </div>\n            <RightArea area={skeleton.rightArea} />\n          </div>\n          <TipContainer />\n        </SkeletonContext.Provider>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/less-variables.less",
    "content": "/*\n * 基础的 DPL 定义使用了 kuma base 的定义，参考：\n * https://github.com/uxcore/kuma-base/tree/master/variables\n */\n\n/**\n * ===========================================================\n * ==================== Font Family ==========================\n * ===========================================================\n */\n\n/*\n * @font-family: \"STHeiti\", \"Microsoft Yahei\", \"Lucida Grande\", \"Lucida Sans Unicode\", Helvetica, Arial, Verdana, sans-serif;\n */\n\n@font-family: 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial, sans-serif;\n@font-family-code: Monaco, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial,\n  sans-serif;\n\n/**\n * ===========================================================\n * ===================== Color DPL ===========================\n * ===========================================================\n  */\n\n@brand-color-1: rgba(0, 108, 255, 1);\n@brand-color-2: rgba(25, 122, 255, 1);\n@brand-color-3: rgba(0, 96, 229, 1);\n\n@brand-color-1-3: rgba(0, 108, 255, 0.6);\n@brand-color-1-4: rgba(0, 108, 255, 0.4);\n@brand-color-1-5: rgba(0, 108, 255, 0.3);\n@brand-color-1-6: rgba(0, 108, 255, 0.2);\n@brand-color-1-7: rgba(0, 108, 255, 0.1);\n\n@brand-color: @brand-color-1;\n\n@white-alpha-1: rgb(255, 255, 255); // W-1\n@white-alpha-2: rgba(255, 255, 255, 0.8); // W-2 A80\n@white-alpha-3: rgba(255, 255, 255, 0.6); // W-3 A60\n@white-alpha-4: rgba(255, 255, 255, 0.4); // W-4 A40\n@white-alpha-5: rgba(255, 255, 255, 0.3); // W-5 A30\n@white-alpha-6: rgba(255, 255, 255, 0.2); // W-6 A20\n@white-alpha-7: rgba(255, 255, 255, 0.1); // W-7 A10\n@white-alpha-8: rgba(255, 255, 255, 0.06); // W-8 A6\n\n@dark-alpha-1: rgba(0, 0, 0, 1); // D-1 A100\n@dark-alpha-2: rgba(0, 0, 0, 0.8); // D-2 A80\n@dark-alpha-3: rgba(0, 0, 0, 0.6); // D-3 A60\n@dark-alpha-4: rgba(0, 0, 0, 0.4); // D-4 A40\n@dark-alpha-5: rgba(0, 0, 0, 0.3); // D-5 A30\n@dark-alpha-6: rgba(0, 0, 0, 0.2); // D-6 A20\n@dark-alpha-7: rgba(0, 0, 0, 0.1); // D-7 A10\n@dark-alpha-8: rgba(0, 0, 0, 0.06); // D-8 A6\n@dark-alpha-9: rgba(0, 0, 0, 0.04); // D-9 A4\n\n@normal-alpha-1: rgba(31, 56, 88, 1); // N-1 A100\n@normal-alpha-2: rgba(31, 56, 88, 0.8); // N-2 A80\n@normal-alpha-3: rgba(31, 56, 88, 0.6); // N-3 A60\n@normal-alpha-4: rgba(31, 56, 88, 0.4); // N-4 A40\n@normal-alpha-5: rgba(31, 56, 88, 0.3); // N-5 A30\n@normal-alpha-6: rgba(31, 56, 88, 0.2); // N-6 A20\n@normal-alpha-7: rgba(31, 56, 88, 0.1); // N-7 A10\n@normal-alpha-8: rgba(31, 56, 88, 0.06); // N-8 A6\n@normal-alpha-9: rgba(31, 56, 88, 0.04); // N-9 A4\n\n@normal-3: #77879c;\n@normal-4: #a3aebd;\n@normal-5: #bac3cc;\n@normal-6: #d1d7de;\n\n@gray-dark: #333; // N2_4\n@gray: #666; // N2_3\n@gray-light: #999; // N2_2\n@gray-lighter: #ccc; // N2_1\n\n@brand-secondary: #2c2f33; // B2_3\n// 补色\n@brand-complement: #00b3e8; // B3_1\n// 复合\n@brand-comosite: #00c587; // B3_2\n// 浓度\n@brand-deep: #73461d; // B3_3\n\n// F1-1\n@brand-danger: rgb(240, 70, 49);\n// F1-2 (10% white)\n@brand-danger-hover: rgba(240, 70, 49, 0.9);\n// F1-3 (5% black)\n@brand-danger-focus: rgba(240, 70, 49, 0.95);\n\n// F2-1\n@brand-warning: rgb(250, 189, 14);\n// F3-1\n@brand-success: rgb(102, 188, 92);\n// F4-1\n@brand-link: rgb(102, 188, 92);\n// F4-2\n@brand-link-hover: #2e76a6;\n\n// F1-1-7 A10\n@brand-danger-alpha-7: rgba(240, 70, 49, 0.1);\n// F1-1-8 A6\n@brand-danger-alpha-8: rgba(240, 70, 49, 0.8);\n// F2-1-2 A80\n@brand-warning-alpha-2: rgba(250, 189, 14, 0.8);\n// F2-1-7 A10\n@brand-warning-alpha-7: rgba(250, 189, 14, 0.1);\n// F3-1-2 A80\n@brand-success-alpha-2: rgba(102, 188, 92, 0.8);\n// F3-1-7 A10\n@brand-success-alpha-7: rgba(102, 188, 92, 0.1);\n// F4-1-7 A10\n@brand-link-alpha-7: rgba(102, 188, 92, 0.1);\n\n// 文本色\n@text-primary-color: @dark-alpha-3;\n@text-secondary-color: @normal-alpha-3;\n@text-thirdary-color: @dark-alpha-4;\n@text-disabled-color: @normal-alpha-5;\n@text-helper-color: @dark-alpha-4;\n@text-danger-color: @brand-danger;\n@text-ali-color: #ec6c00;\n\n/**\n  * ===========================================================\n  * =================== Shadow Box ============================\n  * ===========================================================\n  */\n\n@box-shadow-1: 0 1px 4px 0 rgba(31, 56, 88, 0.15); // 1 级阴影，物体由原来存在于底面的物体展开，物体和底面关联紧密\n@box-shadow-2: 0 2px 10px 0 rgba(31, 56, 88, 0.15); // 2 级阴影，hover状态，物体层级较高\n@box-shadow-3: 0 4px 15px 0 rgba(31, 56, 88, 0.15); // 3 级阴影，当物体层级高于所有界面元素，弹窗用\n\n/**\n  * ===========================================================\n  * ================= FontSize of Level =======================\n  * ===========================================================\n  */\n\n@fontSize-1: 26px;\n@fontSize-2: 20px;\n@fontSize-3: 16px;\n@fontSize-4: 14px;\n@fontSize-5: 12px;\n\n@fontLineHeight-1: 38px;\n@fontLineHeight-2: 30px;\n@fontLineHeight-3: 26px;\n@fontLineHeight-4: 24px;\n@fontLineHeight-5: 20px;\n\n/**\n  * ===========================================================\n  * ================= FontSize of Level =======================\n  * ===========================================================\n  */\n\n@global-border-radius: 3px;\n@input-border-radius: 3px;\n@popup-border-radius: 6px;\n\n/**\n  * ===========================================================\n  * ===================== Transistion =========================\n  * ===========================================================\n  */\n\n@transition-duration: 0.3s;\n@transition-ease: cubic-bezier(0.23, 1, 0.32, 1);\n@transition-delay: 0s;\n\n/**\n  * ===========================================================\n  * ================ Global Configruations ====================\n  * ===========================================================\n  */\n\n@topPaneHeight: 48px;\n@actionpane-height: 48px;\n@tabPaneWidth: 260px;\n@input-standard-height: 32px;\n@dockpane-width: 48px;\n\n/**\n  * ===========================================================\n  * =================== Deprecated Items ======================\n  * ===========================================================\n  */\n\n@head-bgcolor: @white-alpha-1;\n@pane-bgcolor: @white-alpha-1;\n@pane-dark-bgcolor: @white-alpha-1;\n@pane-bdcolor: @normal-4;\n@blank-bgcolor: @normal-5;\n@title-bgcolor: @white-alpha-1;\n@title-bdcolor: transparent;\n@section-bgcolor: transparent;\n@section-bdcolor: @white-alpha-1;\n@button-bgcolor: @white-alpha-1;\n@button-bdcolor: transparent;\n@button-blue-color: @brand-color;\n@button-blue-hover-color: @brand-color;\n@sub-title-bgcolor: @white-alpha-1;\n@sub-title-bdcolor: transparent;\n@text-color: @text-primary-color;\n@icon-color: @gray;\n@icon-color-active: @gray-light;\n@ghost-bgcolor: @dark-alpha-3;\n@input-bgcolor: transparent;\n@input-bdcolor: @normal-alpha-5;\n@hover-color: #5a99cc;\n@active-color: #5a99cc;\n@disabled-color: #666;\n@setter-popup-bg: rgb(80, 86, 109);\n"
  },
  {
    "path": "packages/editor-skeleton/src/locale/en-US.json",
    "content": "{\n  \"Binded: {expr}\": \"Binded: {expr}\",\n  \"Variable Binding\": \"Variable Binding\",\n  \"Switch Setter\": \"Switch Setter\",\n  \"Multiple Value, Click to Clear\": \"Multiple Value, Click to Clear\",\n  \"Required\": \"Required\",\n  \"Setted Value, Click to Clear\": \"Setted Value, Click to Clear\",\n  \"Multiple Value\": \"Multiple Value\",\n  \"Attribute: \": \"Attribute: \",\n  \"Description: \": \"Description: \",\n  \"Please select a node in canvas\": \"Please select a node in canvas\",\n  \"Current node is locked\": \"Current node is locked\",\n  \"No config found for this type of component\": \"No config found for this type of component\",\n  \"Please select same kind of components\": \"Please select same kind of components\"\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/locale/index.ts",
    "content": "import { createIntl } from '@alilc/lowcode-editor-core';\nimport enUS from './en-US.json';\nimport zhCN from './zh-CN.json';\n\nconst { intl, intlNode, getLocale, setLocale } = createIntl({\n  'en-US': enUS,\n  'zh-CN': zhCN,\n});\n\nexport { intl, intlNode, getLocale, setLocale };\n"
  },
  {
    "path": "packages/editor-skeleton/src/locale/zh-CN.json",
    "content": "{\n  \"Binded: {expr}\": \"已绑定：{expr}\",\n  \"Variable Binding\": \"变量绑定\",\n  \"Switch Setter\": \"切换设置器\",\n  \"Multiple Value, Click to Clear\": \"多种值，点击清除\",\n  \"Required\": \"必填项\",\n  \"Setted Value, Click to Clear\": \"已设置值，点击清除\",\n  \"Multiple Value\": \"多种值\",\n  \"Attribute: \": \"属性：\",\n  \"Description: \": \"说明：\",\n  \"Please select a node in canvas\": \"请在左侧画布选中节点\",\n  \"Current node is locked\": \"该节点已被锁定，无法配置\",\n  \"No config found for this type of component\": \"该组件暂无配置\",\n  \"Please select same kind of components\": \"请选中同一类型节点编辑\"\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/register-defaults.ts",
    "content": "import parseJSFunc from './transducers/parse-func';\nimport parseProps from './transducers/parse-props';\nimport addonCombine from './transducers/addon-combine';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nexport const registerDefaults = (ctx: IPublicModelPluginContext) => {\n  const { material } = ctx;\n  return {\n    init() {\n      // parseFunc\n      material.registerMetadataTransducer(parseJSFunc, 1, 'parse-func');\n\n      // parseProps\n      material.registerMetadataTransducer(parseProps, 5, 'parse-props');\n\n      // addon/platform custom\n      material.registerMetadataTransducer(addonCombine, 10, 'combine-props');\n    },\n  };\n};\n\n\nregisterDefaults.pluginName = '___register_defaults___';\n"
  },
  {
    "path": "packages/editor-skeleton/src/skeleton.ts",
    "content": "import { action, makeObservable, obx, engineConfig, IEditor, FocusTracker } from '@alilc/lowcode-editor-core';\nimport {\n  DockConfig,\n  WidgetConfig,\n  PanelDockConfig,\n  DialogDockConfig,\n  isDockConfig,\n  isPanelDockConfig,\n  isPanelConfig,\n  DividerConfig,\n  isDividerConfig,\n} from './types';\nimport { isPanel, Panel } from './widget/panel';\nimport { WidgetContainer } from './widget/widget-container';\nimport { Area } from './area';\nimport { isWidget, IWidget, Widget } from './widget/widget';\nimport { PanelDock } from './widget/panel-dock';\nimport { Dock } from './widget/dock';\nimport { Stage, StageConfig } from './widget/stage';\nimport { isValidElement } from 'react';\nimport { isPlainObject, uniqueId, Logger } from '@alilc/lowcode-utils';\nimport { Divider } from '@alifd/next';\nimport {\n  EditorConfig,\n  PluginClassSet,\n  IPublicTypeWidgetBaseConfig,\n  IPublicTypeWidgetConfigArea,\n  IPublicTypeSkeletonConfig,\n  IPublicApiSkeleton,\n  IPublicTypeConfigTransducer,\n  IPublicTypePanelConfig,\n} from '@alilc/lowcode-types';\n\nconst logger = new Logger({ level: 'warn', bizName: 'skeleton' });\n\nexport enum SkeletonEvents {\n  PANEL_DOCK_ACTIVE = 'skeleton.panel-dock.active',\n  PANEL_DOCK_UNACTIVE = 'skeleton.panel-dock.unactive',\n  PANEL_SHOW = 'skeleton.panel.show',\n  PANEL_HIDE = 'skeleton.panel.hide',\n  WIDGET_SHOW = 'skeleton.widget.show',\n  WIDGET_HIDE = 'skeleton.widget.hide',\n  WIDGET_DISABLE = 'skeleton.widget.disable',\n  WIDGET_ENABLE = 'skeleton.widget.enable',\n}\n\nexport interface ISkeleton extends Omit<IPublicApiSkeleton,\n  'showPanel' |\n  'hidePanel' |\n  'showWidget' |\n  'enableWidget' |\n  'hideWidget' |\n  'disableWidget' |\n  'showArea' |\n  'onShowPanel' |\n  'onHidePanel' |\n  'onShowWidget' |\n  'onHideWidget' |\n  'remove' |\n  'hideArea' |\n  'add'\n> {\n  editor: IEditor;\n\n  readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly topArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly subTopArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly leftFixedArea: Area<IPublicTypePanelConfig, Panel>;\n\n  readonly leftFloatArea: Area<IPublicTypePanelConfig, Panel>;\n\n  readonly rightArea: Area<IPublicTypePanelConfig, Panel>;\n\n  readonly mainArea: Area<WidgetConfig | IPublicTypePanelConfig, Widget | Panel>;\n\n  readonly bottomArea: Area<IPublicTypePanelConfig, Panel>;\n\n  readonly stages: Area<StageConfig, Stage>;\n\n  readonly widgets: IWidget[];\n\n  readonly focusTracker: FocusTracker;\n\n  getPanel(name: string): Panel | undefined;\n\n  getWidget(name: string): IWidget | undefined;\n\n  buildFromConfig(config?: EditorConfig, components?: PluginClassSet): void;\n\n  createStage(config: any): string | undefined;\n\n  getStage(name: string): Stage | null;\n\n  createContainer(\n    name: string,\n    handle: (item: any) => any,\n    exclusive?: boolean,\n    checkVisible?: () => boolean,\n    defaultSetCurrent?: boolean,\n  ): WidgetContainer;\n\n  createPanel(config: IPublicTypePanelConfig): Panel;\n\n  add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined;\n}\n\nexport class Skeleton implements ISkeleton {\n  private panels = new Map<string, Panel>();\n\n  private configTransducers: IPublicTypeConfigTransducer[] = [];\n\n  private containers = new Map<string, WidgetContainer<any>>();\n\n  readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly topArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly subTopArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;\n\n  readonly leftFixedArea: Area<IPublicTypePanelConfig, Panel>;\n\n  readonly leftFloatArea: Area<IPublicTypePanelConfig, Panel>;\n\n  readonly rightArea: Area<IPublicTypePanelConfig, Panel>;\n\n  @obx readonly mainArea: Area<WidgetConfig | IPublicTypePanelConfig, Widget | Panel>;\n\n  readonly bottomArea: Area<IPublicTypePanelConfig, Panel>;\n\n  readonly stages: Area<StageConfig, Stage>;\n\n  readonly widgets: IWidget[] = [];\n\n  readonly focusTracker = new FocusTracker();\n\n  constructor(readonly editor: IEditor, readonly viewName: string = 'global') {\n    makeObservable(this);\n    this.leftArea = new Area(\n      this,\n      'leftArea',\n      (config) => {\n        if (isWidget(config)) {\n          return config;\n        }\n        return this.createWidget(config);\n      },\n      false,\n    );\n    this.topArea = new Area(\n      this,\n      'topArea',\n      (config) => {\n        if (isWidget(config)) {\n          return config;\n        }\n        return this.createWidget(config);\n      },\n      false,\n    );\n    this.subTopArea = new Area(\n      this,\n      'subTopArea',\n      (config) => {\n        if (isWidget(config)) {\n          return config;\n        }\n        return this.createWidget(config);\n      },\n      false,\n    );\n    this.toolbar = new Area(\n      this,\n      'toolbar',\n      (config) => {\n        if (isWidget(config)) {\n          return config;\n        }\n        return this.createWidget(config);\n      },\n      false,\n    );\n    this.leftFixedArea = new Area(\n      this,\n      'leftFixedArea',\n      (config) => {\n        if (isPanel(config)) {\n          return config;\n        }\n        return this.createPanel(config);\n      },\n      true,\n    );\n    this.leftFloatArea = new Area(\n      this,\n      'leftFloatArea',\n      (config) => {\n        if (isPanel(config)) {\n          return config;\n        }\n        return this.createPanel(config);\n      },\n      true,\n    );\n    this.rightArea = new Area(\n      this,\n      'rightArea',\n      (config) => {\n        if (isPanel(config)) {\n          return config;\n        }\n        return this.createPanel(config);\n      },\n      false,\n      true,\n    );\n    this.mainArea = new Area(\n      this,\n      'mainArea',\n      (config) => {\n        if (isWidget(config)) {\n          return config as Widget;\n        }\n        return this.createWidget(config) as Widget;\n      },\n      true,\n      true,\n    );\n    this.bottomArea = new Area(\n      this,\n      'bottomArea',\n      (config) => {\n        if (isPanel(config)) {\n          return config;\n        }\n        return this.createPanel(config);\n      },\n      true,\n    );\n    this.stages = new Area(this, 'stages', (config) => {\n      if (isWidget(config)) {\n        return config;\n      }\n      return new Stage(this, config);\n    });\n\n    this.setupPlugins();\n    this.setupEvents();\n    this.focusTracker.mount(window);\n  }\n\n  /**\n   * setup events\n   *\n   * @memberof Skeleton\n   */\n  setupEvents() {\n    // adjust pinned status when panel shown\n    this.editor.eventBus.on(SkeletonEvents.PANEL_SHOW, (panelName, panel) => {\n      const panelNameKey = `${panelName}-pinned-status-isFloat`;\n      const isInFloatAreaPreferenceExists = engineConfig.getPreference()?.contains(panelNameKey, 'skeleton');\n      if (isInFloatAreaPreferenceExists) {\n        const isInFloatAreaFromPreference = engineConfig.getPreference()?.get(panelNameKey, 'skeleton');\n        const isCurrentInFloatArea = panel?.isChildOfFloatArea();\n        if (isInFloatAreaFromPreference !== isCurrentInFloatArea) {\n          this.toggleFloatStatus(panel);\n        }\n      }\n    });\n  }\n\n  /**\n   * set isFloat status for panel\n   *\n   * @param {*} panel\n   * @memberof Skeleton\n   */\n  @action\n  toggleFloatStatus(panel: Panel) {\n    const isFloat = panel?.parent?.name === 'leftFloatArea';\n    if (isFloat) {\n      this.leftFloatArea.remove(panel);\n      this.leftFixedArea.add(panel);\n      this.leftFixedArea.container.active(panel);\n    } else {\n      this.leftFixedArea.remove(panel);\n      this.leftFloatArea.add(panel);\n      this.leftFloatArea.container.active(panel);\n    }\n    engineConfig.getPreference().set(`${panel.name}-pinned-status-isFloat`, !isFloat, 'skeleton');\n  }\n\n  buildFromConfig(config?: EditorConfig, components: PluginClassSet = {}) {\n    if (config) {\n      this.editor.init(config, components);\n    }\n    this.setupPlugins();\n  }\n\n  private setupPlugins() {\n    const { config, components = {} } = this.editor;\n    if (!config) {\n      return;\n    }\n\n    const { plugins } = config;\n    if (!plugins) {\n      return;\n    }\n    Object.keys(plugins).forEach((area) => {\n      plugins[area].forEach((item) => {\n        const { pluginKey, type, props = {}, pluginProps } = item;\n        const config: IPublicTypeWidgetBaseConfig = {\n          area: area as IPublicTypeWidgetConfigArea,\n          type: 'Widget',\n          name: pluginKey,\n          contentProps: pluginProps,\n        };\n        const { dialogProps, balloonProps, panelProps, linkProps, ...restProps } = props;\n        config.props = restProps;\n        if (dialogProps) {\n          config.dialogProps = dialogProps;\n        }\n        if (balloonProps) {\n          config.balloonProps = balloonProps;\n        }\n        if (panelProps) {\n          config.panelProps = panelProps;\n        }\n        if (linkProps) {\n          config.linkProps = linkProps;\n        }\n        if (type === 'TabPanel') {\n          config.type = 'Panel';\n        } else if (/Icon$/.test(type)) {\n          config.type = type.replace('Icon', 'Dock');\n        }\n        if (pluginKey in components) {\n          config.content = components[pluginKey];\n        }\n        this.add(config);\n      });\n    });\n  }\n\n  postEvent(event: SkeletonEvents, ...args: any[]) {\n    this.editor.eventBus.emit(event, ...args);\n  }\n\n  createWidget(config: IPublicTypeWidgetBaseConfig | IWidget) {\n    if (isWidget(config)) {\n      return config;\n    }\n\n    config = this.parseConfig(config);\n    let widget: IWidget;\n    if (isDockConfig(config)) {\n      if (isPanelDockConfig(config)) {\n        widget = new PanelDock(this, config);\n      } else if (false) {\n        // DialogDock\n        // others...\n      } else {\n        widget = new Dock(this, config);\n      }\n    } else if (isDividerConfig(config)) {\n      widget = new Widget(this, {\n        ...config,\n        type: 'Widget',\n        content: Divider,\n      });\n    } else if (isPanelConfig(config)) {\n      widget = this.createPanel(config);\n    } else {\n      widget = new Widget(this, config as WidgetConfig);\n    }\n    this.widgets.push(widget);\n    return widget;\n  }\n\n  getWidget(name: string): IWidget | undefined {\n    return this.widgets.find(widget => widget.name === name);\n  }\n\n  createPanel(config: IPublicTypePanelConfig) {\n    const parsedConfig = this.parseConfig(config);\n    const panel = new Panel(this, parsedConfig as IPublicTypePanelConfig);\n    this.panels.set(panel.name, panel);\n    logger.debug(`Panel created with name: ${panel.name} \\nconfig:`, config, '\\n current panels: ', this.panels);\n    return panel;\n  }\n\n  getPanel(name: string): Panel | undefined {\n    return this.panels.get(name);\n  }\n\n  getStage(name: string) {\n    return this.stages.container.get(name);\n  }\n\n  createStage(config: any) {\n    const stage = this.add({\n      name: uniqueId('stage'),\n      area: 'stages',\n      ...config,\n    });\n    return stage?.getName?.();\n  }\n\n  createContainer(\n    name: string,\n    handle: (item: any) => any,\n    exclusive = false,\n    checkVisible: () => boolean = () => true,\n    defaultSetCurrent = false,\n  ) {\n    const container = new WidgetContainer(name, handle, exclusive, checkVisible, defaultSetCurrent);\n    this.containers.set(name, container);\n    return container;\n  }\n\n  private parseConfig(config: IPublicTypeWidgetBaseConfig) {\n    if (config.parsed) {\n      return config;\n    }\n    const { content, ...restConfig } = config;\n    if (content) {\n      if (isPlainObject(content) && !isValidElement(content)) {\n        Object.keys(content).forEach((key) => {\n          if (/props$/i.test(key) && restConfig[key]) {\n            restConfig[key] = {\n              ...restConfig[key],\n              ...content[key],\n            };\n          } else {\n            restConfig[key] = content[key];\n          }\n        });\n      } else {\n        restConfig.content = content;\n      }\n    }\n    restConfig.pluginKey = restConfig.name;\n    restConfig.parsed = true;\n    return restConfig;\n  }\n\n  registerConfigTransducer(\n    transducer: IPublicTypeConfigTransducer,\n    level = 100,\n    id?: string,\n  ) {\n    transducer.level = level;\n    transducer.id = id;\n    const i = this.configTransducers.findIndex((item) => item.level != null && item.level > level);\n    if (i < 0) {\n      this.configTransducers.push(transducer);\n    } else {\n      this.configTransducers.splice(i, 0, transducer);\n    }\n  }\n\n  getRegisteredConfigTransducers(): IPublicTypeConfigTransducer[] {\n    return this.configTransducers;\n  }\n\n  add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined {\n    const registeredTransducers = this.getRegisteredConfigTransducers();\n\n    const parsedConfig = registeredTransducers.reduce((prevConfig, current) => {\n      return current(prevConfig);\n    }, {\n      ...this.parseConfig(config),\n      ...extraConfig,\n    });\n\n    let { area } = parsedConfig;\n    if (!area) {\n      if (parsedConfig.type === 'Panel') {\n        area = 'leftFloatArea';\n      } else if (parsedConfig.type === 'Widget') {\n        area = 'mainArea';\n      } else {\n        area = 'leftArea';\n      }\n    }\n    switch (area) {\n      case 'leftArea':\n      case 'left':\n        return this.leftArea.add(parsedConfig as PanelDockConfig);\n      case 'rightArea':\n      case 'right':\n        return this.rightArea.add(parsedConfig as IPublicTypePanelConfig);\n      case 'topArea':\n      case 'top':\n        return this.topArea.add(parsedConfig as PanelDockConfig);\n      case 'subTopArea':\n        return this.subTopArea.add(parsedConfig as PanelDockConfig);\n      case 'toolbar':\n        return this.toolbar.add(parsedConfig as PanelDockConfig);\n      case 'mainArea':\n      case 'main':\n      case 'center':\n      case 'centerArea':\n        return this.mainArea.add(parsedConfig as IPublicTypePanelConfig);\n      case 'bottomArea':\n      case 'bottom':\n        return this.bottomArea.add(parsedConfig as IPublicTypePanelConfig);\n      case 'leftFixedArea':\n        return this.leftFixedArea.add(parsedConfig as IPublicTypePanelConfig);\n      case 'leftFloatArea':\n        return this.leftFloatArea.add(parsedConfig as IPublicTypePanelConfig);\n      case 'stages':\n        return this.stages.add(parsedConfig as StageConfig);\n      default:\n        // do nothing\n    }\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/transducers/addon-combine.ts",
    "content": "import {\n  IPublicTypeTransformedComponentMetadata,\n  IPublicTypeFieldConfig,\n  IPublicModelSettingField,\n} from '@alilc/lowcode-types';\nimport { IconSlot } from '../icons/slot';\nimport { getConvertedExtraKey } from '@alilc/lowcode-designer';\n\nexport default function (\n  metadata: IPublicTypeTransformedComponentMetadata,\n): IPublicTypeTransformedComponentMetadata {\n  const { componentName, configure = {} } = metadata;\n\n  // 如果已经处理过，不再重新执行一遍\n  if (configure.combined) {\n    return metadata;\n  }\n  if (componentName === 'Leaf') {\n    return {\n      ...metadata,\n      configure: {\n        ...configure,\n        combined: [\n          {\n            name: 'children',\n            title: { type: 'i18n', 'zh-CN': '内容设置', 'en-US': 'Content' },\n            setter: {\n              componentName: 'MixedSetter',\n              props: {\n                // TODO:\n                setters: [\n                  {\n                    componentName: 'StringSetter',\n                    props: {\n                      // TODO: textarea mode\n                      multiline: true,\n                    },\n                    initialValue: '',\n                  },\n                  {\n                    componentName: 'ExpressionSetter',\n                    initialValue: {\n                      type: 'JSExpression',\n                      value: '',\n                    },\n                  },\n                ],\n              },\n            },\n          },\n        ],\n      },\n    };\n  }\n\n  const { props, supports = {} } = configure as any;\n  const isRoot: boolean = componentName === 'Page' || componentName === 'Component';\n  const eventsDefinition: any[] = [];\n  const supportedLifecycles =\n    supports.lifecycles ||\n    (isRoot\n      ? /* [\n          {\n            description: '初始化时',\n            name: 'constructor',\n          },\n          {\n            description: '装载后',\n            name: 'componentDidMount',\n          },\n          {\n            description: '更新时',\n            name: 'componentDidUpdate',\n          },\n          {\n            description: '卸载时',\n            name: 'componentWillUnmount',\n          },\n        ] */ null\n      : null);\n  if (supportedLifecycles) {\n    eventsDefinition.push({\n      type: 'lifeCycleEvent',\n      title: '生命周期',\n      list: supportedLifecycles.map((event: any) => (typeof event === 'string' ? { name: event } : event)),\n    });\n  }\n  if (supports.events) {\n    eventsDefinition.push({\n      type: 'events',\n      title: '事件',\n      list: (supports.events || []).map((event: any) => (typeof event === 'string' ? { name: event } : event)),\n    });\n  }\n  //  通用设置\n  let propsGroup = props ? [...props] : [];\n  const basicInfo: any = {};\n  if (componentName === 'Slot') {\n    if (!configure.component) {\n      configure.component = {\n        isContainer: true,\n      };\n    } else if (typeof configure.component === 'object') {\n      configure.component.isContainer = true;\n    }\n    basicInfo.icon = IconSlot;\n    propsGroup = [\n      {\n        name: getConvertedExtraKey('title'),\n        title: {\n          type: 'i18n',\n          'en-US': 'Slot Title',\n          'zh-CN': '插槽标题',\n        },\n        setter: 'StringSetter',\n        defaultValue: '插槽容器',\n      },\n    ];\n  }\n  // propsGroup.push({\n  //   name: '#generals',\n  //   title: { type: 'i18n', 'zh-CN': '通用', 'en-US': 'General' },\n  //   items: [\n  //     {\n  //       name: 'id',\n  //       title: 'ID',\n  //       setter: 'StringSetter',\n  //     },\n  //     {\n  //       name: 'key',\n  //       title: 'Key',\n  //       // todo: use Mixin\n  //       setter: 'StringSetter',\n  //     },\n  //     {\n  //       name: 'ref',\n  //       title: 'Ref',\n  //       setter: 'StringSetter',\n  //     },\n  //     {\n  //       name: '!more',\n  //       title: '更多',\n  //       setter: 'PropertiesSetter',\n  //     },\n  //   ],\n  // });\n  const stylesGroup: IPublicTypeFieldConfig[] = [];\n  const advancedGroup: IPublicTypeFieldConfig[] = [];\n  if (propsGroup) {\n    let l = propsGroup.length;\n    while (l-- > 0) {\n      const item = propsGroup[l];\n      // if (item.type === 'group' && (item.title === '高级' || item.title?.label === '高级')) {\n      //   advancedGroup = item.items || [];\n      //   propsGroup.splice(l, 1);\n      // }\n      if (\n        item.name === '__style__' ||\n        item.name === 'style' ||\n        item.name === 'containerStyle' ||\n        item.name === 'pageStyle'\n      ) {\n        propsGroup.splice(l, 1);\n        stylesGroup.push(item);\n        if (item.extraProps?.defaultCollapsed && item.name !== 'containerStyle') {\n          item.extraProps.defaultCollapsed = false;\n        }\n      }\n    }\n  }\n  const combined: IPublicTypeFieldConfig[] = [\n    {\n      title: { type: 'i18n', 'zh-CN': '属性', 'en-US': 'Props' },\n      name: '#props',\n      items: propsGroup,\n    },\n  ];\n  if (supports.className) {\n    stylesGroup.push({\n      name: 'className',\n      title: { type: 'i18n', 'zh-CN': '类名绑定', 'en-US': 'ClassName' },\n      setter: 'ClassNameSetter',\n    });\n  }\n  if (supports.style) {\n    stylesGroup.push({\n      name: 'style',\n      title: { type: 'i18n', 'zh-CN': '行内样式', 'en-US': 'Style' },\n      setter: 'StyleSetter',\n      extraProps: {\n        display: 'block',\n      },\n    });\n  }\n  if (stylesGroup.length > 0) {\n    combined.push({\n      name: '#styles',\n      title: { type: 'i18n', 'zh-CN': '样式', 'en-US': 'Styles' },\n      items: stylesGroup,\n    });\n  }\n\n  if (eventsDefinition.length > 0) {\n    combined.push({\n      name: '#events',\n      title: { type: 'i18n', 'zh-CN': '事件', 'en-US': 'Events' },\n      items: [\n        {\n          name: '__events',\n          title: { type: 'i18n', 'zh-CN': '事件设置', 'en-US': 'Events' },\n          setter: {\n            componentName: 'EventsSetter',\n            props: {\n              definition: eventsDefinition,\n            },\n          },\n          getValue(field: IPublicModelSettingField, val?: any[]) {\n            return val;\n          },\n\n          setValue(field: IPublicModelSettingField, eventData) {\n            const { eventDataList, eventList } = eventData;\n            Array.isArray(eventList) &&\n              eventList.map((item) => {\n                field.parent.clearPropValue(item.name);\n                return item;\n              });\n            Array.isArray(eventDataList) &&\n              eventDataList.map((item) => {\n                field.parent.setPropValue(item.name, {\n                  type: 'JSFunction',\n                  // 需要传下入参\n                  value: `function(){return this.${\n                    item.relatedEventName\n                  }.apply(this,Array.prototype.slice.call(arguments).concat([${\n                    item.paramStr ? item.paramStr : ''\n                  }])) }`,\n                });\n                return item;\n              });\n          },\n        },\n      ],\n    });\n  }\n\n  if (!isRoot) {\n    if (supports.condition !== false) {\n      advancedGroup.push({\n        name: getConvertedExtraKey('condition'),\n        title: { type: 'i18n', 'zh-CN': '是否渲染', 'en-US': 'Condition' },\n        defaultValue: true,\n        setter: [\n          {\n            componentName: 'BoolSetter',\n          },\n          {\n            componentName: 'VariableSetter',\n          },\n        ],\n        extraProps: {\n          display: 'block',\n        },\n      });\n    }\n    if (supports.loop !== false) {\n      advancedGroup.push({\n        name: '#loop',\n        title: { type: 'i18n', 'zh-CN': '循环', 'en-US': 'Loop' },\n        items: [\n          {\n            name: getConvertedExtraKey('loop'),\n            title: { type: 'i18n', 'zh-CN': '循环数据', 'en-US': 'Loop Data' },\n            setter: [\n              {\n                componentName: 'JsonSetter',\n                props: {\n                  label: { type: 'i18n', 'zh-CN': '编辑数据', 'en-US': 'Edit Data' },\n                  defaultValue: '[]',\n                },\n              },\n              {\n                componentName: 'VariableSetter',\n              },\n            ],\n          },\n          {\n            name: getConvertedExtraKey('loopArgs.0'),\n            title: { type: 'i18n', 'zh-CN': '迭代变量名', 'en-US': 'Loop Item' },\n            setter: {\n              componentName: 'StringSetter',\n              props: {\n                placeholder: { type: 'i18n', 'zh-CN': '默认为: item', 'en-US': 'Defaults: item' },\n              },\n            },\n          },\n          {\n            name: getConvertedExtraKey('loopArgs.1'),\n            title: { type: 'i18n', 'zh-CN': '索引变量名', 'en-US': 'Loop Index' },\n            setter: {\n              componentName: 'StringSetter',\n              props: {\n                placeholder: { type: 'i18n', 'zh-CN': '默认为: index', 'en-US': 'Defaults: index' },\n              },\n            },\n          },\n          {\n            name: 'key',\n            title: { type: 'i18n', 'zh-CN': '循环 Key', 'en-US': 'Loop Key' },\n            setter: [\n              {\n                componentName: 'StringSetter',\n              },\n              {\n                componentName: 'VariableSetter',\n              },\n            ],\n          },\n        ],\n        extraProps: {\n          display: 'accordion',\n        },\n      });\n    }\n\n    if (supports.condition !== false || supports.loop !== false) {\n      advancedGroup.push({\n        name: 'key',\n        title: {\n          label: {\n            type: 'i18n',\n            'zh-CN': '渲染唯一标识 (key)',\n            'en-US': 'Render unique identifier (key)',\n          },\n          tip: {\n            type: 'i18n',\n            'zh-CN': '搭配「条件渲染」或「循环渲染」时使用，和 react 组件中的 key 原理相同，点击查看帮助',\n            'en-US': 'Used with 「Conditional Rendering」or「Cycle Rendering」, the same principle as the key in the react component, click to view the help',\n          },\n          docUrl: 'https://www.yuque.com/lce/doc/qm75w3',\n        },\n        setter: [\n          {\n            componentName: 'StringSetter',\n          },\n          {\n            componentName: 'VariableSetter',\n          },\n        ],\n        extraProps: {\n          display: 'block',\n        },\n      });\n    }\n  }\n  if (advancedGroup.length > 0) {\n    combined.push({\n      name: '#advanced',\n      title: { type: 'i18n', 'zh-CN': '高级', 'en-US': 'Advanced' },\n      items: advancedGroup,\n    });\n  }\n\n  return {\n    ...metadata,\n    ...basicInfo,\n    configure: {\n      ...configure,\n      combined,\n    },\n  };\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/transducers/parse-func.ts",
    "content": "import { IPublicTypeTransformedComponentMetadata } from '@alilc/lowcode-types';\nimport { isPlainObject, isJSFunction, getLogger } from '@alilc/lowcode-utils';\n\nconst leadingFnRe = /^function/;\nconst leadingFnNameRe = /^\\w+\\s*\\(/;\nconst logger = getLogger({ level: 'warn', bizName: 'skeleton:transducers' });\n\n/**\n * 将函数字符串转成函数，支持几种类型\n *   类型一：() => {} / val => {}\n *   类型二：setValue() {}\n *   类型三：function() {} / function setValue() {}\n * @param str\n * @returns\n */\nfunction transformStringToFunction(str: string) {\n  if (typeof str !== 'string') return str;\n\n  let fn;\n  if (leadingFnNameRe.test(str) && !leadingFnRe.test(str)) {\n    str = `function ${str}`;\n  }\n  let fnBody = `\n    return function() {\n      const self = this;\n      try {\n        return (${str}).apply(self, arguments);\n      } catch(e) {\n        console.warn('call function which parsed by lowcode failed: ', e);\n        return e.message;\n      }\n    };\n  `;\n  try {\n    // eslint-disable-next-line no-new-func\n    fn = new Function(fnBody)();\n  } catch (e) {\n    logger.error(str);\n    logger.error(e.message);\n  }\n  return fn;\n}\n\nfunction parseJSFunc(obj: any, enableAllowedKeys = true) {\n  if (!obj) return;\n  Object.keys(obj).forEach(key => {\n    const item = obj[key];\n    if (isJSFunction(item)) {\n      obj[key] = transformStringToFunction(item.value);\n    } else if (Array.isArray(item)) {\n      item.forEach(o => parseJSFunc(o, enableAllowedKeys));\n    } else if (isPlainObject(item)) {\n      parseJSFunc(item, enableAllowedKeys);\n    }\n  });\n}\n\nexport default function (metadata: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata {\n  parseJSFunc(metadata, false);\n\n  return metadata;\n}"
  },
  {
    "path": "packages/editor-skeleton/src/transducers/parse-props.ts",
    "content": "import {\n  IPublicTypeFieldConfig,\n  IPublicTypePropConfig,\n  IPublicTypePropType,\n  IPublicTypeSetterType,\n  IPublicTypeOneOf,\n  IPublicTypeObjectOf,\n  IPublicTypeArrayOf,\n  IPublicTypeTransformedComponentMetadata,\n  IPublicTypeOneOfType,\n  ConfigureSupportEvent,\n  IPublicModelSettingField,\n} from '@alilc/lowcode-types';\n\nfunction propConfigToFieldConfig(propConfig: IPublicTypePropConfig): IPublicTypeFieldConfig {\n  const { name, description } = propConfig;\n  const title = {\n    label: {\n      type: 'i18n',\n      'en-US': name,\n      'zh-CN': description?.slice(0, 10) || name,\n    },\n    tip: description ? `${name} | ${description}` : undefined,\n  };\n  return {\n    title,\n    ...propConfig,\n    // TODO 这边直接用propConfig，将setter丢在propconfig里，需要确认是否在PropConfig扩展还是换实现\n    setter: propConfig.setter ? propConfig.setter : propTypeToSetter(propConfig.propType),\n  };\n}\n\nfunction propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType {\n  let typeName: string;\n  let isRequired: boolean | undefined = false;\n  if (typeof propType === 'string') {\n    typeName = propType;\n  } else if (typeof propType === 'object') {\n    typeName = propType.type;\n    isRequired = propType.isRequired;\n  } else {\n    typeName = 'string';\n  }\n  // TODO: use mixinSetter wrapper\n  switch (typeName) {\n    case 'string':\n      return {\n        componentName: 'StringSetter',\n        isRequired,\n        initialValue: '',\n      };\n    case 'number':\n      return {\n        componentName: 'NumberSetter',\n        isRequired,\n        initialValue: 0,\n      };\n    case 'bool':\n      return {\n        componentName: 'BoolSetter',\n        isRequired,\n        initialValue: false,\n      };\n    case 'oneOf':\n      const dataSource = ((propType as IPublicTypeOneOf).value || []).map((value, index) => {\n        const t = typeof value;\n        return {\n          label: t === 'string' || t === 'number' || t === 'boolean' ? String(value) : `value ${index}`,\n          value,\n        };\n      });\n      const componentName = dataSource.length >= 4 ? 'SelectSetter' : 'RadioGroupSetter';\n      return {\n        componentName,\n        props: { dataSource, options: dataSource },\n        isRequired,\n        initialValue: dataSource[0] ? dataSource[0].value : null,\n      };\n\n    case 'element':\n    case 'node': // TODO: use Mixin\n      return {\n        // slotSetter\n        componentName: 'SlotSetter',\n        props: {\n          mode: typeName,\n        },\n        isRequired,\n        initialValue: {\n          type: 'JSSlot',\n          value: [],\n        },\n      };\n    case 'shape':\n    case 'exact':\n      const items = ((propType as any).value || []).map((item: any) => propConfigToFieldConfig(item));\n      return {\n        componentName: 'ObjectSetter',\n        props: {\n          config: {\n            items,\n            extraSetter: typeName === 'shape' ? propTypeToSetter('any') : null,\n          },\n        },\n        isRequired,\n        initialValue: (field: IPublicModelSettingField) => {\n          const data: any = {};\n          items.forEach((item: any) => {\n            let initial = item.defaultValue;\n            if (initial == null && item.setter && typeof item.setter === 'object') {\n              initial = (item.setter as any).initialValue;\n            }\n            data[item.name] = initial ? (typeof initial === 'function' ? initial(field) : initial) : null;\n          });\n          return data;\n        },\n      };\n    case 'object':\n    case 'objectOf':\n      return {\n        componentName: 'ObjectSetter',\n        props: {\n          config: {\n            extraSetter: propTypeToSetter(typeName === 'objectOf' ? (propType as IPublicTypeObjectOf).value : 'any'),\n          },\n        },\n        isRequired,\n        initialValue: {},\n      };\n    case 'array':\n    case 'arrayOf':\n      return {\n        componentName: 'ArraySetter',\n        props: {\n          itemSetter: propTypeToSetter(typeName === 'arrayOf' ? (propType as IPublicTypeArrayOf).value : 'any'),\n        },\n        isRequired,\n        initialValue: [],\n      };\n    case 'func':\n      return {\n        componentName: 'FunctionSetter',\n        isRequired,\n      };\n    case 'color':\n      return {\n        componentName: 'ColorSetter',\n        isRequired,\n      };\n    case 'oneOfType':\n      return {\n        componentName: 'MixedSetter',\n        props: {\n          // TODO:\n          setters: (propType as IPublicTypeOneOfType).value.map((item) => propTypeToSetter(item)),\n        },\n        isRequired,\n      };\n    default:\n      // do nothing\n  }\n  return {\n    componentName: 'MixedSetter',\n    isRequired,\n    props: {},\n  };\n}\n\nconst EVENT_RE = /^on|after|before[A-Z][\\w]*$/;\n\nexport default function (metadata: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata {\n  const { configure = {} } = metadata;\n  // TODO types后续补充\n  let extendsProps: any = null;\n  if (configure.props) {\n    if (Array.isArray(configure.props)) {\n      return metadata;\n    }\n    const { isExtends, override = [] } = configure.props;\n    // 不开启继承时，直接返回configure配置\n    if (!isExtends) {\n      return {\n        ...metadata,\n        configure: {\n          ...configure,\n          props: [...override],\n        },\n      };\n    }\n\n    extendsProps = {};\n    // 开启继承后，缓存重写内容的配置\n    override.forEach((prop: any) => {\n      extendsProps[prop.name] = prop;\n    });\n  }\n\n  if (!metadata.props) {\n    return {\n      ...metadata,\n      configure: {\n        ...configure,\n        props: [],\n      },\n    };\n  }\n  const { component = {}, supports = {} } = configure;\n  const supportedEvents: ConfigureSupportEvent[] | null = supports.events ? null : [];\n  const props: IPublicTypeFieldConfig[] = [];\n\n  metadata.props.forEach((prop) => {\n    const { name, propType, description } = prop;\n    if (\n      name === 'children' &&\n      (component.isContainer || propType === 'node' || propType === 'element' || propType === 'any')\n    ) {\n      if (component.isContainer !== false) {\n        component.isContainer = true;\n        props.push(propConfigToFieldConfig(prop));\n        return;\n      }\n    }\n\n    if (EVENT_RE.test(name) && (propType === 'func' || propType === 'any')) {\n      if (supportedEvents) {\n        supportedEvents.push({\n          name,\n          description,\n        });\n        supports.events = supportedEvents;\n      }\n      return;\n    }\n\n    if (name === 'className' && (propType === 'string' || propType === 'any')) {\n      if (supports.className == null) {\n        supports.className = true;\n      }\n      return;\n    }\n\n    if (name === 'style' && (propType === 'object' || propType === 'any')) {\n      if (supports.style == null) {\n        supports.style = true;\n      }\n      return;\n    }\n\n    // 存在覆盖配置时\n    if (extendsProps) {\n      if (name in extendsProps) {\n        prop = extendsProps[name];\n      }\n    }\n\n    props.push(propConfigToFieldConfig(prop));\n  });\n\n  return {\n    ...metadata,\n    configure: {\n      ...configure,\n      props,\n      supports,\n      component,\n    },\n  };\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/types.ts",
    "content": "import { ReactElement, ComponentType } from 'react';\nimport {\n  IPublicTypeTitleContent,\n  IPublicTypeWidgetConfigArea,\n  IPublicTypeWidgetBaseConfig,\n  IPublicTypePanelDockProps,\n  IPublicTypePanelConfigProps,\n  IPublicTypePanelConfig,\n} from '@alilc/lowcode-types';\nimport { IWidget } from './widget/widget';\n\nexport interface WidgetConfig extends IPublicTypeWidgetBaseConfig {\n  type: 'Widget';\n  props?: {\n    align?: 'left' | 'right' | 'bottom' | 'center' | 'top';\n    onInit?: (widget: IWidget) => void;\n    title?: IPublicTypeTitleContent | null;\n  };\n  content?: string | ReactElement | ComponentType<any>; // children\n}\n\nexport function isWidgetConfig(obj: any): obj is WidgetConfig {\n  return obj && obj.type === 'Widget';\n}\n\nexport interface DockProps extends IPublicTypePanelDockProps {\n}\n\nexport interface DividerConfig extends IPublicTypeWidgetBaseConfig {\n  type: 'Divider';\n  props?: {\n    align?: 'left' | 'right' | 'center';\n  };\n}\n\nexport function isDividerConfig(obj: any): obj is DividerConfig {\n  return obj && obj.type === 'Divider';\n}\n\nexport interface IDockBaseConfig extends IPublicTypeWidgetBaseConfig {\n  props?: DockProps & {\n    align?: 'left' | 'right' | 'bottom' | 'center' | 'top';\n    onInit?: (widget: IWidget) => void;\n  };\n}\n\nexport interface DockConfig extends IDockBaseConfig {\n  type: 'Dock';\n  content?: string | ReactElement | ComponentType<any>;\n}\n\nexport function isDockConfig(obj: any): obj is DockConfig {\n  return obj && /Dock$/.test(obj.type);\n}\n\n// 按钮弹窗扩展\nexport interface DialogDockConfig extends IDockBaseConfig {\n  type: 'DialogDock';\n  dialogProps?: {\n    [key: string]: any;\n    title?: IPublicTypeTitleContent;\n  };\n}\n\nexport function isDialogDockConfig(obj: any): obj is DialogDockConfig {\n  return obj && obj.type === 'DialogDock';\n}\n\nexport function isPanelConfig(obj: any): obj is IPublicTypePanelConfig {\n  return obj && obj.type === 'Panel';\n}\n\nexport interface PanelDockConfig extends IDockBaseConfig {\n  type: 'PanelDock';\n  panelName?: string;\n  panelProps?: IPublicTypePanelConfigProps & {\n    area?: IPublicTypeWidgetConfigArea;\n  };\n  content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; // content for pane\n}\n\nexport function isPanelDockConfig(obj: any): obj is PanelDockConfig {\n  return obj && obj.type === 'PanelDock';\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/widget/dialog-dock.ts",
    "content": ""
  },
  {
    "path": "packages/editor-skeleton/src/widget/dock.ts",
    "content": "import { ReactNode, createElement } from 'react';\nimport { makeObservable, obx } from '@alilc/lowcode-editor-core';\nimport { uniqueId, createContent } from '@alilc/lowcode-utils';\nimport { getEvent } from '@alilc/lowcode-shell';\nimport { DockConfig } from '../types';\nimport { ISkeleton } from '../skeleton';\nimport { DockView, WidgetView } from '../components/widget-views';\nimport { IWidget } from './widget';\n\n/**\n * 带图标（主要）/标题（次要）的扩展\n */\nexport class Dock implements IWidget {\n  readonly isWidget = true;\n\n  readonly id = uniqueId('dock');\n\n  readonly name: string;\n\n  readonly align?: string;\n\n  @obx.ref private _visible = true;\n\n  get visible(): boolean {\n    return this._visible;\n  }\n\n  @obx.ref private _disabled = false;\n\n  get content(): ReactNode {\n    return createElement(WidgetView, {\n      widget: this,\n      key: this.id,\n    });\n  }\n\n  private inited = false;\n\n  private _body: ReactNode;\n\n  get body() {\n    if (this.inited) {\n      return this._body;\n    }\n\n    const { props, content, contentProps } = this.config;\n\n    if (content) {\n      this._body = createContent(content, {\n        ...contentProps,\n        config: this.config,\n        editor: getEvent(this.skeleton.editor),\n      });\n    } else {\n      this._body = createElement(DockView, props);\n    }\n    this.inited = true;\n\n    return this._body;\n  }\n\n  constructor(readonly skeleton: ISkeleton, readonly config: DockConfig) {\n    makeObservable(this);\n    const { props = {}, name } = config;\n    this.name = name;\n    this.align = props.align;\n    if (props.onInit) {\n      props.onInit.call(this, this);\n    }\n  }\n\n  setVisible(flag: boolean) {\n    if (flag === this._visible) {\n      return;\n    }\n    if (flag) {\n      this._visible = true;\n    } else if (this.inited) {\n      this._visible = false;\n    }\n  }\n\n  private setDisabled(flag: boolean) {\n    if (this._disabled === flag) return;\n    this._disabled = flag;\n  }\n\n  disable() {\n    this.setDisabled(true);\n  }\n\n  enable() {\n    this.setDisabled(false);\n  }\n\n  get disabled(): boolean {\n    return this._disabled;\n  }\n\n  getContent() {\n    return this.content;\n  }\n\n  getName() {\n    return this.name;\n  }\n\n  hide() {\n    this.setVisible(false);\n  }\n\n  show() {\n    this.setVisible(true);\n  }\n\n  toggle() {\n    this.setVisible(!this._visible);\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/widget/index.ts",
    "content": "export * from './widget-container';\nexport * from './panel';\nexport * from './panel-dock';\nexport * from './dock';\nexport * from './widget';\nexport * from './stage';"
  },
  {
    "path": "packages/editor-skeleton/src/widget/panel-dock.ts",
    "content": "import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';\nimport { uniqueId } from '@alilc/lowcode-utils';\nimport { createElement, ReactNode, ReactInstance } from 'react';\nimport { ISkeleton } from '../skeleton';\nimport { PanelDockConfig } from '../types';\nimport { Panel } from './panel';\nimport { PanelDockView, WidgetView } from '../components/widget-views';\nimport { IWidget } from './widget';\nimport { composeTitle } from './utils';\nimport { findDOMNode } from 'react-dom';\n\nexport class PanelDock implements IWidget {\n  readonly isWidget = true;\n\n  readonly isPanelDock = true;\n\n  readonly id: string;\n\n  readonly name: string;\n\n  readonly align?: 'left' | 'right' | 'bottom' | 'center' | 'top' | undefined;\n\n  private inited = false;\n\n  private _body: ReactNode;\n\n  get body() {\n    if (this.inited) {\n      return this._body;\n    }\n    this.inited = true;\n    const { props } = this.config;\n\n    this._body = createElement(PanelDockView, {\n      ...props,\n      dock: this,\n    });\n\n    return this._body;\n  }\n\n  private _shell: ReactInstance | null = null;\n\n  get content(): ReactNode {\n    return createElement(WidgetView, {\n      widget: this,\n      ref: (ref) => {\n        this._shell = ref;\n      },\n      key: this.id,\n    });\n  }\n\n  @obx.ref private _visible = true;\n\n  get visible() {\n    return this._visible;\n  }\n\n  @computed get actived(): boolean {\n    return this.panel?.visible || false;\n  }\n\n  readonly panelName: string;\n\n  private _panel?: Panel;\n\n  @obx.ref private _disabled = false;\n\n  @computed get panel() {\n    return this._panel || this.skeleton.getPanel(this.panelName);\n  }\n\n  constructor(readonly skeleton: ISkeleton, readonly config: PanelDockConfig) {\n    makeObservable(this);\n    const { content, contentProps, panelProps, name, props } = config;\n    this.name = name;\n    this.id = uniqueId(`dock:${name}$`);\n    this.panelName = config.panelName || name;\n    this.align = props?.align;\n    if (content) {\n      const _panelProps = { ...panelProps };\n      if (_panelProps.title == null && props) {\n        _panelProps.title = composeTitle(props.title, undefined, props.description, true, true);\n      }\n      this._panel = this.skeleton.add({\n        type: 'Panel',\n        name: this.panelName,\n        props: _panelProps,\n        contentProps,\n        content,\n        area: panelProps?.area,\n      }) as Panel;\n    }\n    if (props?.onInit) {\n      props.onInit.call(this, this);\n    }\n  }\n\n  getDOMNode() {\n    // eslint-disable-next-line react/no-find-dom-node\n    return this._shell ? findDOMNode(this._shell) : null;\n  }\n\n  setVisible(flag: boolean) {\n    if (flag === this._visible) {\n      return;\n    }\n    if (flag) {\n      this._visible = true;\n    } else if (this.inited) {\n      this._visible = false;\n    }\n  }\n\n  hide() {\n    this.setVisible(false);\n  }\n\n  show() {\n    this.setVisible(true);\n  }\n\n  toggle() {\n    this.setVisible(!this._visible);\n  }\n\n  private setDisabled(flag: boolean) {\n    if (this._disabled === flag) return;\n    this._disabled = flag;\n  }\n\n  disable() {\n    this.setDisabled(true);\n  }\n\n  enable() {\n    this.setDisabled(false);\n  }\n\n  get disabled(): boolean {\n    return this._disabled;\n  }\n\n  togglePanel() {\n    this.panel?.toggle();\n  }\n\n  getName() {\n    return this.name;\n  }\n\n  getContent() {\n    return this.content;\n  }\n\n  hidePanel() {\n    this.panel?.setActive(false);\n  }\n\n  showPanel() {\n    this.panel?.setActive(true);\n  }\n\n  /**\n   * @deprecated\n   */\n  onActiveChange(func: () => any) {\n    return this.panel?.onActiveChange(func);\n  }\n}\n\nexport function isPanelDock(obj: any): obj is PanelDock {\n  return obj && obj.isPanelDock;\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/widget/panel.ts",
    "content": "import { createElement, ReactNode } from 'react';\nimport { obx, computed, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';\nimport { uniqueId, createContent } from '@alilc/lowcode-utils';\nimport { IPublicTypeHelpTipConfig, IPublicTypePanelConfig, IPublicTypeTitleContent } from '@alilc/lowcode-types';\nimport { WidgetContainer } from './widget-container';\nimport { getEvent } from '@alilc/lowcode-shell';\nimport { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views';\nimport { ISkeleton } from '../skeleton';\nimport { composeTitle } from './utils';\nimport { IWidget } from './widget';\nimport { isPanelDock, PanelDock } from './panel-dock';\n\nexport class Panel implements IWidget {\n  readonly isWidget = true;\n\n  readonly name: string;\n\n  readonly id: string;\n\n  @obx.ref inited = false;\n\n  @obx.ref private _actived = false;\n\n  private emitter: IEventBus = createModuleEventBus('Panel');\n\n  @computed get actived(): boolean {\n    return this._actived;\n  }\n\n  @computed get visible(): boolean {\n    if (!this.parent || this.parent.visible) {\n      const { props } = this.config;\n      if (props?.condition) {\n        return props.condition(this);\n      }\n      return this._actived;\n    }\n    return false;\n  }\n\n  readonly isPanel = true;\n\n  get body() {\n    if (this.container) {\n      return createElement(TabsPanelView, {\n        container: this.container,\n        shouldHideSingleTab: true,\n      });\n    }\n\n    const { content, contentProps } = this.config;\n    return createContent(content, {\n      ...contentProps,\n      editor: getEvent(this.skeleton.editor),\n      config: this.config,\n      panel: this,\n      pane: this,\n    });\n  }\n\n  get content(): ReactNode {\n    const area = this.config?.area || this.parent?.name;\n    if (this.plain) {\n      return createElement(PanelView, {\n        panel: this,\n        key: this.id,\n        area,\n      });\n    }\n    return createElement(TitledPanelView, { panel: this, key: this.id, area });\n  }\n\n  readonly title: IPublicTypeTitleContent;\n\n  readonly help?: IPublicTypeHelpTipConfig;\n\n  private plain = false;\n\n  private container?: WidgetContainer<Panel, IPublicTypePanelConfig>;\n\n  @obx.ref public parent?: WidgetContainer;\n\n  constructor(readonly skeleton: ISkeleton, readonly config: IPublicTypePanelConfig) {\n    makeObservable(this);\n    const { name, content, props = {} } = config;\n    const { hideTitleBar, title, icon, description, help } = props;\n    this.name = name;\n    this.id = uniqueId(`pane:${name}$`);\n    this.title = composeTitle(title || name, icon, description);\n    this.plain = hideTitleBar || !title;\n    this.help = help;\n    if (Array.isArray(content)) {\n      this.container = this.skeleton.createContainer(\n        name,\n        (item) => {\n          if (isPanel(item)) {\n            return item;\n          }\n          return this.skeleton.createPanel(item);\n        },\n        true,\n        () => this.visible,\n        true,\n      );\n      content.forEach((item) => this.add(item));\n    }\n    if (props.onInit) {\n      props.onInit.call(this, this);\n    }\n\n    if (typeof content !== 'string' && content && content.onInit) {\n      content.onInit.call(this, this);\n    }\n    // todo: process shortcut\n  }\n\n  setParent(parent: WidgetContainer) {\n    if (parent === this.parent) {\n      return;\n    }\n    if (this.parent) {\n      this.parent.remove(this);\n    }\n    this.parent = parent;\n  }\n\n  add(item: Panel | IPublicTypePanelConfig) {\n    return this.container?.add(item);\n  }\n\n  getPane(name: string): Panel | null {\n    return this.container?.get(name) || null;\n  }\n\n  remove(item: Panel | string) {\n    return this.container?.remove(item);\n  }\n\n  active(item?: Panel | string | null) {\n    if (item) {\n      this.container?.active(item);\n    } else {\n      this.setActive(true);\n    }\n  }\n\n  getName() {\n    return this.name;\n  }\n\n  getContent() {\n    return this.content;\n  }\n\n  /**\n   * check is current panel is in float area or not\n   *\n   * @returns {boolean}\n   * @memberof Panel\n   */\n  isChildOfFloatArea(): boolean {\n    return this.parent?.name === 'leftFloatArea';\n  }\n\n  /**\n   * check is current panel is in fixed area or not\n   *\n   * @returns {boolean}\n   * @memberof Panel\n   */\n  isChildOfFixedArea(): boolean {\n    return this.parent?.name === 'leftFixedArea';\n  }\n\n  setActive(flag: boolean) {\n    if (flag === this._actived) {\n      // TODO: 如果移动到另外一个 container，会有问题\n      return;\n    }\n    if (flag) {\n      // 对于 Area 的直接 Child，要专门处理 Float & Fixed 分组切换, 其他情况不需要\n      if (this.isChildOfFloatArea()) {\n        this.skeleton.leftFixedArea.container.unactiveAll();\n      } else if (this.isChildOfFixedArea()) {\n        this.skeleton.leftFloatArea.container.unactiveAll();\n      }\n      this._actived = true;\n      this.parent?.active(this);\n      if (!this.inited) {\n        this.inited = true;\n      }\n      this.emitter.emit('activechange', true);\n    } else if (this.inited) {\n      if (this.parent?.name && this.name.startsWith(this.parent.name)) {\n        this.inited = false;\n      }\n      this._actived = false;\n      this.parent?.unactive(this);\n      this.emitter.emit('activechange', false);\n    }\n  }\n\n  toggle() {\n    this.setActive(!this._actived);\n  }\n\n  hide() {\n    this.setActive(false);\n  }\n\n  disable() {}\n\n  enable(): void {}\n\n  show() {\n    this.setActive(true);\n  }\n\n  getAssocDocks(): PanelDock[] {\n    return this.skeleton.widgets.filter(item => {\n      return isPanelDock(item) && item.panelName === this.name;\n    }) as any;\n  }\n\n  /**\n   * @deprecated\n   */\n  getSupportedPositions() {\n    return ['default'];\n  }\n\n  /**\n   * @deprecated\n   */\n  getCurrentPosition() {\n    return 'default';\n  }\n\n  /**\n   * @deprecated\n   */\n  setPosition(/* position: string */) {\n    // noop\n  }\n\n  /**\n   * @deprecated\n   */\n  onActiveChange(fn: (flag: boolean) => void): () => void {\n    this.emitter.on('activechange', fn);\n    return () => {\n      this.emitter.removeListener('activechange', fn);\n    };\n  }\n}\n\nexport function isPanel(obj: any): obj is Panel {\n  return obj && obj.isPanel;\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/widget/stage.ts",
    "content": "// import { uniqueId } from '@alilc/lowcode-utils';\nimport { Widget } from './widget';\nimport { ISkeleton } from '../skeleton';\nimport { WidgetConfig } from '../types';\n\nexport interface StageConfig extends WidgetConfig {\n  isRoot?: boolean;\n}\n\nexport class Stage extends Widget {\n  readonly isRoot: boolean;\n\n  private previous?: Stage;\n\n  private refer?: {\n    stage?: Stage;\n    direction?: 'right' | 'left';\n  };\n\n  constructor(skeleton: ISkeleton, config: StageConfig) {\n    super(skeleton, config);\n    this.isRoot = config.isRoot || false;\n  }\n\n  setPrevious(stage: Stage) {\n    this.previous = stage;\n  }\n\n  getPrevious() {\n    return this.previous;\n  }\n\n  hasBack(): boolean {\n    return !!(this.previous && !this.isRoot);\n  }\n\n  setRefer(stage: Stage, direction: 'right' | 'left') {\n    this.refer = { stage, direction };\n  }\n\n  setReferRight(stage: Stage) {\n    this.setRefer(stage, 'right');\n  }\n\n  setReferLeft(stage: Stage) {\n    this.setRefer(stage, 'left');\n  }\n\n  getRefer() {\n    const { refer } = this;\n    this.refer = undefined;\n    return refer;\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/widget/utils.ts",
    "content": "import { IPublicTypeIconType, IPublicTypeTitleContent, TipContent } from '@alilc/lowcode-types';\nimport { isI18nData, isTitleConfig } from '@alilc/lowcode-utils';\nimport { isValidElement } from 'react';\n\nexport function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicTypeIconType, tip?: TipContent, tipAsTitle?: boolean, noIcon?: boolean) {\n  let _title: IPublicTypeTitleContent | undefined;\n  if (!title) {\n    _title = {};\n    if (!icon || tipAsTitle) {\n      _title = {\n        label: tip,\n      };\n      tip = undefined;\n    }\n  } else {\n    _title = title;\n  }\n\n  if (icon || tip) {\n    if (typeof _title !== 'object' || isValidElement(_title) || isI18nData(_title)) {\n      if (isValidElement(_title)) {\n        if (_title.type === 'svg' || _title.type.getIcon) {\n          if (!icon) {\n            icon = _title;\n          }\n          if (tipAsTitle) {\n            _title = tip;\n            tip = null;\n          } else {\n            _title = undefined;\n          }\n        }\n      }\n      _title = {\n        label: _title,\n        icon,\n        tip,\n      };\n    } else {\n      _title = {\n        ..._title,\n        icon,\n        tip,\n      };\n    }\n  }\n  if (isTitleConfig(_title) && noIcon) {\n    if (!isValidElement(_title)) {\n      _title.icon = undefined;\n    }\n  }\n  return _title;\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/widget/widget-container.ts",
    "content": "import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';\nimport { hasOwnProperty } from '@alilc/lowcode-utils';\nimport { isPanel } from './panel';\n\nexport interface WidgetItem {\n  name: string;\n}\n\nexport interface Activeable {\n  setActive(flag: boolean): void;\n}\n\nfunction isActiveable(obj: any): obj is Activeable {\n  return obj && obj.setActive;\n}\n\nexport class WidgetContainer<T extends WidgetItem = any, G extends WidgetItem = any> {\n  @obx.shallow items: T[] = [];\n\n  private maps: { [name: string]: T } = {};\n\n  @obx.ref private _current: T & Activeable | null = null;\n\n  get current() {\n    return this._current;\n  }\n\n  // eslint-disable-next-line no-useless-constructor\n  constructor(\n    readonly name: string,\n    private handle: (item: T | G) => T,\n    private exclusive: boolean = false,\n    private checkVisible: () => boolean = () => true,\n    private defaultSetCurrent: boolean = false,\n  ) {\n    makeObservable(this);\n  }\n\n  @computed get visible() {\n    return this.checkVisible();\n  }\n\n  active(nameOrItem?: T | string | null) {\n    let item: any = nameOrItem;\n    if (nameOrItem && typeof nameOrItem === 'string') {\n      item = this.get(nameOrItem);\n    }\n    if (!isActiveable(item)) {\n      item = null;\n    }\n\n    if (this.exclusive) {\n      if (this._current === item) {\n        return;\n      }\n      if (this._current) {\n        this._current.setActive(false);\n      }\n      this._current = item;\n    }\n\n    if (item) {\n      item.setActive(true);\n    }\n  }\n\n  unactive(nameOrItem?: T | string | null) {\n    let item: any = nameOrItem;\n    if (nameOrItem && typeof nameOrItem === 'string') {\n      item = this.get(nameOrItem);\n    }\n    if (!isActiveable(item)) {\n      item = null;\n    }\n    if (this._current === item) {\n      this._current = null;\n    }\n    if (item) {\n      item.setActive(false);\n    }\n  }\n\n  unactiveAll() {\n    Object.keys(this.maps).forEach((name) => this.unactive(name));\n  }\n\n  add(item: T | G): T {\n    item = this.handle(item);\n    const origin = this.get(item.name);\n    if (origin === item) {\n      return origin;\n    }\n    const i = origin ? this.items.indexOf(origin) : -1;\n    if (i > -1) {\n      this.items[i] = item;\n    } else {\n      this.items.push(item);\n    }\n    this.maps[item.name] = item;\n    if (isPanel(item)) {\n      item.setParent(this);\n    }\n    if (this.defaultSetCurrent) {\n      const shouldHiddenWhenInit = (item as any).config?.props?.hiddenWhenInit;\n      if (!this._current && !shouldHiddenWhenInit) {\n        this.active(item);\n      }\n    }\n    return item;\n  }\n\n  get(name: string): T | null {\n    return this.maps[name] || null;\n  }\n\n  getAt(index: number): T | null {\n    return this.items[index] || null;\n  }\n\n  has(name: string): boolean {\n    return hasOwnProperty(this.maps, name);\n  }\n\n  indexOf(item: T): number {\n    return this.items.indexOf(item);\n  }\n\n  /**\n   * return indexOf the deletion\n   */\n  remove(item: string | T): number {\n    const thing = typeof item === 'string' ? this.get(item) : item;\n    if (!thing) {\n      return -1;\n    }\n    const i = this.items.indexOf(thing);\n    if (i > -1) {\n      this.items.splice(i, 1);\n    }\n    delete this.maps[thing.name];\n    if (thing === this.current) {\n      this._current = null;\n    }\n    return i;\n  }\n}\n"
  },
  {
    "path": "packages/editor-skeleton/src/widget/widget.ts",
    "content": "import { ReactNode, createElement } from 'react';\nimport { makeObservable, obx } from '@alilc/lowcode-editor-core';\nimport { createContent, uniqueId } from '@alilc/lowcode-utils';\nimport { getEvent } from '@alilc/lowcode-shell';\nimport { WidgetConfig } from '../types';\nimport { ISkeleton } from '../skeleton';\nimport { WidgetView } from '../components/widget-views';\nimport { IPublicTypeTitleContent, IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types';\n\nexport interface IWidget {\n  readonly name: string;\n  readonly content: ReactNode;\n  readonly align?: string;\n  readonly isWidget: true;\n  readonly visible: boolean;\n  readonly disabled?: boolean;\n  readonly body: ReactNode;\n  readonly skeleton: ISkeleton;\n  readonly config: IPublicTypeWidgetBaseConfig;\n\n  getName(): string;\n  getContent(): any;\n  show(): void;\n  hide(): void;\n  toggle(): void;\n  enable?(): void;\n  disable?(): void;\n}\n\nexport class Widget implements IWidget {\n  readonly isWidget = true;\n\n  readonly id = uniqueId('widget');\n\n  readonly name: string;\n\n  readonly align?: string;\n\n  @obx.ref private _visible = true;\n\n  get visible(): boolean {\n    return this._visible;\n  }\n\n  @obx.ref inited = false;\n\n  @obx.ref private _disabled = false;\n\n  private _body: ReactNode;\n\n  get body() {\n    if (this.inited) {\n      return this._body;\n    }\n    this.inited = true;\n    const { content, contentProps } = this.config;\n    this._body = createContent(content, {\n      ...contentProps,\n      config: this.config,\n      editor: getEvent(this.skeleton.editor),\n    });\n    return this._body;\n  }\n\n  get content(): ReactNode {\n    return createElement(WidgetView, {\n      widget: this,\n      key: this.id,\n    });\n  }\n\n  readonly title: IPublicTypeTitleContent;\n\n  constructor(readonly skeleton: ISkeleton, readonly config: WidgetConfig) {\n    makeObservable(this);\n    const { props = {}, name } = config;\n    this.name = name;\n    this.align = props.align;\n    this.title = props.title || name;\n    if (props.onInit) {\n      props.onInit.call(this, this);\n    }\n  }\n\n  getId() {\n    return this.id;\n  }\n\n  getName() {\n    return this.name;\n  }\n\n  getContent() {\n    return this.content;\n  }\n\n  hide() {\n    this.setVisible(false);\n  }\n\n  show() {\n    this.setVisible(true);\n  }\n\n  setVisible(flag: boolean) {\n    if (flag === this._visible) {\n      return;\n    }\n    if (flag) {\n      this._visible = true;\n    } else if (this.inited) {\n      this._visible = false;\n    }\n  }\n\n  toggle() {\n    this.setVisible(!this._visible);\n  }\n\n  private setDisabled(flag: boolean) {\n    if (this._disabled === flag) return;\n    this._disabled = flag;\n  }\n\n  disable() {\n    this.setDisabled(true);\n  }\n\n  enable() {\n    this.setDisabled(false);\n  }\n\n  get disabled(): boolean {\n    return this._disabled;\n  }\n}\n\nexport function isWidget(obj: any): obj is IWidget {\n  return obj && obj.isWidget;\n}\n"
  },
  {
    "path": "packages/editor-skeleton/tests/widget/utils.test.ts",
    "content": "import { composeTitle } from '../../src/widget/utils';\nimport * as React from 'react';\n\nconst label = React.createElement('div');\n\ndescribe('composeTitle 测试', () => {\n  it('基础能力测试', () => {\n    expect(composeTitle(undefined)).toEqual({\n      label: undefined,\n    });\n\n    expect(composeTitle(undefined, undefined, 'tips', true, true)).toEqual({\n      icon: undefined,\n      label: 'tips',\n    });\n\n    expect(composeTitle(undefined, undefined, label, true, true)).toEqual({\n      icon: undefined,\n      label,\n    });\n\n    expect(composeTitle({\n      icon: undefined,\n      label,\n    }, undefined, '')).toEqual({\n      icon: undefined,\n      label,\n    });\n\n    expect(composeTitle('settingsPane')).toEqual('settingsPane');\n\n    expect(composeTitle(label, undefined, '物料面板', true, true)).toEqual({\n      icon: undefined,\n      label,\n      tip: '物料面板',\n    });\n\n    expect(composeTitle(label, undefined, label, true, true)).toEqual({\n      icon: undefined,\n      label,\n      tip: label,\n    });\n\n    expect(composeTitle({\n      label: \"物料面板\",\n      icon: undefined,\n      tip: null,\n    })).toEqual({\n      label: \"物料面板\",\n      icon: undefined,\n      tip: null,\n    })\n  });\n})"
  },
  {
    "path": "packages/editor-skeleton/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "packages/engine/README-zh_CN.md",
    "content": "<p align=\"center\">\n  <a href=\"https://lowcode-engine.cn\">\n    <img width=\"200\" src=\"https://img.alicdn.com/imgextra/i3/O1CN01i8K9cD1d0HU7TjDtv_!!6000000003673-2-tps-500-591.png\">\n  </a>\n</p>\n\n<h1 align=\"center\">LowCodeEngine</h1>\n\n<div align=\"center\">\n\n一套面向扩展设计的企业级低代码技术体系\n\n[![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]\n\n[![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]\n\n[![codecov][codecov-image-url]][codecov-url] [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/lowcode-workspace/awesome-lowcode-engine)\n\n[![](https://img.shields.io/badge/LowCodeEngine-%E6%9F%A5%E7%9C%8B%E8%B4%A1%E7%8C%AE%E6%8E%92%E8%A1%8C%E6%A6%9C-orange)](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=lowcode-engine)\n\n[npm-image]: https://img.shields.io/npm/v/@alilc/lowcode-engine.svg?style=flat-square\n[npm-url]: http://npmjs.org/package/@alilc/lowcode-engine\n\n[download-image]: https://img.shields.io/npm/dm/@alilc/lowcode-engine.svg?style=flat-square\n[download-url]: https://npmjs.org/package/@alilc/lowcode-engine\n[help-wanted-image]: https://flat.badgen.net/github/label-issues/alibaba/lowcode-engine/help%20wanted/open\n[help-wanted-url]: https://github.com/alibaba/lowcode-engine/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22\n\n[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square\n[issues-helper-url]: https://github.com/actions-cool/issues-helper\n\n[codecov-image-url]: https://codecov.io/gh/alibaba/lowcode-engine/branch/main/graph/badge.svg\n[codecov-url]: https://codecov.io/gh/alibaba/lowcode-engine\n\n</div>\n\n[![](https://img.alicdn.com/imgextra/i2/O1CN01UhoS7C1sNNhySvfWi_!!6000000005754-2-tps-2878-1588.png)](https://lowcode-engine.cn)\n\n简体中文 | [English](./README.md)\n\n## ✨ 特性\n\n- 🌈 提炼自企业级低代码平台的面向扩展设计的内核引擎，奉行最小内核，最强生态的设计理念\n- 📦 开箱即用的高质量生态元素，包括 物料体系、设置器、插件 等\n- ⚙️ 完善的工具链，支持 物料体系、设置器、插件 等生态元素的全链路研发周期\n- 🔌 强大的扩展能力，已支撑 100+ 个各种类型低代码平台\n- 🛡 使用 TypeScript 开发，提供完整的类型定义文件\n\n## 🎯 兼容环境\n\n- 现代浏览器（Chrome >= 80, Edge >= 80, last 2 safari versions, last 2 firefox versions）\n\n## 📚 引擎协议\n\n引擎完整实现了《低代码引擎搭建协议规范》和《低代码引擎物料协议规范》，协议栈是低代码领域的物料能否流通的关键部分。\n\n![image](https://img.alicdn.com/imgextra/i3/O1CN01IisBcy1dNBIg16QFM_!!6000000003723-2-tps-1916-1070.png)\n\n## 🌰 使用示例\n\n```bash\nnpm install @alilc/lowcode-engine --save-dev\n```\n\n> **TIPS：仅支持 cdn 方式引入，npm 包用于提供 typings 等代码提示能力**\n\n```ts\nimport { init, skeleton } from '@alilc/lowcode-engine';\n\nskeleton.add({\n  area: 'topArea',\n  type: 'Widget',\n  name: 'logo',\n  content: YourFantasticLogo,\n  contentProps: {\n    logo:\n      'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png',\n    href: '/',\n  },\n  props: {\n    align: 'left',\n    width: 100,\n  },\n});\n\ninit(document.getElementById('lce'));\n```\n\n### 工程化配置：\n```json\n{\n  \"externals\": {\n    \"@alilc/lowcode-engine\": \"var window.AliLowCodeEngine\",\n    \"@alilc/lowcode-engine-ext\": \"var window.AliLowCodeEngineExt\"\n  }\n}\n```\n\n### cdn 可选方式：\n#### 方式 1（推荐）：alifd cdn\n```html\nhttps://alifd.alicdn.com/npm/@alilc/lowcode-engine@1.0.18/dist/js/engine-core.js\n\nhttps://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### 方式 2（推荐）：uipaas cdn\n```html\nhttps://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js\n\nhttps://uipaas-assets.com/prod/npm/@alilc/lowcode-react-simulator-renderer/1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### 方式 3：unpkg\n```html\nhttps://unpkg.com/@alilc/lowcode-engine@1.0.18/dist/js/engine-core.js\n\nhttps://unpkg.com/@alilc/lowcode-react-simulator-renderer@1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### 方式 4：jsdelivr\n```html\nhttps://cdn.jsdelivr.net/npm/@alilc/lowcode-engine@1.0.18/dist/js/engine-core.js\n\nhttps://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### 方式 5：使用自有 cdn\n将源码中 packages/engine/dist 和 packages/react-simulator-renderer/dist 下的文件传至你的 cdn 提供商\n\n## 🔗 相关链接\n\n- [官网首页](https://lowcode-engine.cn/)\n- [Demo 马上玩](https://lowcode-engine.cn/demo) | [引擎 Demo 仓库](https://github.com/alibaba/lowcode-demo)\n- [官方物料](https://github.com/alibaba/lowcode-materials)\n- [官方设置器（setter）](https://github.com/alibaba/lowcode-engine-ext)\n- [官方插件（plugin）](https://github.com/alibaba/lowcode-plugins)\n- [生态元素（物料、setter、插件）工具链](https://lowcode-engine.cn/site/docs/guide/expand/editor/cli)\n- [用户文档](https://lowcode-engine.cn/doc)\n- [API](https://lowcode-engine.cn/site/docs/api/)\n\n[awesome-lowcode-engine](https://github.com/lowcode-workspace/awesome-lowcode-engine) 中包含了一系列围绕引擎建设的工具、解决方案等，如果你有类似的解决方案或者工具，欢迎提 PR 到该仓库，让更多人了解到\n\n## 💻 本地调试\n\n```bash\n$ git clone git@github.com:alibaba/lowcode-engine.git\n$ cd lowcode-engine\n$ npm install\n$ npm run setup\n$ npm start\n```\n\n> 📢 npm 访问速度较慢，阿里员工可以使用 tnpm，其他同学建议使用 cnpm 或者指定镜像 registry。\n>\n> 📢 windows 环境必须使用 [WSL](https://docs.microsoft.com/zh-cn/windows/wsl/install)，其他终端不保证能正常运行\n\nlowcode-engine 启动后，提供了几个 umd 文件，可以结合 [lowcode-demo](https://github.com/alibaba/lowcode-demo) 项目做调试，文件代理规则参考[这里](https://lowcode-engine.cn/site/docs/participate/prepare#2-配置资源代理)。\n\n## 🤝 参与共建\n\n请先阅读：\n1. [如何配置引擎调试环境？](https://lowcode-engine.cn/site/docs/participate/prepare)\n2. [关于引擎的研发协作流程](https://lowcode-engine.cn/site/docs/participate/flow)\n3. [引擎的工程化配置](https://lowcode-engine.cn/site/docs/participate/config)\n\n> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393)，更好的问题更容易获得帮助。（此段参考 [antd](https://github.com/ant-design/ant-design)）\n\n关于提交 PR：\n请将目标合并分支设置为 **develop**，不要指定 **main** 分支，在发布正式版本后，develop 分支将会合入 main 分支。\n\n## ❤️ 致谢\n\n感谢所有为引擎项目贡献力量的同学们~\n\n<p>\n<a href=\"https://github.com/alibaba/lowcode-engine/graphs/contributors\"><img src=\"https://contrib.rocks/image?repo=alibaba/lowcode-engine\" /></a>\n</p>\n"
  },
  {
    "path": "packages/engine/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://lowcode-engine.cn\">\n    <img width=\"200\" src=\"https://img.alicdn.com/imgextra/i3/O1CN01i8K9cD1d0HU7TjDtv_!!6000000003673-2-tps-500-591.png\">\n  </a>\n</p>\n\n<h1 align=\"center\">LowCodeEngine</h1>\n\n<div align=\"center\">\n\nAn enterprise-class low-code technology stack with scale-out design\n\n[![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]\n\n[![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]\n\n[![codecov][codecov-image-url]][codecov-url] [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/lowcode-workspace/awesome-lowcode-engine)\n\n[![](https://img.shields.io/badge/LowCodeEngine-Check%20Your%20Contribution-orange)](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=lowcode-engine)\n\n[npm-image]: https://img.shields.io/npm/v/@alilc/lowcode-engine.svg?style=flat-square\n[npm-url]: http://npmjs.org/package/@alilc/lowcode-engine\n\n[download-image]: https://img.shields.io/npm/dm/@alilc/lowcode-engine.svg?style=flat-square\n[download-url]: https://npmjs.org/package/@alilc/lowcode-engine\n[help-wanted-image]: https://flat.badgen.net/github/label-issues/alibaba/lowcode-engine/help%20wanted/open\n[help-wanted-url]: https://github.com/alibaba/lowcode-engine/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22\n\n[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square\n[issues-helper-url]: https://github.com/actions-cool/issues-helper\n\n[codecov-image-url]: https://codecov.io/gh/alibaba/lowcode-engine/branch/main/graph/badge.svg\n[codecov-url]: https://codecov.io/gh/alibaba/lowcode-engine\n\n</div>\n\n[![](https://img.alicdn.com/imgextra/i2/O1CN01UhoS7C1sNNhySvfWi_!!6000000005754-2-tps-2878-1588.png)](http://lowcode-engine.cn)\n\nEnglish | [简体中文](./packages/engine/README-zh_CN.md)\n\n## ✨ Features\n\n- 🌈 An extension-oriented kernel engine extracted from an enterprise-level low-code platform, pursuing the design concept of the smallest kernel and the strongest ecology\n- 📦 Out-of-the-box high-quality ecological elements, including material systems, setters, plugins, etc.\n- ⚙️ A complete tool chain, supporting the full-link R&D cycle of ecological elements such as material systems, setters, and plug-ins\n- 🔌 Powerful expansion capability, has supported nearly 100 various vertical low-code platforms\n- 🛡 Developed with TypeScript, providing complete type definition files\n\n## 🎯 Compatible Environments\n\n- Modern browsers (Chrome >= 80, Edge >= 80, last 2 safari versions, last 2 firefox versions)\n\n## 📚 Engine Protocol\n\nThe engine fully implements the \"LowCodeEngine Basic Construction Protocol Specification\" and \"LowCodeEngine Material Protocol Specification\". The protocol stack is a key part of whether materials in the low-code field can be circulated.\n\n![image](https://img.alicdn.com/imgextra/i3/O1CN01IisBcy1dNBIg16QFM_!!6000000003723-2-tps-1916-1070.png)\n\n## 🌰 Usage example\n\n```bash\nnpm install @alilc/lowcode-engine --save-dev\n```\n\n> **TIPS: Only cdn import is supported, npm package is used to provide code hinting capabilities such as typings**\n\n```ts\nimport { init, skeleton } from '@alilc/lowcode-engine';\n\nskeleton.add({\n  area: 'topArea',\n  type: 'Widget',\n  name: 'logo',\n  content: YourFantasticLogo,\n  contentProps: {\n    logo:\n      'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png',\n    href: '/',\n  },\n  props: {\n    align: 'left',\n    width: 100,\n  },\n});\n\ninit(document.getElementById('lce'));\n```\n\n### Engineering configuration:\n```json\n{\n  \"externals\": {\n    \"@alilc/lowcode-engine\": \"var window.AliLowCodeEngine\",\n    \"@alilc/lowcode-engine-ext\": \"var window.AliLowCodeEngineExt\"\n  }\n}\n```\n\n### cdn optional method:\n#### Method 1: alifd cdn\n```html\nhttps://alifd.alicdn.com/npm/@alilc/lowcode-engine@1.0.18/dist/js/engine-core.js\n\nhttps://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### Method 2: uipaas cdn\n```html\nhttps://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js\n\nhttps://uipaas-assets.com/prod/npm/@alilc/lowcode-react-simulator-renderer/1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### Method 3: unpkg\n```html\nhttps://unpkg.com/@alilc/lowcode-engine@1.0.18/dist/js/engine-core.js\n\nhttps://unpkg.com/@alilc/lowcode-react-simulator-renderer@1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### Method 4: jsdelivr\n```html\nhttps://cdn.jsdelivr.net/npm/@alilc/lowcode-engine@1.0.18/dist/js/engine-core.js\n\nhttps://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist/js/react-simulator-renderer.js\n```\n\n#### Method 5: Use your own cdn\nPass the files under packages/engine/dist and packages/react-simulator-renderer/dist in the source code to your cdn provider\n\n## 🔗 Related Links\n\n- [Official website home page](http://lowcode-engine.cn/)\n- [Demo Play Now](http://lowcode-engine.cn/demo) | [Engine Demo Repository](https://github.com/alibaba/lowcode-demo)\n- [Official Materials](https://github.com/alibaba/lowcode-materials)\n- [official setter](https://github.com/alibaba/lowcode-engine-ext)\n- [Official plugin (plugin)](https://github.com/alibaba/lowcode-plugins)\n- [Ecological elements (materials, setters, plugins) toolchain](https://lowcode-engine.cn/site/docs/guide/expand/editor/cli)\n- [User Documentation](http://lowcode-engine.cn/doc)\n- [API](https://lowcode-engine.cn/site/docs/api/)\n\nThis [awesome-lowcode-engine](https://github.com/lowcode-workspace/awesome-lowcode-engine) page links to a repository which records all of the tools\\materials\\solutions that use or built for the lowcode-engine, PR is welcomed.\n\n## 💻 Local debugging\n\n```bash\n$ git clone git@github.com:alibaba/lowcode-engine.git\n$ cd lowcode-engine\n$ npm install\n$ npm run setup\n$ npm start\n```\n\n> 📢 npm access speed is slow, Alibaba employees can use tnpm, other students recommend using cnpm or specifying a mirror registry.\n>\n> 📢 Windows environment must use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install), other terminals are not guaranteed to work normally\n\nAfter lowcode-engine is started, several umd files are provided, which can be debugged in combination with the [lowcode-demo](https://github.com/alibaba/lowcode-demo) project. Refer to the file proxy rules [here](https://lowcode-engine.cn/site/docs/participate/prepare).\n\n## 🤝 Participation\n\nPlease read first:\n1. [How to configure the engine debugging environment? ](https://lowcode-engine.cn/site/docs/participate/prepare)\n2. [About the R&D collaboration process of the engine](https://lowcode-engine.cn/site/docs/participate/flow)\n3. [Engineering Configuration of Engine](https://lowcode-engine.cn/site/docs/participate/config)\n\n> Strongly recommend reading [\"The Wisdom of Asking Questions\"](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way), [\"How to Ask Questions to the Open Source Community\"](https: //github.com/seajs/seajs/issues/545) and [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html), [ \"How to Submit Unanswerable Questions to Open Source Projects\"](https://zhuanlan.zhihu.com/p/25795393), better questions are easier to get help. (This paragraph refers to [antd](https://github.com/ant-design/ant-design))\n\nAbout Pull Request:\n- set the target branch to **develop** other than **main**\n\n## ❤️ Contributors\n\nSpecial thanks to everyone who contributed to this project.\n\n<p>\n<a href=\"https://github.com/alibaba/lowcode-engine/graphs/contributors\"><img src=\"https://contrib.rocks/image?repo=alibaba/lowcode-engine\" /></a>\n</p>\n"
  },
  {
    "path": "packages/engine/babel.config.js",
    "content": "module.exports = require('../../babel.config');"
  },
  {
    "path": "packages/engine/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-lowcode-light\",\n        \"externalNext\": \"umd\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\"zh-cn\"]\n      }\n    ],\n    \"./build.plugin.js\"\n  ]\n}\n"
  },
  {
    "path": "packages/engine/build.plugin.js",
    "content": "const { execSync } = require('child_process');\nconst TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');\nconst fse = require('fs-extra');\n\n// get version from git branch name,\n//  e.g. release/1.0.7 => 1.0.7\n//       release/1.0.7-beta => 1.0.7 (beta)\n//       release/1.0.7-beta.0 => 1.0.7 (beta)\nfunction getVersion() {\n  const gitBranchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' });\n  const reBranchVersion = /^(?:[\\w-]+\\/)(\\d+\\.\\d+\\.\\d+)(-?beta)?(?:\\.\\d+)?$/im;\n\n  const match = reBranchVersion.exec(gitBranchName);\n  if (!match) {\n    console.warn(`[engine] gitBranchName: ${gitBranchName}`);\n    return 'N/A';\n  }\n\n  const [_, version, beta] = match;\n\n  return beta && beta.endsWith('beta') ? `${version}-beta` : version;\n}\n\nconst releaseVersion = getVersion();\n\nmodule.exports = ({ context, onGetWebpackConfig }) => {\n  onGetWebpackConfig((config) => {\n    config.resolve\n      .plugin('tsconfigpaths')\n      .use(TsconfigPathsPlugin, [{\n        configFile: './tsconfig.json',\n      }]);\n    config\n      .plugin('define')\n      .use(context.webpack.DefinePlugin, [{\n        VERSION_PLACEHOLDER: JSON.stringify(releaseVersion),\n      }]);\n    config.plugins.delete('hot');\n    config.devServer.hot(false);\n  });\n};\n"
  },
  {
    "path": "packages/engine/build.test.json",
    "content": "{\n  \"plugins\": [\n    [\n      \"@alilc/build-plugin-lce\",\n      {\n        \"filename\": \"editor-preset-vision\",\n        \"library\": \"LowcodeEditor\",\n        \"libraryTarget\": \"umd\",\n        \"externals\": {\n          \"react\": \"var window.React\",\n          \"react-dom\": \"var window.ReactDOM\",\n          \"prop-types\": \"var window.PropTypes\",\n          \"rax\": \"var window.Rax\"\n        }\n      }\n    ],\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/engine/build.umd.json",
    "content": "{\n  \"entry\": {\n    \"engine-core\": \"src/index\"\n  },\n  \"sourceMap\": true,\n  \"library\": \"AliLowCodeEngine\",\n  \"libraryTarget\": \"umd\",\n  \"externals\": {\n    \"react\": \"var window.React\",\n    \"react-dom\": \"var window.ReactDOM\",\n    \"prop-types\": \"var window.PropTypes\",\n    \"@ali/visualengine\": \"var window.VisualEngine\",\n    \"@ali/visualengine-utils\": \"var window.VisualEngineUtils\",\n    \"rax\": \"var window.Rax\",\n    \"monaco-editor/esm/vs/editor/editor.api\": \"var window.monaco\",\n    \"monaco-editor/esm/vs/editor/editor.main.js\": \"var window.monaco\",\n    \"@alifd/next\": \"var Next\",\n    \"@alilc/lowcode-engine-ext\": \"var window.AliLowCodeEngineExt\",\n    \"moment\": \"var moment\",\n    \"lodash\": \"var _\"\n  },\n  \"polyfill\": false,\n  \"outputDir\": \"dist\",\n  \"vendor\": false,\n  \"ignoreHtmlTemplate\": true,\n  \"plugins\": [\n    \"build-plugin-react-app\",\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-lowcode-light\",\n        \"externalNext\": \"umd\"\n      }\n    ],\n    [\"build-plugin-moment-locales\", {\n      \"locales\": [\"zh-cn\"]\n    }],\n    \"./build.plugin.js\"\n  ]\n}\n"
  },
  {
    "path": "packages/engine/jest.config.js",
    "content": "const esModules = [\n  '@recore/obx-react',\n  // '@ali/lowcode-editor-core',\n].join('|');\n\nmodule.exports = {\n  // transform: {\n  //   '^.+\\\\.[jt]sx?$': 'babel-jest',\n  //   // '^.+\\\\.(ts|tsx)$': 'ts-jest',\n  //   // '^.+\\\\.(js|jsx)$': 'babel-jest',\n  // },\n  // testMatch: ['(/tests?/.*(test))\\\\.[jt]s$'],\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: false,\n  collectCoverageFrom: [\n    'src/**/*.{ts,tsx}',\n    '!src/**/*.d.ts',\n    '!src/base/**',\n    '!src/fields/**',\n    '!src/prop.ts',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n};\n"
  },
  {
    "path": "packages/engine/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-engine\",\n  \"version\": \"1.3.2\",\n  \"description\": \"An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系\",\n  \"main\": \"lib/engine-core.js\",\n  \"module\": \"es/engine-core.js\",\n  \"files\": [\n    \"dist\",\n    \"es\",\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"start\": \"build-scripts start\",\n    \"version:update\": \"node ./scripts/version.js\",\n    \"build\": \"NODE_OPTIONS=--max_old_space_size=8192 build-scripts build\",\n    \"build:umd\": \"NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json\",\n    \"test\": \"build-scripts test --config build.test.json --jest-passWithNoTests\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@alifd/next\": \"^1.19.12\",\n    \"@alilc/lowcode-designer\": \"1.3.2\",\n    \"@alilc/lowcode-editor-core\": \"1.3.2\",\n    \"@alilc/lowcode-editor-skeleton\": \"1.3.2\",\n    \"@alilc/lowcode-engine-ext\": \"^1.0.0\",\n    \"@alilc/lowcode-plugin-command\": \"1.3.2\",\n    \"@alilc/lowcode-plugin-designer\": \"1.3.2\",\n    \"@alilc/lowcode-plugin-outline-pane\": \"1.3.2\",\n    \"@alilc/lowcode-shell\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"@alilc/lowcode-workspace\": \"1.3.2\",\n    \"react\": \"^16.8.1\",\n    \"react-dom\": \"^16.8.1\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@alifd/theme-lowcode-dark\": \"^0.2.0\",\n    \"@alifd/theme-lowcode-light\": \"^0.2.0\",\n    \"@types/domready\": \"^1.0.0\",\n    \"@types/react\": \"^16.8.3\",\n    \"@types/react-dom\": \"^16.8.2\",\n    \"build-plugin-fusion\": \"0.1.17-beta.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"build-plugin-react-app\": \"^1.8.0\",\n    \"fs-extra\": \"^10.0.0\",\n    \"prop-types\": \"^15.7.2\",\n    \"tsconfig-paths-webpack-plugin\": \"^3.2.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/engine\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/engine/src/engine-core.ts",
    "content": "/* eslint-disable max-len */\n/* eslint-disable no-param-reassign */\nimport { createElement } from 'react';\nimport { render, unmountComponentAtNode } from 'react-dom';\nimport {\n  globalContext,\n  Editor,\n  commonEvent,\n  engineConfig,\n  Setters as InnerSetters,\n  Hotkey as InnerHotkey,\n  IEditor,\n  Command as InnerCommand,\n} from '@alilc/lowcode-editor-core';\nimport {\n  IPublicTypeEngineOptions,\n  IPublicModelDocumentModel,\n  IPublicTypePluginMeta,\n  IPublicTypeDisposable,\n  IPublicApiPlugins,\n  IPublicApiWorkspace,\n  IPublicEnumPluginRegisterLevel,\n  IPublicModelPluginContext,\n} from '@alilc/lowcode-types';\nimport {\n  Designer,\n  LowCodePluginManager,\n  ILowCodePluginContextPrivate,\n  ILowCodePluginContextApiAssembler,\n  PluginPreference,\n  IDesigner,\n} from '@alilc/lowcode-designer';\nimport {\n  Skeleton as InnerSkeleton,\n  registerDefaults,\n} from '@alilc/lowcode-editor-skeleton';\nimport {\n  Workspace as InnerWorkspace,\n  Workbench as WorkSpaceWorkbench,\n  IWorkspace,\n} from '@alilc/lowcode-workspace';\n\nimport {\n  Hotkey,\n  Project,\n  Skeleton,\n  Setters,\n  Material,\n  Event,\n  Plugins,\n  Common,\n  Logger,\n  Canvas,\n  Workspace,\n  Config,\n  CommonUI,\n  Command,\n} from '@alilc/lowcode-shell';\nimport { isPlainObject } from '@alilc/lowcode-utils';\nimport './modules/live-editing';\nimport * as classes from './modules/classes';\nimport symbols from './modules/symbols';\nimport { componentMetaParser } from './inner-plugins/component-meta-parser';\nimport { setterRegistry } from './inner-plugins/setter-registry';\nimport { defaultPanelRegistry } from './inner-plugins/default-panel-registry';\nimport { shellModelFactory } from './modules/shell-model-factory';\nimport { builtinHotkey } from './inner-plugins/builtin-hotkey';\nimport { defaultContextMenu } from './inner-plugins/default-context-menu';\nimport { CommandPlugin } from '@alilc/lowcode-plugin-command';\nimport { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane';\n\nexport * from './modules/skeleton-types';\nexport * from './modules/designer-types';\nexport * from './modules/lowcode-types';\n\nasync function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins: IPublicApiPlugins): Promise<IPublicTypeDisposable> {\n  // 注册一批内置插件\n  const componentMetaParserPlugin = componentMetaParser(designer);\n  const defaultPanelRegistryPlugin = defaultPanelRegistry(editor);\n  await plugins.register(OutlinePlugin, {}, { autoInit: true });\n  await plugins.register(componentMetaParserPlugin);\n  await plugins.register(setterRegistry, {});\n  await plugins.register(defaultPanelRegistryPlugin);\n  await plugins.register(builtinHotkey);\n  await plugins.register(registerDefaults, {}, { autoInit: true });\n  await plugins.register(defaultContextMenu);\n  await plugins.register(CommandPlugin, {});\n\n  return () => {\n    plugins.delete(OutlinePlugin.pluginName);\n    plugins.delete(componentMetaParserPlugin.pluginName);\n    plugins.delete(setterRegistry.pluginName);\n    plugins.delete(defaultPanelRegistryPlugin.pluginName);\n    plugins.delete(builtinHotkey.pluginName);\n    plugins.delete(registerDefaults.pluginName);\n    plugins.delete(defaultContextMenu.pluginName);\n    plugins.delete(CommandPlugin.pluginName);\n  };\n}\n\nconst innerWorkspace: IWorkspace = new InnerWorkspace(registryInnerPlugin, shellModelFactory);\nconst workspace: IPublicApiWorkspace = new Workspace(innerWorkspace);\nconst editor = new Editor();\nglobalContext.register(editor, Editor);\nglobalContext.register(editor, 'editor');\nglobalContext.register(innerWorkspace, 'workspace');\n\nconst engineContext: Partial<ILowCodePluginContextPrivate> = {};\n\nconst innerSkeleton = new InnerSkeleton(editor);\neditor.set('skeleton' as any, innerSkeleton);\n\nconst designer = new Designer({ editor, shellModelFactory });\neditor.set('designer' as any, designer);\n\nconst { project: innerProject } = designer;\n\nconst innerHotkey = new InnerHotkey();\nconst hotkey = new Hotkey(innerHotkey);\nconst project = new Project(innerProject);\nconst skeleton = new Skeleton(innerSkeleton, 'any', false);\nconst innerSetters = new InnerSetters();\nconst setters = new Setters(innerSetters);\nconst innerCommand = new InnerCommand();\nconst command = new Command(innerCommand, engineContext as IPublicModelPluginContext);\n\nconst material = new Material(editor);\nconst commonUI = new CommonUI(editor);\neditor.set('project', project);\neditor.set('setters' as any, setters);\neditor.set('material', material);\neditor.set('innerHotkey', innerHotkey);\nconst config = new Config(engineConfig);\nconst event = new Event(commonEvent, { prefix: 'common' });\nconst logger = new Logger({ level: 'warn', bizName: 'common' });\nconst common = new Common(editor, innerSkeleton);\nconst canvas = new Canvas(editor);\nlet plugins: Plugins;\n\nconst pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  assembleApis: (context: ILowCodePluginContextPrivate, pluginName: string, meta: IPublicTypePluginMeta) => {\n    context.hotkey = hotkey;\n    context.project = project;\n    context.skeleton = new Skeleton(innerSkeleton, pluginName, false);\n    context.setters = setters;\n    context.material = material;\n    const eventPrefix = meta?.eventPrefix || 'common';\n    const commandScope = meta?.commandScope;\n    context.event = new Event(commonEvent, { prefix: eventPrefix });\n    context.config = config;\n    context.common = common;\n    context.canvas = canvas;\n    context.plugins = plugins;\n    context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` });\n    context.workspace = workspace;\n    context.commonUI = commonUI;\n    context.command = new Command(innerCommand, context as IPublicModelPluginContext, {\n      commandScope,\n    });\n    context.registerLevel = IPublicEnumPluginRegisterLevel.Default;\n    context.isPluginRegisteredInWorkspace = false;\n    editor.set('pluginContext', context);\n  },\n};\n\nconst innerPlugins = new LowCodePluginManager(pluginContextApiAssembler);\nplugins = new Plugins(innerPlugins).toProxy();\neditor.set('innerPlugins' as any, innerPlugins);\neditor.set('plugins' as any, plugins);\n\nengineContext.skeleton = skeleton;\nengineContext.plugins = plugins;\nengineContext.project = project;\nengineContext.setters = setters;\nengineContext.material = material;\nengineContext.event = event;\nengineContext.logger = logger;\nengineContext.hotkey = hotkey;\nengineContext.common = common;\nengineContext.workspace = workspace;\nengineContext.canvas = canvas;\nengineContext.commonUI = commonUI;\nengineContext.command = command;\n\nexport {\n  skeleton,\n  plugins,\n  project,\n  setters,\n  material,\n  config,\n  event,\n  logger,\n  hotkey,\n  common,\n  workspace,\n  canvas,\n  commonUI,\n  command,\n};\n// declare this is open-source version\nexport const isOpenSource = true;\nexport const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {\n  symbols,\n  classes,\n};\nengineConfig.set('isOpenSource', isOpenSource);\n\n// container which will host LowCodeEngine DOM\nlet engineContainer: HTMLElement;\n// @ts-ignore webpack Define variable\nexport const version = VERSION_PLACEHOLDER;\nengineConfig.set('ENGINE_VERSION', version);\n\nconst pluginPromise = registryInnerPlugin(designer, editor, plugins);\n\nexport async function init(\n  container?: HTMLElement,\n  options?: IPublicTypeEngineOptions,\n  pluginPreference?: PluginPreference,\n  ) {\n  await destroy();\n  let engineOptions = null;\n  if (isPlainObject(container)) {\n    engineOptions = container;\n    engineContainer = document.createElement('div');\n    engineContainer.id = 'engine';\n    document.body.appendChild(engineContainer);\n  } else {\n    engineOptions = options;\n    engineContainer = container;\n    if (!container) {\n      engineContainer = document.createElement('div');\n      engineContainer.id = 'engine';\n      document.body.appendChild(engineContainer);\n    }\n  }\n  engineConfig.setEngineOptions(engineOptions as any);\n\n  const { Workbench } = common.skeletonCabin;\n  if (options && options.enableWorkspaceMode) {\n    const disposeFun = await pluginPromise;\n    disposeFun && disposeFun();\n    render(\n      createElement(WorkSpaceWorkbench, {\n        workspace: innerWorkspace,\n        // skeleton: workspace.skeleton,\n        className: 'engine-main',\n        topAreaItemClassName: 'engine-actionitem',\n      }),\n      engineContainer,\n    );\n    innerWorkspace.enableAutoOpenFirstWindow = engineConfig.get('enableAutoOpenFirstWindow', true);\n    innerWorkspace.setActive(true);\n    innerWorkspace.initWindow();\n    innerHotkey.activate(false);\n    await innerWorkspace.plugins.init(pluginPreference);\n    return;\n  }\n\n  await plugins.init(pluginPreference as any);\n\n  render(\n    createElement(Workbench, {\n      skeleton: innerSkeleton,\n      className: 'engine-main',\n      topAreaItemClassName: 'engine-actionitem',\n    }),\n    engineContainer,\n  );\n}\n\nexport async function destroy() {\n  // remove all documents\n  const { documents } = project;\n  if (Array.isArray(documents) && documents.length > 0) {\n    documents.forEach(((doc: IPublicModelDocumentModel) => project.removeDocument(doc)));\n  }\n\n  // TODO: delete plugins except for core plugins\n\n  // unmount DOM container, this will trigger React componentWillUnmount lifeCycle,\n  // so necessary cleanups will be done.\n  engineContainer && unmountComponentAtNode(engineContainer);\n}\n"
  },
  {
    "path": "packages/engine/src/index.ts",
    "content": "import { version } from './engine-core';\n\nexport * from './engine-core';\nconsole.log(\n  `%c AliLowCodeEngine %c v${version} `,\n  'padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060; font-weight: bold;',\n  'padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e; font-weight: bold;',\n);\n"
  },
  {
    "path": "packages/engine/src/inner-plugins/builtin-hotkey.ts",
    "content": "/* eslint-disable max-len */\nimport { isFormEvent, isNodeSchema, isNode } from '@alilc/lowcode-utils';\nimport {\n  IPublicModelPluginContext,\n  IPublicEnumTransformStage,\n  IPublicModelNode,\n  IPublicTypeNodeSchema,\n  IPublicTypeNodeData,\n  IPublicEnumDragObjectType,\n  IPublicTypeDragNodeObject,\n} from '@alilc/lowcode-types';\n\nfunction insertChild(\n  container: IPublicModelNode,\n  originalChild: IPublicModelNode | IPublicTypeNodeData,\n  at?: number | null,\n): IPublicModelNode | null {\n  let child = originalChild;\n  if (isNode(child) && (child as IPublicModelNode).isSlotNode) {\n    child = (child as IPublicModelNode).exportSchema(IPublicEnumTransformStage.Clone);\n  }\n  let node = null;\n  if (isNode(child)) {\n    node = (child as IPublicModelNode);\n    container.children?.insert(node, at);\n  } else {\n    node = container.document?.createNode(child) || null;\n    if (node) {\n      container.children?.insert(node, at);\n    }\n  }\n\n  return (node as IPublicModelNode) || null;\n}\n\nfunction insertChildren(\n  container: IPublicModelNode,\n  nodes: IPublicModelNode[] | IPublicTypeNodeData[],\n  at?: number | null,\n): IPublicModelNode[] {\n  let index = at;\n  let node: any;\n  const results: IPublicModelNode[] = [];\n  // eslint-disable-next-line no-cond-assign\n  while ((node = nodes.pop())) {\n    node = insertChild(container, node, index);\n    results.push(node);\n    index = node.index;\n  }\n  return results;\n}\n\n/**\n * 获得合适的插入位置\n */\nfunction getSuitableInsertion(\n  pluginContext: IPublicModelPluginContext,\n  insertNode?: IPublicModelNode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[],\n): { target: IPublicModelNode; index?: number } | null {\n  const { project, material } = pluginContext;\n  const activeDoc = project.currentDocument;\n  if (!activeDoc) {\n    return null;\n  }\n  if (\n    Array.isArray(insertNode) &&\n    isNodeSchema(insertNode[0]) &&\n    material.getComponentMeta(insertNode[0].componentName)?.isModal\n  ) {\n    if (!activeDoc.root) {\n      return null;\n    }\n\n    return {\n      target: activeDoc.root,\n    };\n  }\n\n  const focusNode = activeDoc.focusNode!;\n  const nodes = activeDoc.selection.getNodes();\n  const refNode = nodes.find((item) => focusNode.contains(item));\n  let target;\n  let index: number | undefined;\n  if (!refNode || refNode === focusNode) {\n    target = focusNode;\n  } else if (refNode.componentMeta?.isContainer) {\n    target = refNode;\n  } else {\n    // FIXME!!, parent maybe null\n    target = refNode.parent!;\n    index = refNode.index + 1;\n  }\n\n  if (target && insertNode && !target.componentMeta?.checkNestingDown(target, insertNode)) {\n    return null;\n  }\n\n  return { target, index };\n}\n\n/* istanbul ignore next */\nfunction getNextForSelect(next: IPublicModelNode | null, head?: any, parent?: IPublicModelNode | null): any {\n  if (next) {\n    if (!head) {\n      return next;\n    }\n\n    let ret;\n    if (next.isContainerNode) {\n      const { children } = next;\n      if (children && !children.isEmptyNode) {\n        ret = getNextForSelect(children.get(0));\n        if (ret) {\n          return ret;\n        }\n      }\n    }\n\n    ret = getNextForSelect(next.nextSibling);\n    if (ret) {\n      return ret;\n    }\n  }\n\n  if (parent) {\n    return getNextForSelect(parent.nextSibling, false, parent?.parent);\n  }\n\n  return null;\n}\n\n/* istanbul ignore next */\nfunction getPrevForSelect(prev: IPublicModelNode | null, head?: any, parent?: IPublicModelNode | null): any {\n  if (prev) {\n    let ret;\n    if (!head && prev.isContainerNode) {\n      const { children } = prev;\n      const lastChild = children && !children.isEmptyNode ? children.get(children.size - 1) : null;\n\n      ret = getPrevForSelect(lastChild);\n      if (ret) {\n        return ret;\n      }\n    }\n\n    if (!head) {\n      return prev;\n    }\n\n    ret = getPrevForSelect(prev.prevSibling);\n    if (ret) {\n      return ret;\n    }\n  }\n\n  if (parent) {\n    return parent;\n  }\n\n  return null;\n}\n\nfunction getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicModelNode, ref: any): any {\n  const { document } = targetNode;\n  if (!document) {\n    return null;\n  }\n\n  const dragNodeObject: IPublicTypeDragNodeObject = {\n    type: IPublicEnumDragObjectType.Node,\n    nodes: [node],\n  };\n\n  const focusNode = document?.focusNode;\n  // 如果节点是模态框，插入到根节点下\n  if (node?.componentMeta?.isModal) {\n    return { container: focusNode, ref };\n  }\n\n  if (!ref && focusNode && targetNode.contains(focusNode)) {\n    if (document.checkNesting(focusNode, dragNodeObject)) {\n      return { container: focusNode };\n    }\n\n    return null;\n  }\n\n  if (targetNode.isRootNode && targetNode.children) {\n    const dropElement = targetNode.children.filter((c) => {\n      if (!c.isContainerNode) {\n        return false;\n      }\n      if (document.checkNesting(c, dragNodeObject)) {\n        return true;\n      }\n      return false;\n    })[0];\n\n    if (dropElement) {\n      return { container: dropElement, ref };\n    }\n\n    if (document.checkNesting(targetNode, dragNodeObject)) {\n      return { container: targetNode, ref };\n    }\n\n    return null;\n  }\n\n  if (targetNode.isContainerNode) {\n    if (document.checkNesting(targetNode, dragNodeObject)) {\n      return { container: targetNode, ref };\n    }\n  }\n\n  if (targetNode.parent) {\n    return getSuitablePlaceForNode(targetNode.parent, node, { index: targetNode.index });\n  }\n\n  return null;\n}\n\n// 注册默认的 setters\nexport const builtinHotkey = (ctx: IPublicModelPluginContext) => {\n  return {\n    init() {\n      const { hotkey, project, logger, canvas } = ctx;\n      const { clipboard } = canvas;\n      // hotkey binding\n      hotkey.bind(['backspace', 'del'], (e: KeyboardEvent, action) => {\n        logger.info(`action ${action} is triggered`);\n\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        // TODO: use focus-tracker\n        const doc = project.currentDocument;\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        e.preventDefault();\n\n        const sel = doc.selection;\n        const topItems = sel.getTopNodes();\n        // TODO: check can remove\n        topItems.forEach((node) => {\n          if (node?.canPerformAction('remove')) {\n            node && doc.removeNode(node);\n          }\n        });\n        sel.clear();\n      });\n\n      hotkey.bind('escape', (e: KeyboardEvent, action) => {\n        logger.info(`action ${action} is triggered`);\n\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const sel = project.currentDocument?.selection;\n        if (isFormEvent(e) || !sel) {\n          return;\n        }\n        e.preventDefault();\n\n        sel.clear();\n        // currentFocus.esc();\n      });\n\n      // command + c copy  command + x cut\n      hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const doc = project.currentDocument;\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        const anchorValue = document.getSelection()?.anchorNode?.nodeValue;\n        if (anchorValue && typeof anchorValue === 'string') {\n          return;\n        }\n        e.preventDefault();\n\n        let selected = doc.selection.getTopNodes(true);\n        selected = selected.filter((node) => {\n          return node?.canPerformAction('copy');\n        });\n        if (!selected || selected.length < 1) {\n          return;\n        }\n\n        const componentsMap = {};\n        const componentsTree = selected.map((item) => item?.exportSchema(IPublicEnumTransformStage.Clone));\n\n        // FIXME: clear node.id\n\n        const data = { type: 'nodeSchema', componentsMap, componentsTree };\n\n        clipboard.setData(data);\n\n        const cutMode = action && action.indexOf('x') > 0;\n        if (cutMode) {\n          selected.forEach((node) => {\n            const parentNode = node?.parent;\n            parentNode?.select();\n            node?.remove();\n          });\n        }\n      });\n\n      // command + v paste\n      hotkey.bind(['command+v', 'ctrl+v'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        // TODO\n        const doc = project?.currentDocument;\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        /* istanbul ignore next */\n        clipboard.waitPasteData(e, ({ componentsTree }) => {\n          if (componentsTree) {\n            const { target, index } = getSuitableInsertion(ctx, componentsTree) || {};\n            if (!target) {\n              return;\n            }\n            let canAddComponentsTree = componentsTree.filter((node: IPublicModelNode) => {\n              const dragNodeObject: IPublicTypeDragNodeObject = {\n                type: IPublicEnumDragObjectType.Node,\n                nodes: [node],\n              };\n              return doc.checkNesting(target, dragNodeObject);\n            });\n            if (canAddComponentsTree.length === 0) {\n              return;\n            }\n            const nodes = insertChildren(target, canAddComponentsTree, index);\n            if (nodes) {\n              doc.selection.selectAll(nodes.map((o) => o.id));\n              setTimeout(() => canvas.activeTracker?.track(nodes[0]), 10);\n            }\n          }\n        });\n      });\n\n      // command + z undo\n      hotkey.bind(['command+z', 'ctrl+z'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const history = project.currentDocument?.history;\n        if (isFormEvent(e) || !history) {\n          return;\n        }\n\n        e.preventDefault();\n        const selection = project.currentDocument?.selection;\n        const curSelected = selection?.selected && Array.from(selection?.selected);\n        history.back();\n        selection?.selectAll(curSelected);\n      });\n\n      // command + shift + z redo\n      hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const history = project.currentDocument?.history;\n        if (isFormEvent(e) || !history) {\n          return;\n        }\n        e.preventDefault();\n        const selection = project.currentDocument?.selection;\n        const curSelected = selection?.selected && Array.from(selection?.selected);\n        history.forward();\n        selection?.selectAll(curSelected);\n      });\n\n      // sibling selection\n      hotkey.bind(['left', 'right'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const doc = project.currentDocument;\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        e.preventDefault();\n        const selected = doc.selection.getTopNodes(true);\n        if (!selected || selected.length < 1) {\n          return;\n        }\n        const firstNode = selected[0];\n        const silbing = action === 'left' ? firstNode?.prevSibling : firstNode?.nextSibling;\n        silbing?.select();\n      });\n\n      hotkey.bind(['up', 'down'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const doc = project.currentDocument;\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        e.preventDefault();\n        const selected = doc.selection.getTopNodes(true);\n        if (!selected || selected.length < 1) {\n          return;\n        }\n        const firstNode = selected[0];\n\n        if (action === 'down') {\n          const next = getNextForSelect(firstNode, true, firstNode?.parent);\n          next?.select();\n        } else if (action === 'up') {\n          const prev = getPrevForSelect(firstNode, true, firstNode?.parent);\n          prev?.select();\n        }\n      });\n\n      hotkey.bind(['option+left', 'option+right'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const doc = project.currentDocument;\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        e.preventDefault();\n        const selected = doc.selection.getTopNodes(true);\n        if (!selected || selected.length < 1) {\n          return;\n        }\n        // TODO: 此处需要增加判断当前节点是否可被操作移动，原ve里是用 node.canOperating()来判断\n        // TODO: 移动逻辑也需要重新梳理，对于移动目标位置的选择，是否可以移入，需要增加判断\n\n        const firstNode = selected[0];\n        const parent = firstNode?.parent;\n        if (!parent) return;\n\n        const isPrev = action && /(left)$/.test(action);\n\n        const silbing = isPrev ? firstNode.prevSibling : firstNode.nextSibling;\n        if (silbing) {\n          if (isPrev) {\n            parent.insertBefore(firstNode, silbing, true);\n          } else {\n            parent.insertAfter(firstNode, silbing, true);\n          }\n          firstNode?.select();\n        }\n      });\n\n      hotkey.bind(['option+up'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const doc = project.currentDocument;\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        e.preventDefault();\n        const selected = doc.selection.getTopNodes(true);\n        if (!selected || selected.length < 1) {\n          return;\n        }\n        // TODO: 此处需要增加判断当前节点是否可被操作移动，原ve里是用 node.canOperating()来判断\n        // TODO: 移动逻辑也需要重新梳理，对于移动目标位置的选择，是否可以移入，需要增加判断\n\n        const firstNode = selected[0];\n        const parent = firstNode?.parent;\n        if (!parent) {\n          return;\n        }\n\n        const silbing = firstNode.prevSibling;\n        if (silbing) {\n          if (silbing.isContainerNode) {\n            const place = getSuitablePlaceForNode(silbing, firstNode, null);\n            silbing.insertAfter(firstNode, place.ref, true);\n          } else {\n            parent.insertBefore(firstNode, silbing, true);\n          }\n          firstNode?.select();\n        } else {\n          const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards\n          if (place) {\n            const container = place.container.internalToShellNode();\n            container.insertBefore(firstNode, place.ref);\n            firstNode?.select();\n          }\n        }\n      });\n\n      hotkey.bind(['option+down'], (e, action) => {\n        logger.info(`action ${action} is triggered`);\n        if (canvas.isInLiveEditing) {\n          return;\n        }\n        const doc = project.getCurrentDocument();\n        if (isFormEvent(e) || !doc) {\n          return;\n        }\n        e.preventDefault();\n        const selected = doc.selection.getTopNodes(true);\n        if (!selected || selected.length < 1) {\n          return;\n        }\n        // TODO: 此处需要增加判断当前节点是否可被操作移动，原 ve 里是用 node.canOperating() 来判断\n        // TODO: 移动逻辑也需要重新梳理，对于移动目标位置的选择，是否可以移入，需要增加判断\n\n        const firstNode = selected[0];\n        const parent = firstNode?.parent;\n        if (!parent) {\n          return;\n        }\n\n        const silbing = firstNode.nextSibling;\n        if (silbing) {\n          if (silbing.isContainerNode) {\n            silbing.insertBefore(firstNode, undefined);\n          } else {\n            parent.insertAfter(firstNode, silbing, true);\n          }\n          firstNode?.select();\n        } else {\n          const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards\n          if (place) {\n            const container = place.container.internalToShellNode();\n            container.insertAfter(firstNode, place.ref, true);\n            firstNode?.select();\n          }\n        }\n      });\n    },\n  };\n};\n\nbuiltinHotkey.pluginName = '___builtin_hotkey___';\n"
  },
  {
    "path": "packages/engine/src/inner-plugins/component-meta-parser.ts",
    "content": "import { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nexport const componentMetaParser = (designer: any) => {\n  const fun = (ctx: IPublicModelPluginContext) => {\n    return {\n      init() {\n        const { material } = ctx;\n        material.onChangeAssets(() => {\n          const assets = material.getAssets();\n          const { components = [] } = assets;\n          designer.buildComponentMetasMap(components);\n        });\n      },\n    };\n  };\n\n  fun.pluginName = '___component_meta_parser___';\n\n  return fun;\n};\n"
  },
  {
    "path": "packages/engine/src/inner-plugins/default-context-menu.ts",
    "content": "import {\n  IPublicEnumContextMenuType,\n  IPublicEnumDragObjectType,\n  IPublicEnumTransformStage,\n  IPublicModelNode,\n  IPublicModelPluginContext,\n  IPublicTypeDragNodeDataObject,\n  IPublicTypeNodeSchema,\n} from '@alilc/lowcode-types';\nimport { isProjectSchema } from '@alilc/lowcode-utils';\nimport { Message } from '@alifd/next';\nimport { intl } from '../locale';\n\nfunction getNodesSchema(nodes: IPublicModelNode[]) {\n  const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone));\n  const data = { type: 'nodeSchema', componentsMap: {}, componentsTree };\n  return data;\n}\n\nasync function getClipboardText(): Promise<IPublicTypeNodeSchema[]> {\n  return new Promise((resolve, reject) => {\n    // 使用 Clipboard API 读取剪贴板内容\n    navigator.clipboard.readText().then(\n      (text) => {\n        try {\n          const data = JSON.parse(text);\n          if (isProjectSchema(data)) {\n            resolve(data.componentsTree);\n          } else {\n            Message.error(intl('NotValidNodeData'));\n            reject(\n              new Error(intl('NotValidNodeData')),\n            );\n          }\n        } catch (error) {\n          Message.error(intl('NotValidNodeData'));\n          reject(error);\n        }\n      },\n      (err) => {\n        reject(err);\n      },\n    );\n  });\n}\n\nexport const defaultContextMenu = (ctx: IPublicModelPluginContext) => {\n  const { material, canvas, common } = ctx;\n  const { clipboard } = canvas;\n  const { intl: utilsIntl } = common.utils;\n\n  return {\n    init() {\n      material.addContextMenuOption({\n        name: 'selectComponent',\n        title: intl('SelectComponents'),\n        condition: (nodes = []) => {\n          return nodes.length === 1;\n        },\n        items: [\n          {\n            name: 'nodeTree',\n            type: IPublicEnumContextMenuType.NODE_TREE,\n          },\n        ],\n      });\n\n      material.addContextMenuOption({\n        name: 'copyAndPaste',\n        title: intl('CopyAndPaste'),\n        disabled: (nodes = []) => {\n          return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0;\n        },\n        condition: (nodes) => {\n          return nodes?.length === 1;\n        },\n        action(nodes) {\n          const node = nodes?.[0];\n          if (!node) {\n            return;\n          }\n          const { document: doc, parent, index } = node;\n          const data = getNodesSchema(nodes);\n          clipboard.setData(data);\n\n          if (parent) {\n            const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true);\n            newNode?.select();\n          }\n        },\n      });\n\n      material.addContextMenuOption({\n        name: 'copy',\n        title: intl('Copy'),\n        disabled: (nodes = []) => {\n          return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0;\n        },\n        condition(nodes = []) {\n          return nodes?.length > 0;\n        },\n        action(nodes) {\n          if (!nodes || nodes.length < 1) {\n            return;\n          }\n\n          const data = getNodesSchema(nodes);\n          clipboard.setData(data);\n        },\n      });\n\n      material.addContextMenuOption({\n        name: 'pasteToBottom',\n        title: intl('PasteToTheBottom'),\n        condition: (nodes) => {\n          return nodes?.length === 1;\n        },\n        async action(nodes) {\n          if (!nodes || nodes.length < 1) {\n            return;\n          }\n\n          const node = nodes[0];\n          const { document: doc, parent, index } = node;\n\n          try {\n            const nodeSchema = await getClipboardText();\n            if (nodeSchema.length === 0) {\n              return;\n            }\n            if (parent) {\n              let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => {\n                const dragNodeObject: IPublicTypeDragNodeDataObject = {\n                  type: IPublicEnumDragObjectType.NodeData,\n                  data: nodeSchema,\n                };\n                return doc?.checkNesting(parent, dragNodeObject);\n              });\n              if (canAddNodes.length === 0) {\n                Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`);\n                return;\n              }\n              const nodes: IPublicModelNode[] = [];\n              canAddNodes.forEach((schema, schemaIndex) => {\n                const node = doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true);\n                node && nodes.push(node);\n              });\n              doc?.selection.selectAll(nodes.map((node) => node?.id));\n            }\n          } catch (error) {\n            console.error(error);\n          }\n        },\n      });\n\n      material.addContextMenuOption({\n        name: 'pasteToInner',\n        title: intl('PasteToTheInside'),\n        condition: (nodes) => {\n          return nodes?.length === 1;\n        },\n        disabled: (nodes = []) => {\n          // 获取粘贴数据\n          const node = nodes?.[0];\n          return !node.isContainerNode;\n        },\n        async action(nodes) {\n          const node = nodes?.[0];\n          if (!node) {\n            return;\n          }\n          const { document: doc } = node;\n\n          try {\n            const nodeSchema = await getClipboardText();\n            const index = node.children?.size || 0;\n            if (nodeSchema.length === 0) {\n              return;\n            }\n            let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => {\n              const dragNodeObject: IPublicTypeDragNodeDataObject = {\n                type: IPublicEnumDragObjectType.NodeData,\n                data: nodeSchema,\n              };\n              return doc?.checkNesting(node, dragNodeObject);\n            });\n            if (canAddNodes.length === 0) {\n              Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`);\n              return;\n            }\n\n            const nodes: IPublicModelNode[] = [];\n            nodeSchema.forEach((schema, schemaIndex) => {\n              const newNode = doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true);\n              newNode && nodes.push(newNode);\n            });\n            doc?.selection.selectAll(nodes.map((node) => node?.id));\n          } catch (error) {\n            console.error(error);\n          }\n        },\n      });\n\n      material.addContextMenuOption({\n        name: 'delete',\n        title: intl('Delete'),\n        disabled(nodes = []) {\n          return nodes?.filter((node) => !node?.canPerformAction('remove')).length > 0;\n        },\n        condition(nodes = []) {\n          return nodes.length > 0;\n        },\n        action(nodes) {\n          nodes?.forEach((node) => {\n            node.remove();\n          });\n        },\n      });\n    },\n  };\n};\n\ndefaultContextMenu.pluginName = '___default_context_menu___';\n"
  },
  {
    "path": "packages/engine/src/inner-plugins/default-panel-registry.tsx",
    "content": "import { IPublicModelPluginContext } from '@alilc/lowcode-types';\nimport { SettingsPrimaryPane } from '@alilc/lowcode-editor-skeleton';\nimport DesignerPlugin from '@alilc/lowcode-plugin-designer';\n\n// 注册默认的面板\nexport const defaultPanelRegistry = (editor: any) => {\n  const fun = (ctx: IPublicModelPluginContext) => {\n    return {\n      init() {\n        const { skeleton, config } = ctx;\n        skeleton.add({\n          area: 'mainArea',\n          name: 'designer',\n          type: 'Widget',\n          content: <DesignerPlugin\n            engineConfig={config}\n            engineEditor={editor}\n          />,\n        });\n        if (!config.get('disableDefaultSettingPanel')) {\n          skeleton.add({\n            area: 'rightArea',\n            name: 'settingsPane',\n            type: 'Panel',\n            content: <SettingsPrimaryPane\n              engineEditor={editor}\n            />,\n            props: {\n              ignoreRoot: true,\n            },\n            panelProps: {\n              ...(config.get('defaultSettingPanelProps') || {}),\n            },\n          });\n        }\n      },\n    };\n  };\n\n  fun.pluginName = '___default_panel___';\n\n  return fun;\n};\n\nexport default defaultPanelRegistry;\n"
  },
  {
    "path": "packages/engine/src/inner-plugins/setter-registry.ts",
    "content": "import { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\n// 注册默认的 setters\nexport const setterRegistry = (ctx: IPublicModelPluginContext) => {\n  return {\n    init() {\n      const { config } = ctx;\n      if (config.get('disableDefaultSetters')) return;\n      const builtinSetters = require('@alilc/lowcode-engine-ext')?.setters;\n      if (builtinSetters) {\n        ctx.setters.registerSetter(builtinSetters);\n      }\n    },\n  };\n};\n\nsetterRegistry.pluginName = '___setter_registry___';\n"
  },
  {
    "path": "packages/engine/src/locale/en-US.json",
    "content": "{\n  \"NotValidNodeData\": \"Not valid node data\",\n  \"SelectComponents\": \"Select components\",\n  \"CopyAndPaste\": \"Copy and Paste\",\n  \"Copy\": \"Copy\",\n  \"PasteToTheBottom\": \"Paste to the bottom\",\n  \"PasteToTheInside\": \"Paste to the inside\",\n  \"Delete\": \"Delete\"\n}\n"
  },
  {
    "path": "packages/engine/src/locale/index.ts",
    "content": "import { createIntl } from '@alilc/lowcode-editor-core';\nimport enUS from './en-US.json';\nimport zhCN from './zh-CN.json';\n\nconst { intl, getLocale } = createIntl?.({\n  'en-US': enUS,\n  'zh-CN': zhCN,\n}) || {\n  intl: (id) => {\n    return zhCN[id];\n  },\n};\n\nexport { intl, enUS, zhCN, getLocale };\n"
  },
  {
    "path": "packages/engine/src/locale/zh-CN.json",
    "content": "{\n  \"NotValidNodeData\": \"不是有效的节点数据\",\n  \"SelectComponents\": \"选择组件\",\n  \"CopyAndPaste\": \"复制\",\n  \"Copy\": \"拷贝\",\n  \"PasteToTheBottom\": \"粘贴至下方\",\n  \"PasteToTheInside\": \"粘贴至内部\",\n  \"Delete\": \"删除\"\n}\n"
  },
  {
    "path": "packages/engine/src/modules/classes.ts",
    "content": "export {\n  Project,\n  Skeleton,\n  DocumentModel,\n  Node,\n  NodeChildren,\n  History,\n  SettingPropEntry,\n  SettingTopEntry,\n  Selection,\n  Prop,\n  SimulatorHost,\n  SkeletonItem,\n} from '@alilc/lowcode-shell';\nexport { Node as InnerNode } from '@alilc/lowcode-designer';\n\n"
  },
  {
    "path": "packages/engine/src/modules/designer-types.ts",
    "content": "import * as designerCabin from '@alilc/lowcode-designer';\n\n// 这样做的目的是为了去除 Node / DocumentModel 等的值属性，仅保留类型属性\nexport type Node = designerCabin.Node;\nexport type DocumentModel = designerCabin.DocumentModel;\nexport type RootNode = designerCabin.RootNode;\nexport type EditingTarget = designerCabin.EditingTarget;\nexport type SaveHandler = designerCabin.SaveHandler;\nexport type ComponentMeta = designerCabin.ComponentMeta;\nexport type SettingField = designerCabin.SettingField;\nexport type ILowCodePluginManager = designerCabin.ILowCodePluginManager;\nexport type PluginPreference = designerCabin.PluginPreference;"
  },
  {
    "path": "packages/engine/src/modules/live-editing.ts",
    "content": "import { EditingTarget, Node as DocNode, SaveHandler, LiveEditing } from '@alilc/lowcode-designer';\nimport { isJSExpression } from '@alilc/lowcode-utils';\n\nfunction getText(node: DocNode, prop: string) {\n  const p = node.getProp(prop, false);\n  if (!p || p.isUnset()) {\n    return null;\n  }\n  let v = p.getValue();\n  if (isJSExpression(v)) {\n    v = v.mock;\n  }\n  if (v == null) {\n    return null;\n  }\n  if (p.type === 'literal') {\n    return v;\n  }\n  return Symbol.for('not-literal');\n}\n\nexport function liveEditingRule(target: EditingTarget) {\n  // for vision components specific\n  const { node, event } = target;\n\n  const targetElement = event.target as HTMLElement;\n\n  if (!Array.from(targetElement.childNodes).every((item) => item.nodeType === Node.TEXT_NODE)) {\n    return null;\n  }\n\n  const { innerText } = targetElement;\n  const propTarget = ['title', 'label', 'text', 'content', 'children'].find((prop) => {\n    return equalText(getText(node, prop), innerText);\n  });\n\n  if (propTarget) {\n    return {\n      propElement: targetElement,\n      propTarget,\n    };\n  }\n  return null;\n}\n\nfunction equalText(v: any, innerText: string) {\n  // TODO: enhance compare text logic\n  if (typeof v !== 'string') {\n    return false;\n  }\n  return v.trim() === innerText;\n}\n\nexport const liveEditingSaveHander: SaveHandler = {\n  condition: (prop) => {\n    return prop.type === 'expression';\n  },\n  onSaveContent: (content, prop) => {\n    const v = prop.getValue();\n    let data = v;\n    if (isJSExpression(v)) {\n      data = v.mock;\n    }\n    data = content;\n    if (isJSExpression(v)) {\n      prop.setValue({\n        type: 'JSExpression',\n        value: v.value,\n        mock: data,\n      });\n    } else {\n      prop.setValue(data);\n    }\n  },\n};\n// TODO:\n// 非文本编辑\n//  国际化数据，改变当前\n//  JSExpression, 改变 mock 或 弹出绑定变量\n\nLiveEditing.addLiveEditingSpecificRule(liveEditingRule);\nLiveEditing.addLiveEditingSaveHandler(liveEditingSaveHander);\n"
  },
  {
    "path": "packages/engine/src/modules/lowcode-types.ts",
    "content": "export type { IPublicTypeNodeSchema } from '@alilc/lowcode-types';"
  },
  {
    "path": "packages/engine/src/modules/shell-model-factory.ts",
    "content": "import {\n  INode,\n  ISettingField,\n} from '@alilc/lowcode-designer';\nimport { IShellModelFactory, IPublicModelNode } from '@alilc/lowcode-types';\nimport { IPublicModelSettingField } from '../../../types/src/shell/model/setting-field';\nimport {\n  Node,\n  SettingField,\n} from '@alilc/lowcode-shell';\nclass ShellModelFactory implements IShellModelFactory {\n  createNode(node: INode | null | undefined): IPublicModelNode | null {\n    return Node.create(node);\n  }\n  createSettingField(prop: ISettingField): IPublicModelSettingField {\n    return SettingField.create(prop);\n  }\n}\nexport const shellModelFactory = new ShellModelFactory();"
  },
  {
    "path": "packages/engine/src/modules/skeleton-types.ts",
    "content": "import { IPublicTypeWidgetBaseConfig as innerIWidgetBaseConfig } from '@alilc/lowcode-types';\n\nexport type IWidgetBaseConfig = innerIWidgetBaseConfig;\n"
  },
  {
    "path": "packages/engine/src/modules/symbols.ts",
    "content": "import {\n  projectSymbol,\n  documentSymbol,\n  nodeSymbol,\n  nodeChildrenSymbol,\n  designerSymbol,\n  skeletonSymbol,\n  editorSymbol,\n  settingFieldSymbol,\n  settingTopEntrySymbol,\n  designerCabinSymbol,\n  propSymbol,\n  simulatorHostSymbol,\n  skeletonItemSymbol,\n  editorCabinSymbol,\n  skeletonCabinSymbol,\n  simulatorRenderSymbol,\n} from '@alilc/lowcode-shell';\n\nexport default {\n  projectSymbol,\n  documentSymbol,\n  nodeSymbol,\n  nodeChildrenSymbol,\n  skeletonSymbol,\n  editorSymbol,\n  designerSymbol,\n  settingPropEntrySymbol: settingFieldSymbol,\n  settingTopEntrySymbol,\n  designerCabinSymbol,\n  editorCabinSymbol,\n  skeletonCabinSymbol,\n  propSymbol,\n  simulatorHostSymbol,\n  skeletonItemSymbol,\n  simulatorRenderSymbol,\n};\n"
  },
  {
    "path": "packages/engine/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "packages/ignitor/babel.config.js",
    "content": "module.exports = require('../../babel.config');"
  },
  {
    "path": "packages/ignitor/build.json",
    "content": "{\n  \"entry\": {\n    \"AliLowCodeEngine\": \"../engine/src/index.ts\",\n    \"ReactSimulatorRenderer\": \"../react-simulator-renderer/src/index.ts\"\n  },\n  \"vendor\": false,\n  \"devServer\": {\n    \"liveReload\": false,\n    \"hot\": false\n  },\n  \"library\": \"[name]\",\n  \"publicPath\": \"/\",\n  \"externals\": {\n    \"react\": \"var window.React\",\n    \"react-dom\": \"var window.ReactDOM\",\n    \"prop-types\": \"var window.PropTypes\",\n    \"@alifd/next\": \"var window.Next\",\n    \"rax\": \"var window.Rax\",\n    \"@alilc/lowcode-engine\": \"var window.AliLowCodeEngine\",\n    \"@alilc/lowcode-engine-ext\": \"var window.AliLowCodeEngineExt\",\n    \"moment\": \"var moment\",\n    \"lodash\": \"var _\"\n  },\n  \"plugins\": [\n    [\n      \"build-plugin-react-app\"\n    ],\n    [\n      \"build-plugin-fusion\",\n      {\n        \"themePackage\": \"@alifd/theme-lowcode-light\",\n        \"externalNext\": \"umd\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\n          \"zh-cn\"\n        ]\n      }\n    ],\n    \"./build.plugin.js\"\n  ]\n}\n"
  },
  {
    "path": "packages/ignitor/build.plugin.js",
    "content": "const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');\nconst fse = require('fs-extra');\n// read from lerna\nconst lernaConfig = JSON.parse(fse.readFileSync('../../lerna.json', 'utf8'));\nconst { version } = lernaConfig;\n\nmodule.exports = ({ context, onGetWebpackConfig }) => {\n  onGetWebpackConfig((config) => {\n    config.resolve.plugin('tsconfigpaths').use(TsconfigPathsPlugin, [\n      {\n        configFile: './tsconfig.json',\n      },\n    ]);\n    config\n      .plugin('define')\n      .use(context.webpack.DefinePlugin, [{\n        VERSION_PLACEHOLDER: JSON.stringify(version),\n      }]);\n    config.plugins.delete('hot');\n    config.devServer.hot(false);\n    if (context.command === 'start') {\n      config.devtool('inline-source-map');\n    }\n  });\n};\n"
  },
  {
    "path": "packages/ignitor/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  // transform: {\n  //   '^.+\\\\.[jt]sx?$': 'babel-jest',\n  //   // '^.+\\\\.(ts|tsx)$': 'ts-jest',\n  //   // '^.+\\\\.(js|jsx)$': 'babel-jest',\n  // },\n  // testMatch: ['**/node-children.test.ts'],\n  // testMatch: ['**/plugin-manager.test.ts'],\n  // testMatch: ['**/history/history.test.ts'],\n  // testMatch: ['**/document-model.test.ts'],\n  // testMatch: ['**/prop.test.ts'],\n  // testMatch: ['(/tests?/.*(test))\\\\.[jt]s$'],\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  setupFiles: ['./tests/fixtures/unhandled-rejection.ts'],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: false,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    '!src/**/*.d.ts',\n    '!src/icons/**',\n    '!src/locale/**',\n    '!src/builtin-simulator/utils/**',\n    '!src/plugin/sequencify.ts',\n    '!src/document/node/exclusive-group.ts',\n    '!src/document/node/props/value-to-source.ts',\n    '!src/builtin-simulator/live-editing/live-editing.ts',\n    '!src/designer/offset-observer.ts',\n    '!src/designer/clipboard.ts',\n    '!src/designer/scroller.ts',\n    '!src/builtin-simulator/host.ts',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/ignitor/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-ignitor\",\n  \"version\": \"1.3.2\",\n  \"description\": \"点火器，bootstrap lce project\",\n  \"main\": \"lib/index.js\",\n  \"private\": true,\n  \"files\": [\n    \"dist\",\n    \"es\",\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"start\": \"build-scripts start --disable-open --port 5555\"\n  },\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"fs-extra\": \"^10.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/ignitor\"\n  },\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/ignitor/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge,chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>LowCodeEngine Editor DEMO</title>\n  </head>\n  <body>\n    <h1>\n      This project only provides engine resource files. For usage, go for\n      <a href=\"https://github.com/alibaba/lowcode-demo\" target=\"_blank\">Lowcode Demo</a>\n    </h1>\n    <h2>\n      For local debugging of lowcode engine, please visit\n      <a href=\"https://lowcode-engine.cn/site/docs/participate/prepare\" target=\"_blank\">proxy documentation</a>\n      to get more information.\n    </h2>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/ignitor/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-command/README.md",
    "content": "# `@alilc/plugin-command`\n\n> TODO: description\n\n## Usage\n\n```\nconst pluginCommand = require('@alilc/plugin-command');\n\n// TODO: DEMONSTRATE API\n```\n"
  },
  {
    "path": "packages/plugin-command/__tests__/node-command.test.ts",
    "content": "import { checkPropTypes } from '@alilc/lowcode-utils/src/check-prop-types';\nimport { nodeSchemaPropType } from '../src/node-command';\n\ndescribe('nodeSchemaPropType', () => {\n  const componentName = 'NodeComponent';\n  const getPropType = (name: string) => nodeSchemaPropType.value.find(d => d.name === name)?.propType;\n\n  it('should validate the id as a string', () => {\n    const validId = 'node1';\n    const invalidId = 123; // Not a string\n    expect(checkPropTypes(validId, 'id', getPropType('id'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidId, 'id', getPropType('id'), componentName)).toBe(false);\n    // is not required\n    expect(checkPropTypes(undefined, 'id', getPropType('id'), componentName)).toBe(true);\n  });\n\n  it('should validate the componentName as a string', () => {\n    const validComponentName = 'Button';\n    const invalidComponentName = false; // Not a string\n    expect(checkPropTypes(validComponentName, 'componentName', getPropType('componentName'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidComponentName, 'componentName', getPropType('componentName'), componentName)).toBe(false);\n    // isRequired\n    expect(checkPropTypes(undefined, 'componentName', getPropType('componentName'), componentName)).toBe(false);\n  });\n\n  it('should validate the props as an object', () => {\n    const validProps = { key: 'value' };\n    const invalidProps = 'Not an object'; // Not an object\n    expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidProps, 'props', getPropType('props'), componentName)).toBe(false);\n  });\n\n  it('should validate the props as a JSExpression', () => {\n    const validProps = { type: 'JSExpression', value: 'props' };\n    expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true);\n  });\n\n  it('should validate the props as a JSFunction', () => {\n    const validProps = { type: 'JSFunction', value: 'props' };\n    expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true);\n  });\n\n  it('should validate the props as a JSSlot', () => {\n    const validProps = { type: 'JSSlot', value: 'props' };\n    expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true);\n  });\n\n  it('should validate the condition as a bool', () => {\n    const validCondition = true;\n    const invalidCondition = 'Not a bool'; // Not a boolean\n    expect(checkPropTypes(validCondition, 'condition', getPropType('condition'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidCondition, 'condition', getPropType('condition'), componentName)).toBe(false);\n  });\n\n  it('should validate the condition as a JSExpression', () => {\n    const validCondition = { type: 'JSExpression', value: '1 + 1 === 2' };\n    const invalidCondition = { type: 'JSExpression', value: 123 }; // Not a string\n    expect(checkPropTypes(validCondition, 'condition', getPropType('condition'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidCondition, 'condition', getPropType('condition'), componentName)).toBe(false);\n  });\n\n  it('should validate the loop as an array', () => {\n    const validLoop = ['item1', 'item2'];\n    const invalidLoop = 'Not an array'; // Not an array\n    expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false);\n  });\n\n  it('should validate the loop as a JSExpression', () => {\n    const validLoop = { type: 'JSExpression', value: 'items' };\n    const invalidLoop = { type: 'JSExpression', value: 123 }; // Not a string\n    expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false);\n  });\n\n  it('should validate the loopArgs as an array', () => {\n    const validLoopArgs = ['item'];\n    const invalidLoopArgs = 'Not an array'; // Not an array\n    expect(checkPropTypes(validLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(false);\n  });\n\n  it('should validate the loopArgs as a JSExpression', () => {\n    const validLoopArgs = { type: 'JSExpression', value: 'item' };\n    const invalidLoopArgs = { type: 'JSExpression', value: 123 }; // Not a string\n    const validLoopArgs2 = [{ type: 'JSExpression', value: 'item' }, { type: 'JSExpression', value: 'index' }];\n    expect(checkPropTypes(validLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(false);\n    expect(checkPropTypes(validLoopArgs2, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true);\n  });\n\n  it('should validate the children as an array', () => {\n    const validChildren = [{\n      id: 'child1',\n      componentName: 'Button',\n    }, {\n      id: 'child2',\n      componentName: 'Button',\n    }];\n    const invalidChildren = 'Not an array'; // Not an array\n    const invalidChildren2 = [{}]; // Not an valid array\n    expect(checkPropTypes(invalidChildren, 'children', getPropType('children'), componentName)).toBe(false);\n    expect(checkPropTypes(validChildren, 'children', getPropType('children'), componentName)).toBe(true);\n    expect(checkPropTypes(invalidChildren2, 'children', getPropType('children'), componentName)).toBe(false);\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n});\n"
  },
  {
    "path": "packages/plugin-command/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"build-plugin-fusion\",\n    [\"build-plugin-moment-locales\", {\n      \"locales\": [\"zh-cn\"]\n    }]\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-command/build.test.json",
    "content": "{\n  \"plugins\": [\n    [\n      \"@alilc/build-plugin-lce\",\n      {\n        \"filename\": \"editor-preset-vision\",\n        \"library\": \"LowcodeEditor\",\n        \"libraryTarget\": \"umd\",\n        \"externals\": {\n          \"react\": \"var window.React\",\n          \"react-dom\": \"var window.ReactDOM\",\n          \"prop-types\": \"var window.PropTypes\",\n          \"rax\": \"var window.Rax\"\n        }\n      }\n    ],\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-command/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: true,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    'src/**/*.tsx',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/plugin-command/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-plugin-command\",\n  \"version\": \"1.3.2\",\n  \"description\": \"> TODO: description\",\n  \"author\": \"liujuping <liujup@foxmail.com>\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine#readme\",\n  \"license\": \"ISC\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"directories\": {\n    \"lib\": \"lib\",\n    \"test\": \"__tests__\"\n  },\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/alibaba/lowcode-engine.git\"\n  },\n  \"scripts\": {\n    \"test\": \"build-scripts test --config build.test.json --jest-passWithNoTests\",\n    \"build\": \"build-scripts build\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/alibaba/lowcode-engine/issues\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-command/src/history-command.ts",
    "content": "import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-types';\n\nexport const historyCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => {\n  const { command, project } = ctx;\n  return {\n    init() {\n      command.registerCommand({\n        name: 'undo',\n        description: 'Undo the last operation.',\n        handler: () => {\n          const state = project.currentDocument?.history.getState() || 0;\n          const enable = !!(state & 1);\n          if (!enable) {\n            throw new Error('Can not undo.');\n          }\n          project.currentDocument?.history.back();\n        },\n      });\n\n      command.registerCommand({\n        name: 'redo',\n        description: 'Redo the last operation.',\n        handler: () => {\n          const state = project.currentDocument?.history.getState() || 0;\n          const enable = !!(state & 2);\n          if (!enable) {\n            throw new Error('Can not redo.');\n          }\n          project.currentDocument?.history.forward();\n        },\n      });\n    },\n    destroy() {\n      command.unregisterCommand('history:undo');\n      command.unregisterCommand('history:redo');\n    },\n  };\n};\n\nhistoryCommand.pluginName = '___history_command___';\nhistoryCommand.meta = {\n  commandScope: 'history',\n};\n"
  },
  {
    "path": "packages/plugin-command/src/index.ts",
    "content": "import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-types';\nimport { nodeCommand } from './node-command';\nimport { historyCommand } from './history-command';\n\nexport const CommandPlugin: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => {\n  const { plugins } = ctx;\n\n  return {\n    async init() {\n      await plugins.register(nodeCommand, {}, { autoInit: true });\n      await plugins.register(historyCommand, {}, { autoInit: true });\n    },\n    destroy() {\n      plugins.delete(nodeCommand.pluginName);\n      plugins.delete(historyCommand.pluginName);\n    },\n  };\n};\n\nCommandPlugin.pluginName = '___default_command___';\nCommandPlugin.meta = {\n  commandScope: 'common',\n};\n\nexport default CommandPlugin;"
  },
  {
    "path": "packages/plugin-command/src/node-command.ts",
    "content": "import { IPublicModelPluginContext, IPublicTypeNodeSchema, IPublicTypePlugin, IPublicTypePropType } from '@alilc/lowcode-types';\nimport { isNodeSchema } from '@alilc/lowcode-utils';\n\nconst sampleNodeSchema: IPublicTypePropType = {\n  type: 'shape',\n  value: [\n    {\n      name: 'id',\n      propType: 'string',\n    },\n    {\n      name: 'componentName',\n      propType: {\n        type: 'string',\n        isRequired: true,\n      },\n    },\n    {\n      name: 'props',\n      propType: 'object',\n    },\n    {\n      name: 'condition',\n      propType: 'any',\n    },\n    {\n      name: 'loop',\n      propType: 'any',\n    },\n    {\n      name: 'loopArgs',\n      propType: 'any',\n    },\n    {\n      name: 'children',\n      propType: 'any',\n    },\n  ],\n};\n\nexport const nodeSchemaPropType: IPublicTypePropType = {\n  type: 'shape',\n  value: [\n    sampleNodeSchema.value[0],\n    sampleNodeSchema.value[1],\n    {\n      name: 'props',\n      propType: {\n        type: 'objectOf',\n        value: {\n          type: 'oneOfType',\n          // 不会强制校验，更多作为提示\n          value: [\n            'any',\n            {\n              type: 'shape',\n              value: [\n                {\n                  name: 'type',\n                  propType: {\n                    type: 'oneOf',\n                    value: ['JSExpression'],\n                  },\n                },\n                {\n                  name: 'value',\n                  propType: 'string',\n                },\n              ],\n            },\n            {\n              type: 'shape',\n              value: [\n                {\n                  name: 'type',\n                  propType: {\n                    type: 'oneOf',\n                    value: ['JSFunction'],\n                  },\n                },\n                {\n                  name: 'value',\n                  propType: 'string',\n                },\n              ],\n            },\n            {\n              type: 'shape',\n              value: [\n                {\n                  name: 'type',\n                  propType: {\n                    type: 'oneOf',\n                    value: ['JSSlot'],\n                  },\n                },\n                {\n                  name: 'value',\n                  propType: {\n                    type: 'oneOfType',\n                    value: [\n                      sampleNodeSchema,\n                      {\n                        type: 'arrayOf',\n                        value: sampleNodeSchema,\n                      },\n                    ],\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n    },\n    {\n      name: 'condition',\n      propType: {\n        type: 'oneOfType',\n        value: [\n          'bool',\n          {\n            type: 'shape',\n            value: [\n              {\n                name: 'type',\n                propType: {\n                  type: 'oneOf',\n                  value: ['JSExpression'],\n                },\n              },\n              {\n                name: 'value',\n                propType: 'string',\n              },\n            ],\n          },\n        ],\n      },\n    },\n    {\n      name: 'loop',\n      propType: {\n        type: 'oneOfType',\n        value: [\n          'array',\n          {\n            type: 'shape',\n            value: [\n              {\n                name: 'type',\n                propType: {\n                  type: 'oneOf',\n                  value: ['JSExpression'],\n                },\n              },\n              {\n                name: 'value',\n                propType: 'string',\n              },\n            ],\n          },\n        ],\n      },\n    },\n    {\n      name: 'loopArgs',\n      propType: {\n        type: 'oneOfType',\n        value: [\n          {\n            type: 'arrayOf',\n            value: {\n              type: 'oneOfType',\n              value: [\n                'any',\n                {\n                  type: 'shape',\n                  value: [\n                    {\n                      name: 'type',\n                      propType: {\n                        type: 'oneOf',\n                        value: ['JSExpression'],\n                      },\n                    },\n                    {\n                      name: 'value',\n                      propType: 'string',\n                    },\n                  ],\n                },\n              ],\n            },\n          },\n          {\n            type: 'shape',\n            value: [\n              {\n                name: 'type',\n                propType: {\n                  type: 'oneOf',\n                  value: ['JSExpression'],\n                },\n              },\n              {\n                name: 'value',\n                propType: 'string',\n              },\n            ],\n          },\n        ],\n      },\n    },\n    {\n      name: 'children',\n      propType: {\n        type: 'arrayOf',\n        value: sampleNodeSchema,\n      },\n    },\n  ],\n};\n\nexport const nodeCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => {\n  const { command, project } = ctx;\n  return {\n    init() {\n      command.registerCommand({\n        name: 'add',\n        description: 'Add a node to the canvas.',\n        handler: (param: {\n          parentNodeId: string;\n          nodeSchema: IPublicTypeNodeSchema;\n          index: number;\n        }) => {\n          const {\n            parentNodeId,\n            nodeSchema,\n            index,\n          } = param;\n          const { project } = ctx;\n          const parentNode = project.currentDocument?.getNodeById(parentNodeId);\n          if (!parentNode) {\n            throw new Error(`Can not find node '${parentNodeId}'.`);\n          }\n\n          if (!parentNode.isContainerNode) {\n            throw new Error(`Node '${parentNodeId}' is not a container node.`);\n          }\n\n          if (!isNodeSchema(nodeSchema)) {\n            throw new Error('Invalid node.');\n          }\n\n          if (index < 0 || index > (parentNode.children?.size || 0)) {\n            throw new Error(`Invalid index '${index}'.`);\n          }\n\n          project.currentDocument?.insertNode(parentNode, nodeSchema, index);\n        },\n        parameters: [\n          {\n            name: 'parentNodeId',\n            propType: 'string',\n            description: 'The id of the parent node.',\n          },\n          {\n            name: 'nodeSchema',\n            propType: nodeSchemaPropType,\n            description: 'The node to be added.',\n          },\n          {\n            name: 'index',\n            propType: 'number',\n            description: 'The index of the node to be added.',\n          },\n        ],\n      });\n\n      command.registerCommand({\n        name: 'move',\n        description: 'Move a node to another node.',\n        handler(param: {\n          nodeId: string;\n          targetNodeId: string;\n          index: number;\n        }) {\n          const {\n            nodeId,\n            targetNodeId,\n            index = 0,\n          } = param;\n\n          if (!nodeId) {\n            throw new Error('Invalid node id.');\n          }\n\n          if (!targetNodeId) {\n            throw new Error('Invalid target node id.');\n          }\n\n          const node = project.currentDocument?.getNodeById(nodeId);\n          const targetNode = project.currentDocument?.getNodeById(targetNodeId);\n          if (!node) {\n            throw new Error(`Can not find node '${nodeId}'.`);\n          }\n\n          if (!targetNode) {\n            throw new Error(`Can not find node '${targetNodeId}'.`);\n          }\n\n          if (!targetNode.isContainerNode) {\n            throw new Error(`Node '${targetNodeId}' is not a container node.`);\n          }\n\n          if (index < 0 || index > (targetNode.children?.size || 0)) {\n            throw new Error(`Invalid index '${index}'.`);\n          }\n\n          project.currentDocument?.removeNode(node);\n          project.currentDocument?.insertNode(targetNode, node, index);\n        },\n        parameters: [\n          {\n            name: 'nodeId',\n            propType: {\n              type: 'string',\n              isRequired: true,\n            },\n            description: 'The id of the node to be moved.',\n          },\n          {\n            name: 'targetNodeId',\n            propType: {\n              type: 'string',\n              isRequired: true,\n            },\n            description: 'The id of the target node.',\n          },\n          {\n            name: 'index',\n            propType: 'number',\n            description: 'The index of the node to be moved.',\n          },\n        ],\n      });\n\n      command.registerCommand({\n        name: 'remove',\n        description: 'Remove a node from the canvas.',\n        handler(param: {\n          nodeId: string;\n        }) {\n          const {\n            nodeId,\n          } = param;\n\n          const node = project.currentDocument?.getNodeById(nodeId);\n          if (!node) {\n            throw new Error(`Can not find node '${nodeId}'.`);\n          }\n\n          project.currentDocument?.removeNode(node);\n        },\n        parameters: [\n          {\n            name: 'nodeId',\n            propType: 'string',\n            description: 'The id of the node to be removed.',\n          },\n        ],\n      });\n\n      command.registerCommand({\n        name: 'update',\n        description: 'Update a node.',\n        handler(param: {\n          nodeId: string;\n          nodeSchema: IPublicTypeNodeSchema;\n        }) {\n          const {\n            nodeId,\n            nodeSchema,\n          } = param;\n\n          const node = project.currentDocument?.getNodeById(nodeId);\n          if (!node) {\n            throw new Error(`Can not find node '${nodeId}'.`);\n          }\n\n          if (!isNodeSchema(nodeSchema)) {\n            throw new Error('Invalid node.');\n          }\n\n          node.importSchema(nodeSchema);\n        },\n        parameters: [\n          {\n            name: 'nodeId',\n            propType: 'string',\n            description: 'The id of the node to be updated.',\n          },\n          {\n            name: 'nodeSchema',\n            propType: nodeSchemaPropType,\n            description: 'The node to be updated.',\n          },\n        ],\n      });\n\n      command.registerCommand({\n        name: 'updateProps',\n        description: 'Update the properties of a node.',\n        handler(param: {\n          nodeId: string;\n          props: Record<string, any>;\n        }) {\n          const {\n            nodeId,\n            props,\n          } = param;\n\n          const node = project.currentDocument?.getNodeById(nodeId);\n          if (!node) {\n            throw new Error(`Can not find node '${nodeId}'.`);\n          }\n\n          Object.keys(props).forEach(key => {\n            node.setPropValue(key, props[key]);\n          });\n        },\n        parameters: [\n          {\n            name: 'nodeId',\n            propType: 'string',\n            description: 'The id of the node to be updated.',\n          },\n          {\n            name: 'props',\n            propType: 'object',\n            description: 'The properties to be updated.',\n          },\n        ],\n      });\n\n      command.registerCommand({\n        name: 'removeProps',\n        description: 'Remove the properties of a node.',\n        handler(param: {\n          nodeId: string;\n          propNames: string[];\n        }) {\n          const {\n            nodeId,\n            propNames,\n          } = param;\n\n          const node = project.currentDocument?.getNodeById(nodeId);\n          if (!node) {\n            throw new Error(`Can not find node '${nodeId}'.`);\n          }\n\n          propNames.forEach(key => {\n            node.props?.getProp(key)?.remove();\n          });\n        },\n        parameters: [\n          {\n            name: 'nodeId',\n            propType: 'string',\n            description: 'The id of the node to be updated.',\n          },\n          {\n            name: 'propNames',\n            propType: 'array',\n            description: 'The properties to be removed.',\n          },\n        ],\n      });\n    },\n    destroy() {\n      command.unregisterCommand('node:add');\n      command.unregisterCommand('node:move');\n      command.unregisterCommand('node:remove');\n      command.unregisterCommand('node:update');\n      command.unregisterCommand('node:updateProps');\n      command.unregisterCommand('node:removeProps');\n    },\n  };\n};\n\nnodeCommand.pluginName = '___node_command___';\nnodeCommand.meta = {\n  commandScope: 'node',\n};\n\n"
  },
  {
    "path": "packages/plugin-designer/.gitignore",
    "content": "# project custom\nbuild\ndist\npackages/*/lib/\npackages/*/es/\npackages/*/dist/\npackages/*/output/\npackage-lock.json\nyarn.lock\ndeploy-space/packages\ndeploy-space/.env\n\n\n# IDE\n.vscode\n.idea\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\nlib\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# mac config files\n.DS_Store\n\n# codealike\ncodealike.json\n"
  },
  {
    "path": "packages/plugin-designer/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-designer/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-plugin-designer\",\n  \"version\": \"1.3.2\",\n  \"description\": \"alibaba lowcode editor designer plugin\",\n  \"files\": [\n    \"es\",\n    \"lib\"\n  ],\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"stylePath\": \"style.js\",\n  \"scripts\": {\n    \"build\": \"build-scripts build\"\n  },\n  \"keywords\": [\n    \"lowcode\",\n    \"editor\"\n  ],\n  \"author\": \"xiayang.xy\",\n  \"dependencies\": {\n    \"@alilc/lowcode-designer\": \"1.3.2\",\n    \"@alilc/lowcode-editor-core\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"react\": \"^16.8.1\",\n    \"react-dom\": \"^16.8.1\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.3\",\n    \"@types/react\": \"^16.9.13\",\n    \"@types/react-dom\": \"^16.9.4\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/plugin-designer\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/plugin-designer/src/index.scss",
    "content": ".lowcode-plugin-designer {\n  width: 100%;\n  height: 100%;\n}\n"
  },
  {
    "path": "packages/plugin-designer/src/index.tsx",
    "content": "import React, { PureComponent } from 'react';\nimport { Editor, engineConfig } from '@alilc/lowcode-editor-core';\nimport { DesignerView, Designer } from '@alilc/lowcode-designer';\nimport { Asset, getLogger } from '@alilc/lowcode-utils';\nimport './index.scss';\n\nconst logger = getLogger({ level: 'warn', bizName: 'plugin:plugin-designer' });\n\nexport interface PluginProps {\n  engineEditor: Editor;\n}\n\ninterface DesignerPluginState {\n  componentMetadatas?: any[] | null;\n  library?: any[] | null;\n  extraEnvironment?: any[] | null;\n  renderEnv?: string;\n  device?: string;\n  locale?: string;\n  designMode?: string;\n  deviceClassName?: string;\n  simulatorUrl: Asset | null;\n  // @TODO 类型定义\n  requestHandlersMap: any;\n}\n\nexport default class DesignerPlugin extends PureComponent<PluginProps, DesignerPluginState> {\n  static displayName: 'LowcodePluginDesigner';\n\n  state: DesignerPluginState = {\n    componentMetadatas: null,\n    library: null,\n    extraEnvironment: null,\n    renderEnv: 'default',\n    device: 'default',\n    locale: '',\n    designMode: 'live',\n    deviceClassName: '',\n    simulatorUrl: null,\n    requestHandlersMap: null,\n  };\n\n  private _mounted = true;\n\n  constructor(props: any) {\n    super(props);\n    this.setupAssets();\n  }\n\n  private async setupAssets() {\n    const editor = this.props.engineEditor;\n    try {\n      const assets = await editor.onceGot('assets');\n      const renderEnv = engineConfig.get('renderEnv') || editor.get('renderEnv');\n      const device = engineConfig.get('device') || editor.get('device');\n      const locale = engineConfig.get('locale') || editor.get('locale');\n      const designMode = engineConfig.get('designMode') || editor.get('designMode');\n      const deviceClassName = engineConfig.get('deviceClassName') || editor.get('deviceClassName');\n      const simulatorUrl = engineConfig.get('simulatorUrl') || editor.get('simulatorUrl');\n      // @TODO setupAssets 里设置 requestHandlersMap 不太合适\n      const requestHandlersMap = engineConfig.get('requestHandlersMap') || editor.get('requestHandlersMap');\n      if (!this._mounted) {\n        return;\n      }\n      engineConfig.onGot('locale', (locale) => {\n        this.setState({\n          locale,\n        });\n      });\n      engineConfig.onGot('requestHandlersMap', (requestHandlersMap) => {\n        this.setState({\n          requestHandlersMap,\n        });\n      });\n      engineConfig.onGot('device', (device) => {\n        this.setState({\n          device,\n        });\n      });\n      const { components, packages, extraEnvironment, utils } = assets;\n      const state = {\n        componentMetadatas: components || [],\n        library: packages || [],\n        utilsMetadata: utils || [],\n        extraEnvironment,\n        renderEnv,\n        device,\n        designMode,\n        deviceClassName,\n        simulatorUrl,\n        requestHandlersMap,\n        locale,\n      };\n      this.setState(state);\n    } catch (e) {\n      logger.error(e);\n    }\n  }\n\n  componentWillUnmount() {\n    this._mounted = false;\n  }\n\n  private handleDesignerMount = (designer: Designer): void => {\n    const editor = this.props.engineEditor;\n    editor.set('designer', designer);\n    editor.eventBus.emit('designer.ready', designer);\n    editor.onGot('schema', (schema) => {\n      designer.project.open(schema);\n    });\n  };\n\n  render(): React.ReactNode {\n    const editor: Editor = this.props.engineEditor;\n    const {\n      componentMetadatas,\n      utilsMetadata,\n      library,\n      extraEnvironment,\n      renderEnv,\n      device,\n      designMode,\n      deviceClassName,\n      simulatorUrl,\n      requestHandlersMap,\n      locale,\n    } = this.state;\n\n    if (!library || !componentMetadatas) {\n      // TODO: use a Loading\n      return null;\n    }\n\n    return (\n      <DesignerView\n        onMount={this.handleDesignerMount}\n        className=\"lowcode-plugin-designer\"\n        editor={editor}\n        name={editor.viewName}\n        designer={editor.get('designer')}\n        componentMetadatas={componentMetadatas}\n        simulatorProps={{\n          library,\n          utilsMetadata,\n          extraEnvironment,\n          renderEnv,\n          device,\n          locale,\n          designMode,\n          deviceClassName,\n          simulatorUrl,\n          requestHandlersMap,\n        }}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/plugin-designer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/.gitignore",
    "content": "# project custom\nbuild\ndist\npackages/*/lib/\npackages/*/es/\npackages/*/dist/\npackages/*/output/\npackage-lock.json\nyarn.lock\ndeploy-space/packages\ndeploy-space/.env\n\n\n# IDE\n.vscode\n.idea\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\nlib\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# mac config files\n.DS_Store\n\n# codealike\ncodealike.json\n"
  },
  {
    "path": "packages/plugin-outline-pane/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"build-plugin-fusion\",\n    [\"build-plugin-moment-locales\", {\n      \"locales\": [\"zh-cn\"]\n    }]\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-plugin-outline-pane\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Outline pane for Ali lowCode engine\",\n  \"files\": [\n    \"es\",\n    \"lib\"\n  ],\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"scripts\": {\n    \"build\": \"build-scripts build\"\n  },\n  \"dependencies\": {\n    \"@alifd/next\": \"^1.19.16\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"react\": \"^16\",\n    \"react-dom\": \"^16.7.0\",\n    \"ric-shim\": \"^1.0.1\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@types/classnames\": \"^2.2.7\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\",\n    \"@types/react-dom\": \"^16\",\n    \"build-plugin-fusion\": \"^0.1.1\",\n    \"build-plugin-moment-locales\": \"^0.1.0\"\n  },\n  \"license\": \"MIT\",\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/plugin-outline-pane\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/README.md",
    "content": "大纲树\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/controllers/pane-controller.ts",
    "content": "/* eslint-disable max-len */\nimport requestIdleCallback, { cancelIdleCallback } from 'ric-shim';\nimport {\n  uniqueId,\n  isDragNodeObject,\n  isDragAnyObject,\n  isLocationChildrenDetail,\n} from '@alilc/lowcode-utils';\nimport {\n  IPublicModelDragObject,\n  IPublicTypeScrollable,\n  IPublicModelSensor,\n  IPublicTypeLocationChildrenDetail,\n  IPublicTypeLocationDetailType,\n  IPublicModelNode,\n  IPublicModelDropLocation,\n  IPublicModelScroller,\n  IPublicModelScrollTarget,\n  IPublicModelLocateEvent,\n} from '@alilc/lowcode-types';\nimport TreeNode from './tree-node';\nimport { IndentTrack } from '../helper/indent-track';\nimport DwellTimer from '../helper/dwell-timer';\nimport { IOutlinePanelPluginContext, ITreeBoard, TreeMaster } from './tree-master';\n\nexport class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTypeScrollable {\n  private pluginContext: IOutlinePanelPluginContext;\n\n  private treeMaster?: TreeMaster;\n\n  readonly id = uniqueId('outline');\n\n  private indentTrack = new IndentTrack();\n\n  private _sensorAvailable = false;\n\n  /**\n   * @see IPublicModelSensor\n   */\n  get sensorAvailable() {\n    return this._sensorAvailable;\n  }\n\n  private dwell = new DwellTimer((target, event) => {\n    const { canvas, project } = this.pluginContext;\n    const document = project.getCurrentDocument();\n    let index: any;\n    let focus: any;\n    let valid = true;\n    if (target.hasSlots()) {\n      index = null;\n      focus = { type: 'slots' };\n    } else {\n      index = 0;\n      valid = !!document?.checkNesting(target, event.dragObject as any);\n    }\n    canvas.createLocation({\n      target,\n      source: this.id,\n      event,\n      detail: {\n        type: IPublicTypeLocationDetailType.Children,\n        index,\n        focus,\n        valid,\n      },\n    });\n  });\n\n  /**\n   * @see ITreeBoard\n   */\n  readonly at: string | symbol;\n\n  private tryScrollAgain: number | null = null;\n\n  private sensing = false;\n\n  /**\n   * @see IScrollable\n   */\n  get bounds(): DOMRect | null {\n    if (!this._shell) {\n      return null;\n    }\n    return this._shell.getBoundingClientRect();\n  }\n\n  private _scrollTarget?: IPublicModelScrollTarget;\n\n  /**\n   * @see IScrollable\n   */\n  get scrollTarget() {\n    return this._scrollTarget;\n  }\n\n  private scroller?: IPublicModelScroller;\n\n  private _shell: HTMLDivElement | null = null;\n\n  constructor(at: string | symbol, treeMaster: TreeMaster) {\n    this.pluginContext = treeMaster.pluginContext;\n    this.treeMaster = treeMaster;\n    this.at = at;\n    let inited = false;\n    const setup = () => {\n      if (inited) {\n        return false;\n      }\n      inited = true;\n      this.treeMaster?.addBoard(this);\n      const { canvas } = this.pluginContext;\n      canvas.dragon?.addSensor(this);\n      this.scroller = canvas.createScroller(this);\n    };\n\n    setup();\n  }\n\n  /** -------------------- IPublicModelSensor begin -------------------- */\n\n  /**\n   * @see IPublicModelSensor\n   */\n  fixEvent(e: IPublicModelLocateEvent): IPublicModelLocateEvent {\n    if (e.fixed) {\n      return e;\n    }\n\n    const notMyEvent = e.originalEvent.view?.document !== document;\n\n    if (!e.target || notMyEvent) {\n      e.target = document.elementFromPoint(e.canvasX!, e.canvasY!);\n    }\n\n    // documentModel : 目标文档\n    e.documentModel = this.pluginContext.project.getCurrentDocument();\n\n    // 事件已订正\n    e.fixed = true;\n    return e;\n  }\n\n  /**\n   * @see IPublicModelSensor\n   */\n  locate(e: IPublicModelLocateEvent): IPublicModelDropLocation | undefined | null {\n    this.sensing = true;\n    this.scroller?.scrolling(e);\n    const { globalY, dragObject } = e;\n    const nodes = dragObject?.nodes;\n\n    const tree = this.treeMaster?.currentTree;\n    if (!tree || !tree.root || !this._shell) {\n      return null;\n    }\n\n    const operationalNodes = nodes?.filter((node: any) => {\n      const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook;\n      const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node) : true;\n\n      return canMove;\n    });\n\n    // 如果拖拽的是 Node 才需要后面的判断，拖拽 data 不需要\n    if (isDragNodeObject(dragObject) && (!operationalNodes || operationalNodes.length === 0)) {\n      return;\n    }\n\n    const { project, canvas } = this.pluginContext;\n    const document = project.getCurrentDocument();\n    const pos = getPosFromEvent(e, this._shell);\n    const irect = this.getInsertionRect();\n    const originLoc = document?.dropLocation;\n\n    const componentMeta = e.dragObject?.nodes ? e.dragObject.nodes[0].componentMeta : null;\n    if (e.dragObject?.type === 'node' && componentMeta && componentMeta.isModal && document?.focusNode) {\n      return canvas.createLocation({\n        target: document?.focusNode,\n        detail: {\n          type: IPublicTypeLocationDetailType.Children,\n          index: 0,\n          valid: true,\n        },\n        source: this.id,\n        event: e,\n      });\n    }\n\n    if (originLoc\n      && ((pos && pos === 'unchanged') || (irect && globalY >= irect.top && globalY <= irect.bottom))\n      && dragObject) {\n      const loc = originLoc.clone(e);\n      const indented = this.indentTrack.getIndentParent(originLoc, loc);\n      if (indented) {\n        const [parent, index] = indented;\n        if (checkRecursion(parent, dragObject)) {\n          if (tree.getTreeNode(parent).expanded) {\n            this.dwell.reset();\n            return canvas.createLocation({\n              target: parent,\n              source: this.id,\n              event: e,\n              detail: {\n                type: IPublicTypeLocationDetailType.Children,\n                index,\n                valid: document?.checkNesting(parent, e.dragObject as any),\n              },\n            });\n          }\n\n          (originLoc.detail as IPublicTypeLocationChildrenDetail).focus = {\n            type: 'node',\n            node: parent,\n          };\n          // focus try expand go on\n          this.dwell.focus(parent, e);\n        } else {\n          this.dwell.reset();\n        }\n      // FIXME: recreate new location\n      } else if ((originLoc.detail as IPublicTypeLocationChildrenDetail).near) {\n        (originLoc.detail as IPublicTypeLocationChildrenDetail).near = undefined;\n        this.dwell.reset();\n      }\n      return;\n    }\n\n    this.indentTrack.reset();\n\n    if (pos && pos !== 'unchanged') {\n      let treeNode = tree.getTreeNodeById(pos.nodeId);\n      if (treeNode) {\n        let { focusSlots } = pos;\n        let { node } = treeNode;\n        if (isDragNodeObject(dragObject)) {\n          const newNodes = operationalNodes;\n          let i = newNodes?.length;\n          let p: any = node;\n          while (i-- > 0) {\n            if (newNodes[i].contains(p)) {\n              p = newNodes[i].parent;\n            }\n          }\n          if (p !== node) {\n            node = p || document?.focusNode;\n            treeNode = tree.getTreeNode(node);\n            focusSlots = false;\n          }\n        }\n\n        if (focusSlots) {\n          this.dwell.reset();\n          return canvas.createLocation({\n            target: node as IPublicModelNode,\n            source: this.id,\n            event: e,\n            detail: {\n              type: IPublicTypeLocationDetailType.Children,\n              index: null,\n              valid: false,\n              focus: { type: 'slots' },\n            },\n          });\n        }\n\n        if (!treeNode.isRoot()) {\n          const loc = this.getNear(treeNode, e);\n          this.dwell.tryFocus(loc);\n          return loc;\n        }\n      }\n    }\n\n    const loc = this.drillLocate(tree.root, e);\n    this.dwell.tryFocus(loc);\n    return loc;\n  }\n\n  /**\n   * @see IPublicModelSensor\n   */\n  isEnter(e: IPublicModelLocateEvent): boolean {\n    if (!this._shell) {\n      return false;\n    }\n    const rect = this._shell.getBoundingClientRect();\n    return e.globalY >= rect.top && e.globalY <= rect.bottom && e.globalX >= rect.left && e.globalX <= rect.right;\n  }\n\n  /**\n   * @see IPublicModelSensor\n   */\n  deactiveSensor() {\n    this.sensing = false;\n    this.scroller?.cancel();\n    this.dwell.reset();\n    this.indentTrack.reset();\n  }\n\n  /** -------------------- IPublicModelSensor end -------------------- */\n\n  /** -------------------- ITreeBoard begin -------------------- */\n\n  /**\n   * @see ITreeBoard\n   */\n  scrollToNode(treeNode: TreeNode, detail?: any, tryTimes = 0) {\n    if (tryTimes < 1 && this.tryScrollAgain) {\n      cancelIdleCallback(this.tryScrollAgain);\n      this.tryScrollAgain = null;\n    }\n    if (!this.bounds || !this.scroller || !this.scrollTarget) {\n      // is a active sensor\n      return;\n    }\n\n    let rect: ClientRect | undefined;\n    if (detail && isLocationChildrenDetail(detail)) {\n      rect = this.getInsertionRect();\n    } else {\n      rect = this.getTreeNodeRect(treeNode);\n    }\n\n    if (!rect) {\n      if (tryTimes < 3) {\n        this.tryScrollAgain = requestIdleCallback(() => this.scrollToNode(treeNode, detail, tryTimes + 1));\n      }\n      return;\n    }\n    const { scrollHeight, top: scrollTop } = this.scrollTarget;\n    const { height, top, bottom } = this.bounds;\n    if (rect.top < top || rect.bottom > bottom) {\n      const opt: any = {};\n      opt.top = Math.min(rect.top + rect.height / 2 + scrollTop - top - height / 2, scrollHeight - height);\n      if (rect.height >= height) {\n        opt.top = Math.min(scrollTop + rect.top - top, opt.top);\n      }\n      this.scroller.scrollTo(opt);\n    }\n    // make tail scroll be sure\n    if (tryTimes < 4) {\n      this.tryScrollAgain = requestIdleCallback(() => this.scrollToNode(treeNode, detail, 4));\n    }\n  }\n\n  /** -------------------- ITreeBoard end -------------------- */\n\n  private getNear(treeNode: TreeNode, e: IPublicModelLocateEvent, originalIndex?: number, originalRect?: DOMRect) {\n    const { canvas, project } = this.pluginContext;\n    const document = project.getCurrentDocument();\n    const { globalY, dragObject } = e;\n    if (!dragObject) {\n      return null;\n    }\n    // TODO: check dragObject is anyData\n    const { node, expanded } = treeNode;\n    let rect = originalRect;\n    if (!rect) {\n      rect = this.getTreeNodeRect(treeNode);\n      if (!rect) {\n        return null;\n      }\n    }\n    let index = originalIndex;\n    if (index == null) {\n      index = node.index;\n    }\n\n    if (node.isSlotNode) {\n      // 是个插槽根节点\n      if (!treeNode.isContainer() && !treeNode.hasSlots()) {\n        return canvas.createLocation({\n          target: node.parent!,\n          source: this.id,\n          event: e,\n          detail: {\n            type: IPublicTypeLocationDetailType.Children,\n            index: null,\n            near: { node, pos: 'replace' },\n            valid: true, // TODO: future validation the slot limit\n          },\n        });\n      }\n      const loc1 = this.drillLocate(treeNode, e);\n      if (loc1) {\n        return loc1;\n      }\n\n      return canvas.createLocation({\n        target: node.parent!,\n        source: this.id,\n        event: e,\n        detail: {\n          type: IPublicTypeLocationDetailType.Children,\n          index: null,\n          valid: false,\n          focus: { type: 'slots' },\n        },\n      });\n    }\n\n    let focusNode: IPublicModelNode | undefined;\n    // focus\n    if (!expanded && (treeNode.isContainer() || treeNode.hasSlots())) {\n      focusNode = node;\n    }\n\n    // before\n    const titleRect = this.getTreeTitleRect(treeNode) || rect;\n    if (globalY < titleRect.top + titleRect.height / 2) {\n      return canvas.createLocation({\n        target: node.parent!,\n        source: this.id,\n        event: e,\n        detail: {\n          type: IPublicTypeLocationDetailType.Children,\n          index,\n          valid: document?.checkNesting(node.parent!, dragObject as any),\n          near: { node, pos: 'before' },\n          focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined,\n        },\n      });\n    }\n\n    if (globalY > titleRect.bottom) {\n      focusNode = undefined;\n    }\n\n    if (expanded) {\n      // drill\n      const loc = this.drillLocate(treeNode, e);\n      if (loc) {\n        return loc;\n      }\n    }\n\n    // after\n    return canvas.createLocation({\n      target: node.parent!,\n      source: this.id,\n      event: e,\n      detail: {\n        type: IPublicTypeLocationDetailType.Children,\n        index: (index || 0) + 1,\n        valid: document?.checkNesting(node.parent!, dragObject as any),\n        near: { node, pos: 'after' },\n        focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined,\n      },\n    });\n  }\n\n  private drillLocate(treeNode: TreeNode, e: IPublicModelLocateEvent): IPublicModelDropLocation | null {\n    const { canvas, project } = this.pluginContext;\n    const document = project.getCurrentDocument();\n    const { dragObject, globalY } = e;\n    if (!dragObject) {\n      return null;\n    }\n\n    if (!checkRecursion(treeNode.node, dragObject)) {\n      return null;\n    }\n\n    if (isDragAnyObject(dragObject)) {\n      // TODO: future\n      return null;\n    }\n\n    const container = treeNode.node as IPublicModelNode;\n    const detail: IPublicTypeLocationChildrenDetail = {\n      type: IPublicTypeLocationDetailType.Children,\n    };\n    const locationData: any = {\n      target: container,\n      detail,\n      source: this.id,\n      event: e,\n    };\n    const isSlotContainer = treeNode.hasSlots();\n    const isContainer = treeNode.isContainer();\n\n    if (container.isSlotNode && !treeNode.expanded) {\n      // 未展开，直接定位到内部第一个节点\n      if (isSlotContainer) {\n        detail.index = null;\n        detail.focus = { type: 'slots' };\n        detail.valid = false;\n      } else {\n        detail.index = 0;\n        detail.valid = document?.checkNesting(container, dragObject);\n      }\n    }\n\n    let items: TreeNode[] | null = null;\n    let slotsRect: DOMRect | undefined;\n    let focusSlots = false;\n    // isSlotContainer\n    if (isSlotContainer) {\n      slotsRect = this.getTreeSlotsRect(treeNode);\n      if (slotsRect) {\n        if (globalY <= slotsRect.bottom) {\n          focusSlots = true;\n          items = treeNode.slots;\n        } else if (!isContainer) {\n          // 不在 slots 范围，又不是 container 的情况，高亮 slots 区\n          detail.index = null;\n          detail.focus = { type: 'slots' };\n          detail.valid = false;\n          return canvas.createLocation(locationData);\n        }\n      }\n    }\n\n    if (!items && isContainer) {\n      items = treeNode.children;\n    }\n\n    if (!items) {\n      return null;\n    }\n\n    const l = items.length;\n    let index = 0;\n    let before = l < 1;\n    let current: TreeNode | undefined;\n    let currentIndex = index;\n    for (; index < l; index++) {\n      current = items[index];\n      currentIndex = index;\n      const rect = this.getTreeNodeRect(current);\n      if (!rect) {\n        continue;\n      }\n\n      // rect\n      if (globalY < rect.top) {\n        before = true;\n        break;\n      }\n\n      if (globalY > rect.bottom) {\n        continue;\n      }\n\n      const loc = this.getNear(current, e, index, rect);\n      if (loc) {\n        return loc;\n      }\n    }\n\n    if (focusSlots) {\n      detail.focus = { type: 'slots' };\n      detail.valid = false;\n      detail.index = null;\n    } else {\n      if (current) {\n        detail.index = before ? currentIndex : currentIndex + 1;\n        detail.near = { node: current.node, pos: before ? 'before' : 'after' };\n      } else {\n        detail.index = l;\n      }\n      detail.valid = document?.checkNesting(container, dragObject);\n    }\n\n    return canvas.createLocation(locationData);\n  }\n\n  purge() {\n    const { canvas } = this.pluginContext;\n    canvas.dragon?.removeSensor(this);\n    this.treeMaster?.removeBoard(this);\n  }\n\n  mount(shell: HTMLDivElement | null) {\n    if (this._shell === shell) {\n      return;\n    }\n    this._shell = shell;\n    const { canvas, project } = this.pluginContext;\n    if (shell) {\n      this._scrollTarget = canvas.createScrollTarget(shell);\n      this._sensorAvailable = true;\n\n      // check if there is current selection and scroll to it\n      const selection = project.currentDocument?.selection;\n      const topNodes = selection?.getTopNodes(true);\n      const tree = this.treeMaster?.currentTree;\n      if (topNodes && topNodes[0] && tree) {\n        const treeNode = tree.getTreeNodeById(topNodes[0].id);\n        if (treeNode) {\n          // at this moment, it is possible that pane is not ready yet, so\n          // put ui related operations to the next loop\n          setTimeout(() => {\n            tree.setNodeSelected(treeNode.nodeId);\n            this.scrollToNode(treeNode, null, 4);\n          }, 0);\n        }\n      }\n    } else {\n      this._scrollTarget = undefined;\n      this._sensorAvailable = false;\n    }\n  }\n\n  private getInsertionRect(): DOMRect | undefined {\n    if (!this._shell) {\n      return undefined;\n    }\n    return this._shell.querySelector('.insertion')?.getBoundingClientRect();\n  }\n\n  private getTreeNodeRect(treeNode: TreeNode): DOMRect | undefined {\n    if (!this._shell) {\n      return undefined;\n    }\n    return this._shell.querySelector(`.tree-node[data-id=\"${treeNode.nodeId}\"]`)?.getBoundingClientRect();\n  }\n\n  private getTreeTitleRect(treeNode: TreeNode): DOMRect | undefined {\n    if (!this._shell) {\n      return undefined;\n    }\n    return this._shell.querySelector(`.tree-node-title[data-id=\"${treeNode.nodeId}\"]`)?.getBoundingClientRect();\n  }\n\n  private getTreeSlotsRect(treeNode: TreeNode): DOMRect | undefined {\n    if (!this._shell) {\n      return undefined;\n    }\n    return this._shell.querySelector(`.tree-node-slots[data-id=\"${treeNode.nodeId}\"]`)?.getBoundingClientRect();\n  }\n}\n\nfunction checkRecursion(parent: IPublicModelNode | undefined | null, dragObject: IPublicModelDragObject): boolean {\n  if (!parent) {\n    return false;\n  }\n  if (isDragNodeObject(dragObject)) {\n    const { nodes } = dragObject;\n    if (nodes.some((node: IPublicModelNode) => node.contains(parent))) {\n      return false;\n    }\n  }\n  return true;\n}\n\nfunction getPosFromEvent(\n  { target }: IPublicModelLocateEvent,\n  stop: Element,\n): null | 'unchanged' | { nodeId: string; focusSlots: boolean } {\n  if (!target || !stop.contains(target)) {\n    return null;\n  }\n  if (target.matches('.insertion')) {\n    return 'unchanged';\n  }\n  const closest = target.closest('[data-id]');\n  if (!closest || !stop.contains(closest)) {\n    return null;\n  }\n\n  const nodeId = (closest as HTMLDivElement).dataset.id!;\n  return {\n    focusSlots: closest.matches('.tree-node-slots'),\n    nodeId,\n  };\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/controllers/ric-shim.d.ts",
    "content": "declare module 'ric-shim';"
  },
  {
    "path": "packages/plugin-outline-pane/src/controllers/tree-master.ts",
    "content": "import { isLocationChildrenDetail } from '@alilc/lowcode-utils';\nimport { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode, IPublicTypeDisposable, IPublicEnumPluginRegisterLevel } from '@alilc/lowcode-types';\nimport TreeNode from './tree-node';\nimport { Tree } from './tree';\nimport EventEmitter from 'events';\nimport { enUS, zhCN } from '../locale';\nimport { ReactNode } from 'react';\n\nexport interface ITreeBoard {\n  readonly at: string | symbol;\n  scrollToNode(treeNode: TreeNode, detail?: any): void;\n}\n\nenum EVENT_NAMES {\n  pluginContextChanged = 'pluginContextChanged',\n}\n\nexport interface IOutlinePanelPluginContext extends IPublicModelPluginContext {\n  extraTitle?: string;\n  intlNode(id: string, params?: object): ReactNode;\n  intl(id: string, params?: object): string;\n  getLocale(): string;\n}\n\nexport class TreeMaster {\n  pluginContext: IOutlinePanelPluginContext;\n\n  private boards = new Set<ITreeBoard>();\n\n  private treeMap = new Map<string, Tree>();\n\n  private disposeEvents: (IPublicTypeDisposable | undefined)[] = [];\n\n  event = new EventEmitter();\n\n  constructor(pluginContext: IPublicModelPluginContext, readonly options: {\n    extraTitle?: string;\n  }) {\n    this.setPluginContext(pluginContext);\n    const { workspace } = this.pluginContext;\n    this.initEvent();\n    if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) {\n      this.setPluginContext(workspace.window?.currentEditorView);\n      let dispose: IPublicTypeDisposable | undefined;\n      const windowViewTypeChangeEvent = () => {\n        dispose = workspace.window?.onChangeViewType(() => {\n          this.setPluginContext(workspace.window?.currentEditorView);\n        });\n      };\n\n      windowViewTypeChangeEvent();\n\n      workspace.onChangeActiveWindow(() => {\n        this.setPluginContext(workspace.window?.currentEditorView);\n        dispose && dispose();\n        windowViewTypeChangeEvent();\n      });\n    }\n  }\n\n  private setPluginContext(pluginContext: IPublicModelPluginContext | undefined | null) {\n    if (!pluginContext) {\n      return;\n    }\n    const { intl, intlNode, getLocale } = pluginContext.common.utils.createIntl({\n      'en-US': enUS,\n      'zh-CN': zhCN,\n    });\n    let _pluginContext: IOutlinePanelPluginContext = Object.assign(pluginContext, {\n      intl,\n      intlNode,\n      getLocale,\n    });\n    _pluginContext.extraTitle = this.options && this.options['extraTitle'];\n    this.pluginContext = _pluginContext;\n    this.disposeEvent();\n    this.initEvent();\n    this.emitPluginContextChange();\n  }\n\n  private disposeEvent() {\n    this.disposeEvents.forEach(d => {\n      d && d();\n    });\n  }\n\n  private initEvent() {\n    let startTime: any;\n    const { event, project, canvas } = this.pluginContext;\n    const setExpandByActiveTracker = (target: IPublicTypeActiveTarget) => {\n      const { node, detail } = target;\n      const tree = this.currentTree;\n      if (!tree/* || node.document !== tree.document */) {\n        return;\n      }\n      const treeNode = tree.getTreeNode(node);\n      if (detail && isLocationChildrenDetail(detail)) {\n        treeNode.expand(true);\n      } else {\n        treeNode.expandParents();\n      }\n      this.boards.forEach((board) => {\n        board.scrollToNode(treeNode, detail);\n      });\n    };\n    this.disposeEvents = [\n      canvas.dragon?.onDragstart(() => {\n        startTime = Date.now() / 1000;\n        // needs?\n        this.toVision();\n      }),\n      canvas.activeTracker?.onChange(setExpandByActiveTracker),\n      canvas.dragon?.onDragend(() => {\n        const endTime: any = Date.now() / 1000;\n        const nodes = project.currentDocument?.selection?.getNodes();\n        event.emit('outlinePane.dragend', {\n          selected: nodes\n            ?.map((n) => {\n              if (!n) {\n                return;\n              }\n              const npm = n?.componentMeta?.npm;\n              return (\n                [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || n?.componentMeta?.componentName\n              );\n            })\n            .join('&'),\n          time: (endTime - startTime).toFixed(2),\n        });\n      }),\n      project.onRemoveDocument((data: {id: string}) => {\n        const { id } = data;\n        this.treeMap.delete(id);\n      }),\n    ];\n    if (canvas.activeTracker?.target) {\n      setExpandByActiveTracker(canvas.activeTracker?.target);\n    }\n  }\n\n  private toVision() {\n    const tree = this.currentTree;\n    if (tree) {\n      const selection = this.pluginContext.project.getCurrentDocument()?.selection;\n      selection?.getTopNodes().forEach((node: IPublicModelNode) => {\n        tree.getTreeNode(node).setExpanded(false);\n      });\n    }\n  }\n\n  addBoard(board: ITreeBoard) {\n    this.boards.add(board);\n  }\n\n  removeBoard(board: ITreeBoard) {\n    this.boards.delete(board);\n  }\n\n  purge() {\n    // todo others purge\n  }\n\n  onPluginContextChange(fn: () => void) {\n    this.event.on(EVENT_NAMES.pluginContextChanged, fn);\n  }\n\n  emitPluginContextChange() {\n    this.event.emit(EVENT_NAMES.pluginContextChanged);\n  }\n\n  get currentTree(): Tree | null {\n    const doc = this.pluginContext.project.getCurrentDocument();\n    if (doc) {\n      const { id } = doc;\n      if (this.treeMap.has(id)) {\n        return this.treeMap.get(id)!;\n      }\n      const tree = new Tree(this);\n      this.treeMap.set(id, tree);\n      return tree;\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/controllers/tree-node.ts",
    "content": "import {\n  IPublicTypeTitleContent,\n  IPublicTypeLocationChildrenDetail,\n  IPublicModelNode,\n  IPublicTypeDisposable,\n} from '@alilc/lowcode-types';\nimport { isI18nData, isLocationChildrenDetail, uniqueId } from '@alilc/lowcode-utils';\nimport EventEmitter from 'events';\nimport { Tree } from './tree';\nimport { IOutlinePanelPluginContext } from './tree-master';\n\n/**\n * 大纲树过滤结果\n */\nexport interface FilterResult {\n  // 过滤条件是否生效\n  filterWorking: boolean;\n  // 命中子节点\n  matchChild: boolean;\n  // 命中本节点\n  matchSelf: boolean;\n  // 关键字\n  keywords: string;\n}\n\nenum EVENT_NAMES {\n  filterResultChanged = 'filterResultChanged',\n\n  expandedChanged = 'expandedChanged',\n\n  hiddenChanged = 'hiddenChanged',\n\n  lockedChanged = 'lockedChanged',\n\n  titleLabelChanged = 'titleLabelChanged',\n\n  expandableChanged = 'expandableChanged',\n\n  conditionChanged = 'conditionChanged',\n}\n\nexport default class TreeNode {\n  readonly pluginContext: IOutlinePanelPluginContext;\n  event = new EventEmitter();\n\n  private _node: IPublicModelNode;\n\n  readonly tree: Tree;\n\n  private _filterResult: FilterResult = {\n    filterWorking: false,\n    matchChild: false,\n    matchSelf: false,\n    keywords: '',\n  };\n\n  /**\n   * 默认为折叠状态\n   * 在初始化根节点时，设置为展开状态\n   */\n  private _expanded = false;\n\n  id = uniqueId('treeNode');\n\n  get nodeId(): string {\n    return this.node.id;\n  }\n\n  /**\n   * 是否可以展开\n   */\n  get expandable(): boolean {\n    if (this.locked) return false;\n    return this.hasChildren() || this.hasSlots() || this.dropDetail?.index != null;\n  }\n\n  get expanded(): boolean {\n    return this.isRoot(true) || (this.expandable && this._expanded);\n  }\n\n  /**\n   * 插入\"线\"位置信息\n   */\n  get dropDetail(): IPublicTypeLocationChildrenDetail | undefined | null {\n    const loc = this.pluginContext.project.getCurrentDocument()?.dropLocation;\n    return loc && this.isResponseDropping() && isLocationChildrenDetail(loc.detail) ? loc.detail : null;\n  }\n\n  get depth(): number {\n    return this.node.zLevel;\n  }\n\n  get detecting() {\n    const doc = this.pluginContext.project.currentDocument;\n    return !!(doc?.isDetectingNode(this.node));\n  }\n\n  get hidden(): boolean {\n    const cv = this.node.isConditionalVisible();\n    if (cv == null) {\n      return !this.node.visible;\n    }\n    return !cv;\n  }\n\n  get locked(): boolean {\n    return this.node.isLocked;\n  }\n\n  get selected(): boolean {\n    // TODO: check is dragging\n    const selection = this.pluginContext.project.getCurrentDocument()?.selection;\n    if (!selection) {\n      return false;\n    }\n    return selection?.has(this.node.id);\n  }\n\n  get title(): IPublicTypeTitleContent {\n    return this.node.title;\n  }\n\n  get titleLabel() {\n    let { title } = this;\n    if (!title) {\n      return '';\n    }\n    if ((title as any).label) {\n      title = (title as any).label;\n    }\n    if (typeof title === 'string') {\n      return title;\n    }\n    if (isI18nData(title)) {\n      const currentLocale = this.pluginContext.getLocale();\n      const currentTitle = title[currentLocale];\n      return currentTitle;\n    }\n    return this.node.componentName;\n  }\n\n  get icon() {\n    return this.node.componentMeta?.icon;\n  }\n\n  get parent(): TreeNode | null {\n    const { parent } = this.node;\n    if (parent) {\n      return this.tree.getTreeNode(parent);\n    }\n    return null;\n  }\n\n  get slots(): TreeNode[] {\n    // todo: shallowEqual\n    return this.node.slots.map((node) => this.tree.getTreeNode(node));\n  }\n\n  get condition(): boolean {\n    return this.node.hasCondition() && !this.node.conditionGroup;\n  }\n\n  get children(): TreeNode[] | null {\n    return this.node.children?.map((node) => this.tree.getTreeNode(node)) || null;\n  }\n\n  get node(): IPublicModelNode {\n    return this._node;\n  }\n\n  constructor(tree: Tree, node: IPublicModelNode) {\n    this.tree = tree;\n    this.pluginContext = tree.pluginContext;\n    this._node = node;\n  }\n\n  setLocked(flag: boolean) {\n    this.node.lock(flag);\n    this.event.emit(EVENT_NAMES.lockedChanged, flag);\n  }\n  deleteNode(node: IPublicModelNode) {\n    node && node.remove();\n  }\n  onFilterResultChanged(fn: () => void): IPublicTypeDisposable {\n    this.event.on(EVENT_NAMES.filterResultChanged, fn);\n    return () => {\n      this.event.off(EVENT_NAMES.filterResultChanged, fn);\n    };\n  }\n  onExpandedChanged(fn: (expanded: boolean) => void): IPublicTypeDisposable {\n    this.event.on(EVENT_NAMES.expandedChanged, fn);\n    return () => {\n      this.event.off(EVENT_NAMES.expandedChanged, fn);\n    };\n  }\n  onHiddenChanged(fn: (hidden: boolean) => void): IPublicTypeDisposable {\n    this.event.on(EVENT_NAMES.hiddenChanged, fn);\n    return () => {\n      this.event.off(EVENT_NAMES.hiddenChanged, fn);\n    };\n  }\n  onLockedChanged(fn: (locked: boolean) => void): IPublicTypeDisposable {\n    this.event.on(EVENT_NAMES.lockedChanged, fn);\n    return () => {\n      this.event.off(EVENT_NAMES.lockedChanged, fn);\n    };\n  }\n\n  onTitleLabelChanged(fn: (treeNode: TreeNode) => void): IPublicTypeDisposable {\n    this.event.on(EVENT_NAMES.titleLabelChanged, fn);\n\n    return () => {\n      this.event.off(EVENT_NAMES.titleLabelChanged, fn);\n    };\n  }\n\n  onConditionChanged(fn: (treeNode: TreeNode) => void): IPublicTypeDisposable {\n    this.event.on(EVENT_NAMES.conditionChanged, fn);\n\n    return () => {\n      this.event.off(EVENT_NAMES.conditionChanged, fn);\n    };\n  }\n\n  onExpandableChanged(fn: (expandable: boolean) => void): IPublicTypeDisposable {\n    this.event.on(EVENT_NAMES.expandableChanged, fn);\n    return () => {\n      this.event.off(EVENT_NAMES.expandableChanged, fn);\n    };\n  }\n\n  /**\n   * 触发 onExpandableChanged 回调\n   */\n  notifyExpandableChanged(): void {\n    this.event.emit(EVENT_NAMES.expandableChanged, this.expandable);\n  }\n\n  notifyTitleLabelChanged(): void {\n    this.event.emit(EVENT_NAMES.titleLabelChanged, this.title);\n  }\n\n  notifyConditionChanged(): void {\n    this.event.emit(EVENT_NAMES.conditionChanged, this.condition);\n  }\n\n  setHidden(flag: boolean) {\n    if (this.node.conditionGroup) {\n      return;\n    }\n    if (this.node.visible !== !flag) {\n      this.node.visible = !flag;\n    }\n    this.event.emit(EVENT_NAMES.hiddenChanged, flag);\n  }\n\n  isFocusingNode(): boolean {\n    const loc = this.pluginContext.project.getCurrentDocument()?.dropLocation;\n    if (!loc) {\n      return false;\n    }\n    return (\n      isLocationChildrenDetail(loc.detail) && loc.detail.focus?.type === 'node' && loc.detail?.focus?.node.id === this.nodeId\n    );\n  }\n\n  setExpanded(value: boolean) {\n    this._expanded = value;\n    this.event.emit(EVENT_NAMES.expandedChanged, value);\n  }\n\n  isRoot(includeOriginalRoot = false) {\n    const rootNode = this.pluginContext.project.getCurrentDocument()?.root;\n    return this.tree.root === this || (includeOriginalRoot && rootNode === this.node);\n  }\n\n  /**\n   * 是否是响应投放区\n   */\n  isResponseDropping(): boolean {\n    const loc = this.pluginContext.project.getCurrentDocument()?.dropLocation;\n    if (!loc) {\n      return false;\n    }\n    return loc.target?.id === this.nodeId;\n  }\n\n  setTitleLabel(label: string) {\n    const origLabel = this.titleLabel;\n    if (label === origLabel) {\n      return;\n    }\n    if (label === '') {\n      this.node.getExtraProp('title', false)?.remove();\n    } else {\n      this.node.getExtraProp('title', true)?.setValue(label);\n    }\n    this.event.emit(EVENT_NAMES.titleLabelChanged, this);\n  }\n\n  /**\n   * 是否是容器，允许子节点拖入\n   */\n  isContainer(): boolean {\n    return this.node.isContainerNode;\n  }\n\n  /**\n   * 判断是否有\"插槽\"\n   */\n  hasSlots(): boolean {\n    return this.node.hasSlots();\n  }\n\n  hasChildren(): boolean {\n    return !!(this.isContainer() && this.node.children?.notEmptyNode);\n  }\n\n  select(isMulti: boolean) {\n    const { node } = this;\n\n    const selection = this.pluginContext.project.getCurrentDocument()?.selection;\n    if (isMulti) {\n      selection?.add(node.id);\n    } else {\n      selection?.select(node.id);\n    }\n  }\n\n  /**\n   * 展开节点，支持依次展开父节点\n   */\n  expand(tryExpandParents = false) {\n    // 这边不能直接使用 expanded，需要额外判断是否可以展开\n    // 如果只使用 expanded，会漏掉不可以展开的情况，即在不可以展开的情况下，会触发展开\n    if (this.expandable && !this._expanded) {\n      this.setExpanded(true);\n    }\n    if (tryExpandParents) {\n      this.expandParents();\n    }\n  }\n\n  expandParents() {\n    let p = this.node.parent;\n    while (p) {\n      this.tree.getTreeNode(p).setExpanded(true);\n      p = p.parent;\n    }\n  }\n\n  setNode(node: IPublicModelNode) {\n    if (this._node !== node) {\n      this._node = node;\n    }\n  }\n\n  get filterReult(): FilterResult {\n    return this._filterResult;\n  }\n\n  setFilterReult(val: FilterResult) {\n    this._filterResult = val;\n    this.event.emit(EVENT_NAMES.filterResultChanged);\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/controllers/tree.ts",
    "content": "import TreeNode from './tree-node';\nimport { IPublicModelNode, IPublicTypePropChangeOptions } from '@alilc/lowcode-types';\nimport { IOutlinePanelPluginContext, TreeMaster } from './tree-master';\n\nexport class Tree {\n  private treeNodesMap = new Map<string, TreeNode>();\n\n  readonly id: string | undefined;\n\n  readonly pluginContext: IOutlinePanelPluginContext;\n\n  get root(): TreeNode | null {\n    if (this.pluginContext.project.currentDocument?.focusNode) {\n      return this.getTreeNode(this.pluginContext.project.currentDocument.focusNode!);\n    }\n    return null;\n  }\n\n  readonly treeMaster: TreeMaster;\n\n  constructor(treeMaster: TreeMaster) {\n    this.treeMaster = treeMaster;\n    this.pluginContext = treeMaster.pluginContext;\n    const doc = this.pluginContext.project.currentDocument;\n    this.id = doc?.id;\n\n    doc?.onChangeNodeChildren((info: {node: IPublicModelNode }) => {\n      const { node } = info;\n      const treeNode = this.getTreeNodeById(node.id);\n      treeNode?.notifyExpandableChanged();\n    });\n\n    doc?.history.onChangeCursor(() => {\n      this.root?.notifyExpandableChanged();\n    });\n\n    doc?.onChangeNodeProp((info: IPublicTypePropChangeOptions) => {\n      const { node, key } = info;\n      if (key === '___title___') {\n        const treeNode = this.getTreeNodeById(node.id);\n        treeNode?.notifyTitleLabelChanged();\n      } else if (key === '___condition___') {\n        const treeNode = this.getTreeNodeById(node.id);\n        treeNode?.notifyConditionChanged();\n      }\n    });\n\n    doc?.onChangeNodeVisible((node: IPublicModelNode, visible: boolean) => {\n      const treeNode = this.getTreeNodeById(node.id);\n      treeNode?.setHidden(!visible);\n    });\n\n    doc?.onImportSchema(() => {\n      this.treeNodesMap = new Map<string, TreeNode>();\n    });\n  }\n\n  setNodeSelected(nodeId: string): void {\n    // 目标节点选中，其他节点展开\n    const treeNode = this.treeNodesMap.get(nodeId);\n    if (!treeNode) {\n      return;\n    }\n    this.expandAllAncestors(treeNode);\n  }\n\n  getTreeNode(node: IPublicModelNode): TreeNode {\n    if (this.treeNodesMap.has(node.id)) {\n      const tnode = this.treeNodesMap.get(node.id)!;\n      tnode.setNode(node);\n      return tnode;\n    }\n\n    const treeNode = new TreeNode(this, node);\n    this.treeNodesMap.set(node.id, treeNode);\n    return treeNode;\n  }\n\n  getTreeNodeById(id: string) {\n    return this.treeNodesMap.get(id);\n  }\n\n  expandAllAncestors(treeNode: TreeNode | undefined | null) {\n    if (!treeNode) {\n      return;\n    }\n    if (treeNode.isRoot()) {\n      return;\n    }\n    const ancestors = [];\n    let currentNode: TreeNode | null | undefined = treeNode;\n    while (!treeNode.isRoot()) {\n      currentNode = currentNode?.parent;\n      if (currentNode) {\n        ancestors.unshift(currentNode);\n      } else {\n        break;\n      }\n    }\n    ancestors.forEach((ancestor) => {\n      ancestor.setExpanded(true);\n    });\n  }\n\n  expandAllDecendants(treeNode: TreeNode | undefined | null) {\n    if (!treeNode) {\n      return;\n    }\n    treeNode.setExpanded(true);\n    const children = treeNode && treeNode.children;\n    if (children) {\n      children.forEach((child) => {\n        this.expandAllDecendants(child);\n      });\n    }\n  }\n\n  collapseAllDecendants(treeNode: TreeNode | undefined | null): void {\n    if (!treeNode) {\n      return;\n    }\n    treeNode.setExpanded(false);\n    const children = treeNode && treeNode.children;\n    if (children) {\n      children.forEach((child) => {\n        this.collapseAllDecendants(child);\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/helper/consts.ts",
    "content": "export const BackupPaneName = 'outline-backup-pane';\nexport const MasterPaneName = 'outline-master-pane';"
  },
  {
    "path": "packages/plugin-outline-pane/src/helper/dwell-timer.ts",
    "content": "import { isLocationChildrenDetail } from '@alilc/lowcode-utils';\nimport { IPublicModelNode, IPublicModelDropLocation, IPublicModelLocateEvent } from '@alilc/lowcode-types';\n\n\n/**\n * 停留检查计时器\n */\nexport default class DwellTimer {\n  private timer: number | undefined;\n\n  private previous?: IPublicModelNode;\n\n  private event?: IPublicModelLocateEvent;\n\n  private decide: (node: IPublicModelNode, event: IPublicModelLocateEvent) => void;\n\n  private timeout = 500;\n\n  constructor(decide: (node: IPublicModelNode, event: IPublicModelLocateEvent) => void, timeout = 500) {\n    this.decide = decide;\n    this.timeout = timeout;\n  }\n\n  focus(node: IPublicModelNode, event: IPublicModelLocateEvent) {\n    this.event = event;\n    if (this.previous === node) {\n      return;\n    }\n    this.reset();\n    this.previous = node;\n    this.timer = setTimeout(() => {\n      this.previous && this.decide(this.previous, this.event!);\n      this.reset();\n    }, this.timeout) as any;\n  }\n\n  tryFocus(loc?: IPublicModelDropLocation | null) {\n    if (!loc || !isLocationChildrenDetail(loc.detail)) {\n      this.reset();\n      return;\n    }\n    if (loc.detail.focus?.type === 'node') {\n      this.focus(loc.detail.focus.node, loc.event);\n    } else {\n      this.reset();\n    }\n  }\n\n  reset() {\n    if (this.timer) {\n      clearTimeout(this.timer);\n      this.timer = undefined;\n    }\n\n    this.previous = undefined;\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/helper/indent-track.ts",
    "content": "import { isLocationChildrenDetail } from '@alilc/lowcode-utils';\nimport { IPublicModelDropLocation, IPublicModelNode } from '@alilc/lowcode-types';\n\n\nconst IndentSensitive = 15;\nexport class IndentTrack {\n  private indentStart: number | null = null;\n\n  reset() {\n    this.indentStart = null;\n  }\n\n  // eslint-disable-next-line max-len\n  getIndentParent(lastLoc: IPublicModelDropLocation, loc: IPublicModelDropLocation): [IPublicModelNode, number | undefined] | null {\n    if (\n      lastLoc.target !== loc.target ||\n      !isLocationChildrenDetail(lastLoc.detail) ||\n      !isLocationChildrenDetail(loc.detail) ||\n      lastLoc.source !== loc.source ||\n      lastLoc.detail.index !== loc.detail.index ||\n      loc.detail.index == null\n    ) {\n      this.indentStart = null;\n      return null;\n    }\n    if (this.indentStart == null) {\n      this.indentStart = lastLoc.event.globalX;\n    }\n    const delta = loc.event.globalX - this.indentStart;\n    const indent = Math.floor(Math.abs(delta) / IndentSensitive);\n    if (indent < 1) {\n      return null;\n    }\n    this.indentStart = loc.event.globalX;\n    const direction = delta < 0 ? 'left' : 'right';\n\n    let parent: IPublicModelNode = loc.target;\n    const { index } = loc.detail;\n\n    if (direction === 'left') {\n      if (!parent.parent || index < (parent.children?.size || 0) || parent.isSlotNode) {\n        return null;\n      }\n      return [(parent as any).parent, parent.index + 1];\n    } else {\n      if (index === 0) {\n        return null;\n      }\n      parent = parent.children?.get(index - 1) as any;\n      if (parent && parent.isContainerNode) {\n        return [parent, parent.children?.size];\n      }\n    }\n\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/arrow-right.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconArrowRight(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M512.002047 771.904425c-10.152221 0.518816-20.442588-2.800789-28.202319-10.598382L77.902254 315.937602c-14.548344-14.618952-14.548344-38.318724 0-52.933583 14.544251-14.614859 38.118156-14.614859 52.662407 0l381.437385 418.531212L893.432269 263.004019c14.544251-14.614859 38.125319-14.614859 52.662407 0 14.552437 14.614859 14.552437 38.314631 0 52.933583L540.205389 761.307066C532.451798 769.103636 522.158361 772.424264 512.002047 771.904425z\" />\n    </SVGIcon>\n  );\n}\n\nIconArrowRight.displayName = 'IconArrowRight';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/cond.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconCond(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M479.552 276.544l296.896 2.752v75.712L960 249.024l-183.552-106.048v92.48h-271.36l-46.656-2.752-190.784 203.648 30.976 30.976 180.928-190.784z m296.896 484.928l-253.056-2.816-262.976-263.04H64v43.904h175.296l262.912 262.976 274.176 2.816v75.712L960 774.976l-183.616-105.984 0.064 92.48z\" />\n    </SVGIcon>\n  );\n}\n\nIconCond.displayName = 'IconCond';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/delete.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconDelete(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M224 256v639.84A64 64 0 0 0 287.84 960h448.32A64 64 0 0 0 800 895.84V256h64a32 32 0 1 0 0-64H160a32 32 0 1 0 0 64h64zM384 96c0-17.664 14.496-32 31.904-32h192.192C625.696 64 640 78.208 640 96c0 17.664-14.496 32-31.904 32H415.904A31.872 31.872 0 0 1 384 96z m-96 191.744C288 270.208 302.4 256 320.224 256h383.552C721.6 256 736 270.56 736 287.744v576.512C736 881.792 721.6 896 703.776 896H320.224A32.224 32.224 0 0 1 288 864.256V287.744zM352 352c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z m128 0c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z m128 0c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z\" />\n    </SVGIcon>\n  );\n}\n\nIconDelete.displayName = 'IconDelete';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/eye-close.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconEyeClose(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M512.7 700.9c-102.1 0-184.9-82.8-184.9-184.9 0-28.6 6.5-55.6 18-79.7l-93.7-93.7C138.9 418.1 65.2 514 65.2 514s200.4 260.7 447.6 260.7c50.2 0 98.6-10.8 143.6-27.9l-63.9-63.9c-24.2 11.5-51.2 18-79.8 18z\" />\n      <path d=\"M960.3 514S759.9 253.3 512.7 253.3c-49.5 0-97.2 10.5-141.7 27.2L243.5 153.1l-45.3 45.3 262.3 262.2c-13.1 13.3-21.2 31.5-21.2 51.6 0 40.6 32.9 73.4 73.4 73.4 20.1 0 38.4-8.1 51.6-21.2l260.9 260.8 45.3-45.3-95.6-95.6C887.2 609.1 960.3 514 960.3 514z m-376.7-20.9c-6.8-25.2-26.6-45.1-51.9-51.9L437.5 347c23-10.3 48.5-16 75.3-16 102.1 0 184.9 82.8 184.9 184.9 0 26.8-5.7 52.2-15.9 75.2l-98.2-98z\" />\n    </SVGIcon>\n  );\n}\n\nIconEyeClose.displayName = 'IconEyeClose';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/eye.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconEye(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M512 256c-163.8 0-291.4 97.6-448 256 134.8 135.4 248 256 448 256 199.8 0 346.8-152.8 448-253.2C856.4 397.2 709.6 256 512 256z m0 438.6c-98.8 0-179.2-82-179.2-182.6 0-100.8 80.4-182.6 179.2-182.6s179.2 82 179.2 182.6c0 100.8-80.4 182.6-179.2 182.6z\" />\n      <path d=\"M512 448c0-15.8 5.8-30.2 15.2-41.4-5-0.8-10-1.2-15.2-1.2-57.6 0-104.6 47.8-104.6 106.6s47 106.6 104.6 106.6 104.6-47.8 104.6-106.6c0-4.6-0.4-9.2-0.8-13.8-11 8.6-24.6 13.8-39.6 13.8-35.6 0-64.2-28.6-64.2-64z\" />\n    </SVGIcon>\n  );\n}\n\nIconEye.displayName = 'IconEye';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/filter.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconFilter(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M911.457097 168.557714a35.986286 35.986286 0 0 1-8.009143 40.009143L621.73824 490.276571V914.285714c0 14.848-9.142857 28.013714-22.272 33.718857A42.349714 42.349714 0 0 1 585.166811 950.857143a34.084571 34.084571 0 0 1-25.709714-10.861714l-146.285714-146.285715A36.425143 36.425143 0 0 1 402.309669 768v-277.723429L120.599954 208.566857a35.986286 35.986286 0 0 1-8.009143-40.009143C118.295954 155.428571 131.461669 146.285714 146.309669 146.285714h731.428571c14.848 0 28.013714 9.142857 33.718857 22.272z\" fill=\"#666\" p-id=\"2025\" />\n    </SVGIcon>\n  );\n}\n\nIconFilter.displayName = 'IconFilter';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/index.ts",
    "content": "export * from './lock';\nexport * from './unlock';\nexport * from './arrow-right';\nexport * from './cond';\nexport * from './eye-close';\nexport * from './eye';\nexport * from './filter';\nexport * from './loop';\nexport * from './radio-active';\nexport * from './radio';\nexport * from './setting';\nexport * from './delete';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/lock.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconLock(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM540 701v53c0 4.4-3.6 8-8 8h-40c-4.4 0-8-3.6-8-8v-53c-12.1-8.7-20-22.9-20-39 0-26.5 21.5-48 48-48s48 21.5 48 48c0 16.1-7.9 30.3-20 39z m152-237H332V240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224z\" />\n    </SVGIcon>\n  );\n}\n\nIconLock.displayName = 'IconLock';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/loop.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconLoop(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M60.235294 542.117647c0 132.879059 103.062588 240.941176 229.677176 240.941176l0 60.235294c-159.864471 0-289.912471-135.107765-289.912471-301.176471s130.048-301.176471 289.912471-301.176471l254.735059 0-99.147294-99.147294 42.586353-42.586353 171.911529 171.851294-171.851294 171.911529-42.646588-42.646588 99.207529-99.147294-254.795294 0c-126.614588 0-229.677176 108.062118-229.677176 240.941176zM734.087529 240.941176l0 60.235294c126.614588 0 229.677176 108.062118 229.677176 240.941176s-103.062588 240.941176-229.677176 240.941176l-254.795294 0 99.147294-99.147294-42.586353-42.586353-171.851294 171.851294 171.911529 171.911529 42.586353-42.586353-99.207529-99.207529 254.735059 0c159.924706 0 289.972706-135.107765 289.972706-301.176471s-130.048-301.176471-289.912471-301.176471z\" />\n    </SVGIcon>\n  );\n}\n\nIconLoop.displayName = 'IconLoop';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/outline.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconOutline(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M128 96h512a64 64 0 0 1 64 64v64a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V160a64 64 0 0 1 64-64z m32 64a32 32 0 1 0 0 64h448a32 32 0 0 0 0-64H160z m224 576h512a64 64 0 0 1 64 64v64a64 64 0 0 1-64 64H384a64 64 0 0 1-64-64v-64a64 64 0 0 1 64-64z m32 64a32 32 0 0 0 0 64h448a32 32 0 0 0 0-64H416z m-32-384h512a64 64 0 0 1 64 64v64a64 64 0 0 1-64 64H384a64 64 0 0 1-64-64v-64a64 64 0 0 1 64-64z m32 64a32 32 0 0 0 0 64h448a32 32 0 0 0 0-64H416z\" />\n    </SVGIcon>\n  );\n}\n\nIconOutline.displayName = 'IconOutline';\n\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/radio-active.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconRadioActive(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024z m0-256a256 256 0 1 0 0-512 256 256 0 0 0 0 512z\" />\n    </SVGIcon>\n  );\n}\n\nIconRadioActive.displayName = 'IconRadioActive';\n\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/radio.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconRadio(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024z m0-64A448 448 0 1 0 512 64a448 448 0 0 0 0 896z\" />\n    </SVGIcon>\n  );\n}\n\nIconRadio.displayName = 'IconRadio';\n\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/setting.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconSetting(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M965.824 405.952a180.48 180.48 0 0 1-117.12-85.376 174.464 174.464 0 0 1-16-142.08 22.208 22.208 0 0 0-7.04-23.552 480.576 480.576 0 0 0-153.6-89.216 23.104 23.104 0 0 0-24.32 5.76 182.208 182.208 0 0 1-135.68 57.92 182.208 182.208 0 0 1-133.12-56.64 23.104 23.104 0 0 0-26.88-7.04 478.656 478.656 0 0 0-153.6 89.856 22.208 22.208 0 0 0-7.04 23.552 174.464 174.464 0 0 1-16 141.44A180.48 180.48 0 0 1 58.24 405.952a22.4 22.4 0 0 0-17.28 17.792 455.08 455.08 0 0 0 0 176.512 22.4 22.4 0 0 0 17.28 17.792 180.48 180.48 0 0 1 117.12 84.736c25.408 42.944 31.232 94.592 16 142.08a22.208 22.208 0 0 0 7.04 23.552A480.576 480.576 0 0 0 352 957.632h7.68a23.04 23.04 0 0 0 16.64-7.04 184.128 184.128 0 0 1 266.944 0c6.592 8.96 18.752 11.968 28.8 7.04a479.36 479.36 0 0 0 156.16-88.576 22.208 22.208 0 0 0 7.04-23.552 174.464 174.464 0 0 1 13.44-142.72 180.48 180.48 0 0 1 117.12-84.736 22.4 22.4 0 0 0 17.28-17.792 452.613 452.613 0 0 0 0-176.512 23.04 23.04 0 0 0-17.28-17.792z m-42.88 169.408a218.752 218.752 0 0 0-128 98.112 211.904 211.904 0 0 0-21.76 156.736 415.936 415.936 0 0 1-112 63.68 217.472 217.472 0 0 0-149.12-63.68 221.312 221.312 0 0 0-149.12 63.68 414.592 414.592 0 0 1-112-63.68c12.8-53.12 4.288-109.12-23.68-156.096A218.752 218.752 0 0 0 101.12 575.36a386.176 386.176 0 0 1 0-127.36 218.752 218.752 0 0 0 128-98.112c27.2-47.552 34.944-103.68 21.76-156.8a415.296 415.296 0 0 1 112-63.68A221.44 221.44 0 0 0 512 187.392a218.24 218.24 0 0 0 149.12-57.984 413.952 413.952 0 0 1 112 63.744 211.904 211.904 0 0 0 23.04 156.096 218.752 218.752 0 0 0 128 98.112 386.65 386.65 0 0 1 0 127.36l-1.28 0.64z\" />\n      <path d=\"M512 320.576c-105.984 0-192 85.568-192 191.104a191.552 191.552 0 0 0 192 191.104c106.112 0 192.064-85.568 192.064-191.104a190.72 190.72 0 0 0-56.256-135.168 192.448 192.448 0 0 0-135.744-55.936z m0 318.528c-70.656 0-128-57.088-128-127.424 0-70.4 57.344-127.36 128-127.36 70.72 0 128 56.96 128 127.36 0 33.792-13.44 66.176-37.44 90.112a128.32 128.32 0 0 1-90.496 37.312z\" />\n    </SVGIcon>\n  );\n}\n\nIconSetting.displayName = 'IconSetting';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/icons/unlock.tsx",
    "content": "import { SVGIcon, IconProps } from '@alilc/lowcode-utils';\n\nexport function IconUnlock(props: IconProps) {\n  return (\n    <SVGIcon viewBox=\"0 0 1024 1024\" {...props}>\n      <path d=\"M832 464H332V240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v68c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-68c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32z m-40 376H232V536h560v304z\" />\n      <path d=\"M484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53c12.1-8.7 20-22.9 20-39 0-26.5-21.5-48-48-48s-48 21.5-48 48c0 16.1 7.9 30.3 20 39z\" />\n    </SVGIcon>\n  );\n}\n\nIconUnlock.displayName = 'IconUnlock';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/index.tsx",
    "content": "import { Pane } from './views/pane';\nimport { IconOutline } from './icons/outline';\nimport { IPublicModelPluginContext, IPublicModelDocumentModel } from '@alilc/lowcode-types';\nimport { MasterPaneName, BackupPaneName } from './helper/consts';\nimport { TreeMaster } from './controllers/tree-master';\nimport { PaneController } from './controllers/pane-controller';\nimport { useState, useEffect } from 'react';\n\nexport function OutlinePaneContext(props: {\n  treeMaster?: TreeMaster;\n\n  pluginContext: IPublicModelPluginContext;\n\n  options: any;\n\n  paneName: string;\n\n  hideFilter?: boolean;\n}) {\n  const treeMaster = props.treeMaster || new TreeMaster(props.pluginContext, props.options);\n  const [masterPaneController, setMasterPaneController] = useState(\n    () => new PaneController(props.paneName || MasterPaneName, treeMaster),\n  );\n  useEffect(() => {\n    return treeMaster.onPluginContextChange(() => {\n      setMasterPaneController(new PaneController(props.paneName || MasterPaneName, treeMaster));\n    });\n  }, []);\n\n  return (\n    <Pane\n      treeMaster={treeMaster}\n      controller={masterPaneController}\n      key={masterPaneController.id}\n      hideFilter={props.hideFilter}\n      {...props}\n    />\n  );\n}\n\nexport const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {\n  const { skeleton, config, canvas, project } = ctx;\n\n  let isInFloatArea = true;\n  const hasPreferenceForOutline = config\n    .getPreference()\n    .contains('outline-pane-pinned-status-isFloat', 'skeleton');\n  if (hasPreferenceForOutline) {\n    isInFloatArea = config.getPreference().get('outline-pane-pinned-status-isFloat', 'skeleton');\n  }\n  const showingPanes = {\n    masterPane: false,\n    backupPane: false,\n  };\n  const treeMaster = new TreeMaster(ctx, options);\n  return {\n    async init() {\n      skeleton.add({\n        area: 'leftArea',\n        name: 'outlinePane',\n        type: 'PanelDock',\n        index: -1,\n        content: {\n          name: MasterPaneName,\n          props: {\n            icon: IconOutline,\n            description: treeMaster.pluginContext.intlNode('Outline Tree'),\n          },\n          content: OutlinePaneContext,\n        },\n        panelProps: {\n          area: isInFloatArea ? 'leftFloatArea' : 'leftFixedArea',\n          keepVisibleWhileDragging: true,\n          ...config.get('defaultOutlinePaneProps'),\n        },\n        contentProps: {\n          treeTitleExtra: config.get('treeTitleExtra'),\n          treeMaster,\n          paneName: MasterPaneName,\n        },\n      });\n\n      skeleton.add({\n        area: 'rightArea',\n        name: BackupPaneName,\n        type: 'Panel',\n        props: {\n          hiddenWhenInit: true,\n        },\n        content: OutlinePaneContext,\n        contentProps: {\n          paneName: BackupPaneName,\n          treeMaster,\n        },\n        index: 1,\n      });\n\n      // 处理 master pane 和 backup pane 切换\n      const switchPanes = () => {\n        const isDragging = canvas.dragon?.dragging;\n        const hasVisibleTreeBoard = showingPanes.backupPane || showingPanes.masterPane;\n        const shouldShowBackupPane = isDragging && !hasVisibleTreeBoard;\n\n        if (shouldShowBackupPane) {\n          skeleton.showPanel(BackupPaneName);\n        } else {\n          skeleton.hidePanel(BackupPaneName);\n        }\n      };\n      canvas.dragon?.onDragstart(() => {\n        switchPanes();\n      });\n      canvas.dragon?.onDragend(() => {\n        switchPanes();\n      });\n      skeleton.onShowPanel((key: string) => {\n        if (key === MasterPaneName) {\n          showingPanes.masterPane = true;\n        }\n        if (key === BackupPaneName) {\n          showingPanes.backupPane = true;\n        }\n      });\n      skeleton.onHidePanel((key: string) => {\n        if (key === MasterPaneName) {\n          showingPanes.masterPane = false;\n          switchPanes();\n        }\n        if (key === BackupPaneName) {\n          showingPanes.backupPane = false;\n        }\n      });\n      project.onChangeDocument((document: IPublicModelDocumentModel) => {\n        if (!document) {\n          return;\n        }\n\n        const { selection } = document;\n\n        selection?.onSelectionChange(() => {\n          const selectedNodes = selection?.getNodes();\n          if (!selectedNodes || selectedNodes.length === 0) {\n            return;\n          }\n          const tree = treeMaster.currentTree;\n          selectedNodes.forEach((node) => {\n            const treeNode = tree?.getTreeNodeById(node.id);\n            tree?.expandAllAncestors(treeNode);\n          });\n        });\n      });\n    },\n  };\n};\nOutlinePlugin.meta = {\n  eventPrefix: 'OutlinePlugin',\n  preferenceDeclaration: {\n    title: '大纲树插件配置',\n    properties: [\n      {\n        key: 'extraTitle',\n        type: 'object',\n        description: '副标题',\n      },\n    ],\n  },\n};\nOutlinePlugin.pluginName = 'OutlinePlugin';\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/locale/en-US.json",
    "content": "{\n  \"Initializing\": \"Initializing\",\n  \"Hide\": \"Hide\",\n  \"Show\": \"Show\",\n  \"Lock\": \"Lock\",\n  \"Unlock\": \"Unlock\",\n  \"Expand\": \"Expand\",\n  \"Collapse\": \"Collapse\",\n  \"Conditional\": \"Condition\",\n  \"Loop\": \"Loop\",\n  \"Slots\": \"Slots\",\n  \"Slot for {prop}\": \"Slot for {prop}\",\n  \"Outline Tree\": \"Component Tree\",\n  \"Filter Node\": \"Filter Node\",\n  \"Check All\": \"Check All\",\n  \"Conditional rendering\": \"Conditional rendering\",\n  \"Loop rendering\": \"Loop rendering\",\n  \"Locked\": \"Locked\",\n  \"Hidden\": \"Hidden\",\n  \"Modal View\": \"Modal View\",\n  \"Rename\": \"Rename\",\n  \"Delete\": \"Delete\"\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/locale/index.ts",
    "content": "import enUS from './en-US.json';\nimport zhCN from './zh-CN.json';\n\nexport { enUS, zhCN };\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/locale/zh-CN.json",
    "content": "{\n  \"Initializing\": \"正在初始化\",\n  \"Hide\": \"隐藏\",\n  \"Show\": \"显示\",\n  \"Lock\": \"锁定\",\n  \"Unlock\": \"解锁\",\n  \"Expand\": \"展开\",\n  \"Collapse\": \"收起\",\n  \"Conditional\": \"条件式\",\n  \"Loop\": \"循环\",\n  \"Slots\": \"插槽\",\n  \"Slot for {prop}\": \"属性 {prop} 的插槽\",\n  \"Outline Tree\": \"大纲树\",\n  \"Filter Node\": \"过滤节点\",\n  \"Check All\": \"全选\",\n  \"Conditional rendering\": \"条件渲染\",\n  \"Loop rendering\": \"循环渲染\",\n  \"Locked\": \"已锁定\",\n  \"Hidden\": \"已隐藏\",\n  \"Modal View\": \"模态视图层\",\n  \"Rename\": \"重命名\",\n  \"Delete\": \"删除\"\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/filter-tree.ts",
    "content": "import TreeNode from '../controllers/tree-node';\n\nexport const FilterType = {\n  CONDITION: 'CONDITION',\n  LOOP: 'LOOP',\n  LOCKED: 'LOCKED',\n  HIDDEN: 'HIDDEN',\n};\n\nexport const FILTER_OPTIONS = [{\n  value: FilterType.CONDITION,\n  label: 'Conditional rendering',\n}, {\n  value: FilterType.LOOP,\n  label: 'Loop rendering',\n}, {\n  value: FilterType.LOCKED,\n  label: 'Locked',\n}, {\n  value: FilterType.HIDDEN,\n  label: 'Hidden',\n}];\n\nexport const matchTreeNode = (\n  treeNode: TreeNode,\n  keywords: string,\n  filterOps: string[],\n): boolean => {\n  // 无效节点\n  if (!treeNode || !treeNode.node) {\n    return false;\n  }\n\n  // 过滤条件为空，重置过滤结果\n  if (!keywords && filterOps.length === 0) {\n    treeNode.setFilterReult({\n      filterWorking: false,\n      matchChild: false,\n      matchSelf: false,\n      keywords: '',\n    });\n\n    (treeNode.children || []).concat(treeNode.slots || []).forEach((childNode) => {\n      matchTreeNode(childNode, keywords, filterOps);\n    });\n\n    return false;\n  }\n\n  const { node } = treeNode;\n\n  // 命中过滤选项\n  const matchFilterOps = filterOps.length === 0 || !!filterOps.find((op: string) => {\n    switch (op) {\n      case FilterType.CONDITION:\n        return node.hasCondition();\n      case FilterType.LOOP:\n        return node.hasLoop();\n      case FilterType.LOCKED:\n        return treeNode.locked;\n      case FilterType.HIDDEN:\n        return treeNode.hidden;\n      default:\n        return false;\n    }\n  });\n\n  // 命中节点名\n  const matchKeywords = typeof treeNode.titleLabel === 'string' && treeNode.titleLabel.indexOf(keywords) > -1;\n\n  // 同时命中才展示（根结点永远命中）\n  const matchSelf = treeNode.isRoot() || (matchFilterOps && matchKeywords);\n\n  // 命中子节点\n  const matchChild = !!(treeNode.children || []).concat(treeNode.slots || [])\n    .map((childNode: TreeNode) => {\n      return matchTreeNode(childNode, keywords, filterOps);\n    }).find(Boolean);\n\n  // 如果命中了子节点，需要将该节点展开\n  if (matchChild && treeNode.expandable) {\n    treeNode.setExpanded(true);\n  }\n\n  treeNode.setFilterReult({\n    filterWorking: true,\n    matchChild,\n    matchSelf,\n    keywords,\n  });\n\n  return matchSelf || matchChild;\n};\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/filter.tsx",
    "content": "import React, { PureComponent } from 'react';\nimport './style.less';\nimport { IconFilter } from '../icons/filter';\nimport { Search, Checkbox, Balloon, Divider } from '@alifd/next';\nimport TreeNode from '../controllers/tree-node';\nimport { Tree } from '../controllers/tree';\nimport { matchTreeNode, FILTER_OPTIONS } from './filter-tree';\n\nexport default class Filter extends PureComponent<{\n  tree: Tree;\n}, {\n  keywords: string;\n  filterOps: string[];\n}> {\n  state = {\n    keywords: '',\n    filterOps: [],\n  };\n\n  handleSearchChange = (val: string) => {\n    this.setState({\n      keywords: val.trim(),\n    }, this.filterTree);\n  };\n\n  handleOptionChange = (val: string[]) => {\n    this.setState({\n      filterOps: val,\n    }, this.filterTree);\n  };\n\n  handleCheckAll = () => {\n    const { filterOps } = this.state;\n    const final = filterOps.length === FILTER_OPTIONS.length\n      ? [] : FILTER_OPTIONS.map((op) => op.value);\n\n    this.handleOptionChange(final);\n  };\n\n  filterTree() {\n    const { tree } = this.props;\n    const { keywords, filterOps } = this.state;\n\n    matchTreeNode(tree.root as TreeNode, keywords, filterOps);\n  }\n\n  render() {\n    const { keywords, filterOps } = this.state;\n    const indeterminate = filterOps.length > 0 && filterOps.length < FILTER_OPTIONS.length;\n    const checkAll = filterOps.length === FILTER_OPTIONS.length;\n\n    return (\n      <div className=\"lc-outline-filter\">\n        <Search\n          hasClear\n          shape=\"simple\"\n          placeholder={this.props.tree.pluginContext.intl('Filter Node')}\n          className=\"lc-outline-filter-search-input\"\n          value={keywords}\n          onChange={this.handleSearchChange}\n        />\n        <Balloon\n          v2\n          align=\"br\"\n          closable={false}\n          triggerType=\"hover\"\n          trigger={(\n            <div className=\"lc-outline-filter-icon\">\n              <IconFilter />\n            </div>\n          )}\n        >\n          <Checkbox\n            checked={checkAll}\n            indeterminate={indeterminate}\n            onChange={this.handleCheckAll}\n          >\n            {this.props.tree.pluginContext.intlNode('Check All')}\n          </Checkbox>\n          <Divider />\n          <Checkbox.Group\n            value={filterOps}\n            direction=\"ver\"\n            onChange={this.handleOptionChange}\n          >\n            {FILTER_OPTIONS.map((op) => (\n              <Checkbox\n                id={op.value}\n                value={op.value}\n                key={op.value}\n              >\n                {this.props.tree.pluginContext.intlNode(op.label)}\n              </Checkbox>\n            ))}\n          </Checkbox.Group>\n        </Balloon>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/pane.tsx",
    "content": "import React, { PureComponent } from 'react';\nimport { Loading } from '@alifd/next';\nimport { PaneController } from '../controllers/pane-controller';\nimport TreeView from './tree';\nimport './style.less';\nimport Filter from './filter';\nimport { TreeMaster } from '../controllers/tree-master';\nimport { Tree } from '../controllers/tree';\nimport { IPublicTypeDisposable } from '@alilc/lowcode-types';\n\nexport class Pane extends PureComponent<{\n  treeMaster: TreeMaster;\n  controller: PaneController;\n  hideFilter?: boolean;\n}, {\n  tree: Tree | null;\n}> {\n  private controller;\n\n  private simulatorRendererReadyDispose: IPublicTypeDisposable;\n  private changeDocumentDispose: IPublicTypeDisposable;\n  private removeDocumentDispose: IPublicTypeDisposable;\n\n  constructor(props: any) {\n    super(props);\n    const { controller, treeMaster } = props;\n    this.controller = controller;\n    this.state = {\n      tree: treeMaster.currentTree,\n    };\n    this.simulatorRendererReadyDispose = this.props.treeMaster.pluginContext?.project?.onSimulatorRendererReady(this.changeTree);\n    this.changeDocumentDispose = this.props.treeMaster.pluginContext?.project?.onChangeDocument(this.changeTree);\n    this.removeDocumentDispose = this.props.treeMaster.pluginContext?.project?.onRemoveDocument(this.changeTree);\n  }\n\n  changeTree = () => {\n    this.setState({\n      tree: this.props.treeMaster.currentTree,\n    });\n  };\n\n  componentWillUnmount() {\n    this.controller.purge();\n    this.simulatorRendererReadyDispose?.();\n    this.changeDocumentDispose?.();\n    this.removeDocumentDispose?.();\n  }\n\n  render() {\n    const tree = this.state.tree;\n\n    if (!tree) {\n      return (\n        <div className=\"lc-outline-pane\">\n          <p className=\"lc-outline-notice\">\n            <Loading\n              style={{\n                display: 'block',\n                marginTop: '40px',\n              }}\n              tip={this.props.treeMaster.pluginContext.intl('Initializing')}\n            />\n          </p>\n        </div>\n      );\n    }\n\n    return (\n      <div className=\"lc-outline-pane\">\n        { !this.props.hideFilter && <Filter tree={tree} /> }\n        <div ref={(shell) => this.controller.mount(shell)} className={`lc-outline-tree-container ${ this.props.hideFilter ? 'lc-hidden-outline-filter' : '' }`}>\n          <TreeView key={tree.id} tree={tree} />\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/style.less",
    "content": ".lc-outline-pane {\n  height: 100%;\n  width: 100%;\n  position: relative;\n  z-index: 200;\n\n  > .lc-outline-tree-container {\n    top: 52px;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    position: absolute;\n    overflow: auto;\n  }\n\n  > .lc-outline-tree-container.lc-hidden-outline-filter {\n    top: 0;\n  }\n\n  > .lc-outline-filter {\n    padding: 12px 16px;\n    display: flex;\n    align-items: stretch;\n    justify-content: right;\n\n    .lc-outline-filter-search-input {\n      width: 100%;\n    }\n\n    .lc-outline-filter-icon {\n      background: var(--color-block-background-light, #ebecf0);\n      border: 1px solid var(--color-field-border, #c4c6cf);\n      display: flex;\n      align-items: center;\n      border-radius: 0 2px 2px 0;\n      overflow: hidden;\n      margin-left: -2px;\n      z-index: 1;\n      padding: 0 6px;\n\n      &:hover {\n        cursor: pointer;\n      }\n    }\n  }\n}\n\n.lc-outline-tree {\n  @treeNodeHeight: 30px;\n  overflow: hidden;\n  margin-bottom: @treeNodeHeight;\n  user-select: none;\n  overflow-x: scroll;\n\n  .tree-node-modal {\n    margin: 5px;\n    border: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2));\n    border-radius: 3px;\n    box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 56, 88, 0.15));\n\n    .tree-node-modal-title {\n      position: relative;\n      background: var(--color-block-background-light, rgba(31, 56, 88, 0.04));\n      padding: 0 10px;\n      height: 32px;\n      line-height: 32px;\n      border-bottom: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2));\n\n      .tree-node-modal-title-visible-icon {\n        position: absolute;\n        top: 4px;\n        right: 12px;\n        cursor: pointer;\n      }\n    }\n\n    .tree-pane-modal-content {\n      & > .tree-node-branches::before {\n        display: none;\n      }\n    }\n\n    .tree-node-modal-radio,\n    .tree-node-modal-radio-active {\n      margin-right: 4px;\n      opacity: 0.8;\n      position: absolute;\n      top: 7px;\n      left: 6px;\n    }\n    .tree-node-modal-radio-active {\n      color: var(--color-brand, #006cff);\n    }\n  }\n\n  .tree-node-branches::before {\n    position: absolute;\n    display: block;\n    width: 0;\n    border-left: 1px solid transparent;\n    height: 100%;\n    top: 0;\n    left: 6px;\n    content: ' ';\n    z-index: 2;\n    pointer-events: none;\n  }\n\n  &:hover {\n    .tree-node-branches::before {\n      border-left-color: var(--color-line-darken, #ddd);\n    }\n  }\n\n  .insertion {\n    pointer-events: all !important;\n    border: 1px dashed var(--color-brand-light);\n    height: @treeNodeHeight;\n    box-sizing: border-box;\n    transform: translateZ(0);\n    transition: all 0.2s ease-in-out;\n    &.invalid {\n      border-color: var(--color-error, var(--color-function-error, red));\n      background-color: var(--color-block-background-error, rgba(240, 154, 154, 0.719));\n    }\n  }\n\n  .condition-group-container {\n    border-bottom: 1px solid var(--color-brown, var(--color-function-brown, #7b605b));\n    position: relative;\n\n    &:before {\n      position: absolute;\n      display: block;\n      width: 0;\n      border-left: 0.5px solid var(--color-brown, var(--color-function-brown, #7b605b));\n      height: 100%;\n      top: 0;\n      left: 0;\n      content: ' ';\n      z-index: 2;\n    }\n    > .condition-group-title {\n      text-align: center;\n      background-color: var(--color-brown, var(--color-function-brown, #7b605b));\n      height: 14px;\n      > .lc-title {\n        font-size: 12px;\n        transform: scale(0.8);\n        transform-origin: top;\n        color: var(--color-text-reverse, white);\n        text-shadow: 0 0 2px var(--color-block-background-shallow, black);\n        display: block;\n      }\n    }\n  }\n  .tree-node-slots {\n    border-bottom: 1px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190)));\n    position: relative;\n    &::before {\n      position: absolute;\n      display: block;\n      width: 0;\n      border-left: 0.5px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190)));\n      height: 100%;\n      top: 0;\n      left: 0;\n      content: ' ';\n      z-index: 2;\n    }\n    > .tree-node-slots-title {\n      text-align: center;\n      background-color: var(--color-purple, var(--color-function-purple, rgb(144, 94, 190)));\n      height: 14px;\n      > .lc-title {\n        font-size: 12px;\n        transform: scale(0.8);\n        transform-origin: top;\n        color: var(--color-text-reverse, white);\n        text-shadow: 0 0 2px black;\n        display: block;\n      }\n    }\n    &.insertion-at-slots {\n      padding-bottom: @treeNodeHeight;\n      border-bottom-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55)));\n      > .tree-node-slots-title {\n        background-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55)));\n      }\n      &::before {\n        border-left-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55)));\n      }\n    }\n  }\n\n  .tree-node {\n    .tree-node-expand-btn {\n      width: 12px;\n      line-height: 0;\n      align-self: stretch;\n      display: flex;\n      align-items: center;\n      transition: color 200ms ease;\n      color: var(--color-icon-normal);\n      &:hover {\n        color: var(--color-icon-hover);\n      }\n      > svg {\n        transform-origin: center;\n        transform: rotate(-90deg);\n        transition: transform 100ms ease;\n      }\n      margin-right: 4px;\n    }\n    .tree-node-expand-placeholder {\n      width: 12px;\n      height: 12px;\n      margin-right: 4px;\n    }\n\n    .tree-node-icon {\n      transform: translateZ(0);\n      display: flex;\n      align-items: center;\n      margin-right: 4px;\n      color: var(--color-text);\n\n      & > svg {\n        width: 16px;\n        height: 16px;\n        * {\n          fill: var(--color-icon-normal, rgba(31, 56, 88, 0.4));\n        }\n      }\n      & > img {\n        width: 16px;\n        height: 16px;\n        * {\n          fill: var(--color-icon-normal, rgba(31, 56, 88, 0.4));\n        }\n      }\n    }\n\n    .tree-node-title {\n      font-size: var(--font-size-text);\n      cursor: pointer;\n      border-bottom: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1));\n      display: flex;\n      align-items: center;\n      height: @treeNodeHeight;\n      box-sizing: border-box;\n      position: relative;\n      transform: translateZ(0);\n      padding-right: 5px;\n      & > :first-child {\n        margin-left: 2px;\n      }\n\n      .tree-node-title-label {\n        flex: 1;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n        display: flex;\n        align-items: center;\n        align-self: stretch;\n        overflow: visible;\n        margin-right: 5px;\n\n        .tree-node-title-input {\n          flex: 1;\n          border: 1px solid var(--color-brand-light);\n          background-color: var(--color-pane-background);\n          color: var(--color-text);\n          line-height: 18px;\n          padding: 2px;\n          outline: none;\n          margin-left: -3px;\n          border-radius: 2px;\n        }\n      }\n\n      .tree-node-hide-btn,\n      .tree-node-lock-btn,\n      .tree-node-rename-btn,\n      .tree-node-delete-btn {\n        opacity: 0;\n        color: var(--color-text);\n        line-height: 0;\n        align-self: stretch;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        width: 22px;\n        &:hover {\n          opacity: 1 !important;\n        }\n      }\n      &:hover {\n        .tree-node-hide-btn,\n        .tree-node-lock-btn,\n        .tree-node-rename-btn,\n        .tree-node-delete-btn {\n          opacity: 0.5;\n        }\n      }\n      html.lc-cursor-dragging & {\n        // FIXME: only hide hover shows\n        .tree-node-hide-btn,\n        .tree-node-lock-btn,\n        .tree-node-rename-btn {\n          display: none;\n        }\n      }\n      &.editing {\n        & > .tree-node-hide-btn,\n        & > .tree-node-lock-btn,\n        & > .tree-node-rename-btn,\n        & > .tree-node-delete-btn {\n          display: none;\n        }\n      }\n\n      .tree-node-tag {\n        margin-left: 5px;\n        display: flex;\n        align-items: center;\n        line-height: 0;\n        &.cond {\n          color: var(--color-error, var(--color-function-error, rgb(179, 52, 6)));\n        }\n        &.loop {\n          color: var(--color-success, var(--color-function-success, rgb(103, 187, 187)));\n        }\n        &.slot {\n          color: var(--color-purple, var(--color-function-purple, rgb(211, 90, 211)));\n        }\n      }\n    }\n\n    &.is-root {\n      > .tree-node-title {\n        padding-left: 5px;\n      }\n    }\n\n    &.expanded {\n      & > .tree-node-title > .tree-node-expand-btn > svg {\n        transform: rotate(0);\n      }\n    }\n\n    &.detecting > .tree-node-title {\n      background: var(--color-block-background-light);\n    }\n\n    // 选中节点处理\n    &.selected {\n      & > .tree-node-title {\n        background: var(--color-block-background-light);\n      }\n\n      & > .tree-node-branches::before {\n        border-left-color: var(--color-brand-light);\n      }\n    }\n\n    &.hidden {\n      .tree-node-title-label {\n        color: var(--color-text-disabled, #9b9b9b);\n      }\n      & > .tree-node-title > .tree-node-hide-btn {\n        opacity: 0.8;\n      }\n      .tree-node-branches {\n        .tree-node-hide-btn {\n          opacity: 0;\n        }\n      }\n    }\n\n    &.condition-flow {\n      & > .tree-node-title > .tree-node-hide-btn {\n        opacity: 1;\n      }\n      &.hidden > .tree-node-title > .tree-node-hide-btn {\n        opacity: 0;\n      }\n    }\n\n    &.locked {\n      & > .tree-node-title > .tree-node-lock-btn {\n        opacity: 0.8;\n      }\n      .tree-node-branches {\n        .tree-node-lock-btn,\n        .tree-node-hide-btn {\n          opacity: 0;\n        }\n      }\n    }\n\n    // 处理拖入节点\n    &.dropping {\n      & > .tree-node-branches::before {\n        border-left: 1px solid var(--color-brand);\n      }\n      & > .tree-node-title {\n        .tree-node-expand-btn {\n          color: var(--color-brand);\n        }\n        .tree-node-icon {\n          color: var(--color-brand);\n        }\n        .tree-node-title-label > .lc-title {\n          color: var(--color-brand);\n        }\n      }\n    }\n    &.highlight {\n      & > .tree-node-title {\n        background: var(--color-block-background-shallow);\n      }\n    }\n\n    .tree-node-branches {\n      padding-left: 12px;\n      position: relative;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/tree-branches.tsx",
    "content": "import { PureComponent } from 'react';\nimport classNames from 'classnames';\nimport TreeNode from '../controllers/tree-node';\nimport TreeNodeView from './tree-node';\nimport { IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types';\n\nexport default class TreeBranches extends PureComponent<{\n  treeNode: TreeNode;\n  isModal?: boolean;\n  expanded: boolean;\n  treeChildren: TreeNode[] | null;\n}> {\n  state = {\n    filterWorking: false,\n    matchChild: false,\n  };\n  private offExpandedChanged: (() => void) | null;\n  constructor(props: any) {\n    super(props);\n\n    const { treeNode } = this.props;\n    const { filterWorking, matchChild } = treeNode.filterReult;\n    this.setState({ filterWorking, matchChild });\n  }\n\n  componentDidMount() {\n    const { treeNode } = this.props;\n    treeNode.onFilterResultChanged(() => {\n      const { filterWorking: newFilterWorking, matchChild: newMatchChild } = treeNode.filterReult;\n      this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild });\n    });\n  }\n\n  componentWillUnmount(): void {\n    if (this.offExpandedChanged) {\n      this.offExpandedChanged();\n    }\n  }\n\n  render() {\n    const { treeNode, isModal, expanded } = this.props;\n    const { filterWorking, matchChild } = this.state;\n    // 条件过滤生效时，如果命中了子节点，需要将该节点展开\n    const expandInFilterResult = filterWorking && matchChild;\n\n    if (!expandInFilterResult && !expanded) {\n      return null;\n    }\n\n    return (\n      <div className=\"tree-node-branches\">\n        {\n          !isModal && <TreeNodeSlots treeNode={treeNode} />\n        }\n        <TreeNodeChildren\n          treeNode={treeNode}\n          isModal={isModal || false}\n          treeChildren={this.props.treeChildren}\n        />\n      </div>\n    );\n  }\n}\n\ninterface ITreeNodeChildrenState {\n  filterWorking: boolean;\n  matchSelf: boolean;\n  keywords: string | null;\n  dropDetail: IPublicTypeLocationChildrenDetail | undefined | null;\n}\nclass TreeNodeChildren extends PureComponent<{\n    treeNode: TreeNode;\n    isModal?: boolean;\n    treeChildren: TreeNode[] | null;\n  }, ITreeNodeChildrenState> {\n  state: ITreeNodeChildrenState = {\n    filterWorking: false,\n    matchSelf: false,\n    keywords: null,\n    dropDetail: null,\n  };\n  offLocationChanged: IPublicTypeDisposable | undefined;\n  componentDidMount() {\n    const { treeNode } = this.props;\n    const { project } = treeNode.pluginContext;\n    const { filterWorking, matchSelf, keywords } = treeNode.filterReult;\n    const { dropDetail } = treeNode;\n    this.setState({\n      filterWorking,\n      matchSelf,\n      keywords,\n      dropDetail,\n    });\n    treeNode.onFilterResultChanged(() => {\n      const {\n        filterWorking: newFilterWorking,\n        matchSelf: newMatchChild,\n        keywords: newKeywords,\n       } = treeNode.filterReult;\n      this.setState({\n        filterWorking: newFilterWorking,\n        matchSelf: newMatchChild,\n        keywords: newKeywords,\n      });\n    });\n    this.offLocationChanged = project.currentDocument?.onDropLocationChanged(\n        () => {\n          this.setState({ dropDetail: treeNode.dropDetail });\n        },\n      );\n  }\n  componentWillUnmount(): void {\n    this.offLocationChanged && this.offLocationChanged();\n  }\n\n  render() {\n    const { isModal } = this.props;\n    const children: any = [];\n    let groupContents: any[] = [];\n    let currentGrp: IPublicModelExclusiveGroup;\n    const { filterWorking, matchSelf, keywords } = this.state;\n    const Title = this.props.treeNode.pluginContext.common.editorCabin.Title;\n\n    const endGroup = () => {\n      if (groupContents.length > 0) {\n        children.push(\n          <div key={currentGrp.id} className=\"condition-group-container\" data-id={currentGrp.firstNode?.id}>\n            <div className=\"condition-group-title\">\n              {/* @ts-ignore */}\n              <Title\n                title={currentGrp.title}\n                match={filterWorking && matchSelf}\n                keywords={keywords}\n              />\n            </div>\n            {groupContents}\n          </div>,\n        );\n        groupContents = [];\n      }\n    };\n\n    const { dropDetail } = this.state;\n    const dropIndex = dropDetail?.index;\n    const insertion = (\n      <div\n        key=\"insertion\"\n        className={classNames('insertion', {\n          invalid: dropDetail?.valid === false,\n        })}\n      />\n    );\n    this.props.treeChildren?.forEach((child, index) => {\n      const childIsModal = child.node.componentMeta?.isModal || false;\n      if (isModal != childIsModal) {\n        return;\n      }\n      const { conditionGroup } = child.node;\n      if (conditionGroup !== currentGrp) {\n        endGroup();\n      }\n\n      if (conditionGroup) {\n        currentGrp = conditionGroup;\n        if (index === dropIndex) {\n          if (groupContents.length > 0) {\n            groupContents.push(insertion);\n          } else {\n            children.push(insertion);\n          }\n        }\n        groupContents.push(<TreeNodeView key={child.nodeId} treeNode={child} isModal={isModal} />);\n      } else {\n        if (index === dropIndex) {\n          children.push(insertion);\n        }\n        children.push(<TreeNodeView key={child.nodeId} treeNode={child} isModal={isModal} />);\n      }\n    });\n    endGroup();\n    const length = this.props.treeChildren?.length || 0;\n    if (dropIndex != null && dropIndex >= length) {\n      children.push(insertion);\n    }\n\n    return <div className=\"tree-node-children\">{children}</div>;\n  }\n}\n\nclass TreeNodeSlots extends PureComponent<{\n    treeNode: TreeNode;\n  }> {\n  render() {\n    const { treeNode } = this.props;\n    if (!treeNode.hasSlots()) {\n      return null;\n    }\n    const Title = this.props.treeNode.pluginContext.common.editorCabin.Title;\n    return (\n      <div\n        className={classNames('tree-node-slots', {\n          'insertion-at-slots': treeNode.dropDetail?.focus?.type === 'slots',\n        })}\n        data-id={treeNode.nodeId}\n      >\n        <div className=\"tree-node-slots-title\">\n          {/* @ts-ignore */}\n          <Title title={{ type: 'i18n', intl: this.props.treeNode.pluginContext.intlNode('Slots') }} />\n        </div>\n        {treeNode.slots.map(tnode => (\n          <TreeNodeView key={tnode.nodeId} treeNode={tnode} />\n        ))}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/tree-node.tsx",
    "content": "import { PureComponent } from 'react';\nimport classNames from 'classnames';\nimport TreeNode from '../controllers/tree-node';\nimport TreeTitle from './tree-title';\nimport TreeBranches from './tree-branches';\nimport { IconEyeClose } from '../icons/eye-close';\nimport { IPublicModelModalNodesManager, IPublicTypeDisposable } from '@alilc/lowcode-types';\nimport { IOutlinePanelPluginContext } from '../controllers/tree-master';\n\nclass ModalTreeNodeView extends PureComponent<{\n  treeNode: TreeNode;\n}, {\n  treeChildren: TreeNode[] | null;\n}> {\n  private modalNodesManager: IPublicModelModalNodesManager | undefined | null;\n  readonly pluginContext: IOutlinePanelPluginContext;\n\n  constructor(props: {\n    treeNode: TreeNode;\n  }) {\n    super(props);\n\n    // 模态管理对象\n    this.pluginContext = props.treeNode.pluginContext;\n    const { project } = this.pluginContext;\n    this.modalNodesManager = project.currentDocument?.modalNodesManager;\n    this.state = {\n      treeChildren: this.rootTreeNode.children,\n    };\n  }\n\n  hideAllNodes() {\n    this.modalNodesManager?.hideModalNodes();\n  }\n\n  componentDidMount(): void {\n    const { rootTreeNode } = this;\n    rootTreeNode.onExpandableChanged(() => {\n      this.setState({\n        treeChildren: rootTreeNode.children,\n      });\n    });\n  }\n\n  get rootTreeNode() {\n    const { treeNode } = this.props;\n    // 当指定了新的根节点时，要从原始的根节点去获取模态节点\n    const { project } = this.pluginContext;\n    const rootNode = project.currentDocument?.root;\n    const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);\n\n    return rootTreeNode;\n  }\n\n  render() {\n    const { rootTreeNode } = this;\n    const { expanded } = rootTreeNode;\n\n    const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode();\n    return (\n      <div className=\"tree-node-modal\">\n        <div className=\"tree-node-modal-title\">\n          <span>{this.pluginContext.intlNode('Modal View')}</span>\n          <div\n            className=\"tree-node-modal-title-visible-icon\"\n            onClick={this.hideAllNodes.bind(this)}\n          >\n            {hasVisibleModalNode ? <IconEyeClose /> : null}\n          </div>\n        </div>\n        <div className=\"tree-pane-modal-content\">\n          <TreeBranches\n            treeNode={rootTreeNode}\n            treeChildren={this.state.treeChildren}\n            expanded={expanded}\n            isModal\n          />\n        </div>\n      </div>\n    );\n  }\n}\n\nexport default class TreeNodeView extends PureComponent<{\n  treeNode: TreeNode;\n  isModal?: boolean;\n  isRootNode?: boolean;\n}> {\n  state: {\n    expanded: boolean;\n    selected: boolean;\n    hidden: boolean;\n    locked: boolean;\n    detecting: boolean;\n    isRoot: boolean;\n    highlight: boolean;\n    dropping: boolean;\n    conditionFlow: boolean;\n    expandable: boolean;\n    treeChildren: TreeNode[] | null;\n    filterWorking: boolean;\n    matchChild: boolean;\n    matchSelf: boolean;\n  } = {\n    expanded: false,\n    selected: false,\n    hidden: false,\n    locked: false,\n    detecting: false,\n    isRoot: false,\n    highlight: false,\n    dropping: false,\n    conditionFlow: false,\n    expandable: false,\n    treeChildren: [],\n    filterWorking: false,\n    matchChild: false,\n    matchSelf: false,\n  };\n\n  eventOffCallbacks: Array<IPublicTypeDisposable | undefined> = [];\n  constructor(props: any) {\n    super(props);\n\n    const { treeNode, isRootNode } = this.props;\n    this.state = {\n      expanded: isRootNode ? true : treeNode.expanded,\n      selected: treeNode.selected,\n      hidden: treeNode.hidden,\n      locked: treeNode.locked,\n      detecting: treeNode.detecting,\n      isRoot: treeNode.isRoot(),\n      // 是否投放响应\n      dropping: treeNode.dropDetail?.index != null,\n      conditionFlow: treeNode.node.conditionGroup != null,\n      highlight: treeNode.isFocusingNode(),\n      expandable: treeNode.expandable,\n      treeChildren: treeNode.children,\n    };\n  }\n\n  componentDidMount() {\n    const { treeNode } = this.props;\n    const { project } = treeNode.pluginContext;\n\n    const doc = project.currentDocument;\n\n    treeNode.onExpandedChanged(((expanded: boolean) => {\n      this.setState({ expanded });\n    }));\n    treeNode.onHiddenChanged((hidden: boolean) => {\n      this.setState({ hidden });\n    });\n    treeNode.onLockedChanged((locked: boolean) => {\n      this.setState({ locked });\n    });\n    treeNode.onExpandableChanged((expandable: boolean) => {\n      this.setState({\n        expandable,\n        treeChildren: treeNode.children,\n      });\n    });\n    treeNode.onFilterResultChanged(() => {\n      const { filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf } = treeNode.filterReult;\n      this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf });\n    });\n    this.eventOffCallbacks.push(\n      doc?.onDropLocationChanged(() => {\n        this.setState({\n          dropping: treeNode.dropDetail?.index != null,\n        });\n      }),\n    );\n\n    const offSelectionChange = doc?.selection?.onSelectionChange(() => {\n      this.setState({ selected: treeNode.selected });\n    });\n    this.eventOffCallbacks.push(offSelectionChange!);\n    const offDetectingChange = doc?.detecting?.onDetectingChange(() => {\n      this.setState({ detecting: treeNode.detecting });\n    });\n    this.eventOffCallbacks.push(offDetectingChange!);\n  }\n  componentWillUnmount(): void {\n    this.eventOffCallbacks?.forEach((offFun: IPublicTypeDisposable | undefined) => {\n      offFun && offFun();\n    });\n  }\n\n  shouldShowModalTreeNode(): boolean {\n    const { treeNode, isRootNode } = this.props;\n    if (!isRootNode) {\n      // 只在 当前树 的根节点展示模态节点\n      return false;\n    }\n\n    // 当指定了新的根节点时，要从原始的根节点去获取模态节点\n    const { project } = treeNode.pluginContext;\n    const rootNode = project.currentDocument?.root;\n    const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);\n    const modalNodes = rootTreeNode.children?.filter((item) => {\n      return item.node.componentMeta?.isModal;\n    });\n    return !!(modalNodes && modalNodes.length > 0);\n  }\n\n  render() {\n    const { treeNode, isModal, isRootNode } = this.props;\n    const className = classNames('tree-node', {\n      // 是否展开\n      expanded: this.state.expanded,\n      // 是否选中的\n      selected: this.state.selected,\n      // 是否隐藏的\n      hidden: this.state.hidden,\n      // 是否锁定的\n      locked: this.state.locked,\n      // 是否悬停中\n      detecting: this.state.detecting,\n      // 是否投放响应\n      dropping: this.state.dropping,\n      'is-root': this.state.isRoot,\n      'condition-flow': this.state.conditionFlow,\n      highlight: this.state.highlight,\n    });\n    let shouldShowModalTreeNode: boolean = this.shouldShowModalTreeNode();\n\n    // filter 处理\n    const { filterWorking, matchChild, matchSelf } = this.state;\n    if (!isRootNode && filterWorking && !matchChild && !matchSelf) {\n      // 条件过滤生效时，如果未命中本节点或子节点，则不展示该节点\n      // 根节点始终展示\n      return null;\n    }\n    return (\n      <div\n        className={className}\n        data-id={treeNode.nodeId}\n      >\n        <TreeTitle\n          treeNode={treeNode}\n          isModal={isModal}\n          expanded={this.state.expanded}\n          hidden={this.state.hidden}\n          locked={this.state.locked}\n          expandable={this.state.expandable}\n        />\n        {shouldShowModalTreeNode &&\n          <ModalTreeNodeView\n            treeNode={treeNode}\n          />\n        }\n        <TreeBranches\n          treeNode={treeNode}\n          isModal={false}\n          expanded={this.state.expanded}\n          treeChildren={this.state.treeChildren}\n        />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/tree-title.tsx",
    "content": "import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react';\nimport classNames from 'classnames';\nimport { createIcon } from '@alilc/lowcode-utils';\nimport { IPublicApiEvent } from '@alilc/lowcode-types';\nimport TreeNode from '../controllers/tree-node';\nimport { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting, IconDelete } from '../icons';\n\nfunction emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNode, rest?: Record<string, unknown>) {\n  const node = treeNode?.node;\n  const npm = node?.componentMeta?.npm;\n  const selected =\n    [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';\n  event.emit(`outlinePane.${type}`, {\n    selected,\n    ...rest,\n  });\n}\n\nexport default class TreeTitle extends PureComponent<{\n  treeNode: TreeNode;\n  isModal?: boolean;\n  expanded: boolean;\n  hidden: boolean;\n  locked: boolean;\n  expandable: boolean;\n}> {\n  state: {\n    editing: boolean;\n    title: string;\n    condition?: boolean;\n    visible?: boolean;\n    filterWorking: boolean;\n    keywords: string;\n    matchSelf: boolean;\n  } = {\n    editing: false,\n    title: '',\n    filterWorking: false,\n    keywords: '',\n    matchSelf: false,\n  };\n\n  private lastInput?: HTMLInputElement;\n\n  private enableEdit = (e: MouseEvent) => {\n    e.preventDefault();\n    this.setState({\n      editing: true,\n    });\n  };\n\n  private cancelEdit() {\n    this.setState({\n      editing: false,\n    });\n    this.lastInput = undefined;\n  }\n\n  private saveEdit = (e: FocusEvent<HTMLInputElement> | KeyboardEvent<HTMLInputElement>) => {\n    const { treeNode } = this.props;\n    const value = (e.target as HTMLInputElement).value || '';\n    treeNode.setTitleLabel(value);\n    emitOutlineEvent(this.props.treeNode.pluginContext.event, 'rename', treeNode, { value });\n    this.cancelEdit();\n  };\n\n  private handleKeyUp = (e: KeyboardEvent<HTMLInputElement>) => {\n    if (e.keyCode === 13) {\n      this.saveEdit(e);\n    }\n    if (e.keyCode === 27) {\n      this.cancelEdit();\n    }\n  };\n\n  private setCaret = (input: HTMLInputElement | null) => {\n    if (!input || this.lastInput === input) {\n      return;\n    }\n    input.focus();\n    input.select();\n    // 光标定位最后一个\n    // input.selectionStart = input.selectionEnd;\n  };\n\n  componentDidMount() {\n    const { treeNode } = this.props;\n    this.setState({\n      editing: false,\n      title: treeNode.titleLabel,\n      condition: treeNode.condition,\n      visible: !treeNode.hidden,\n    });\n    treeNode.onTitleLabelChanged(() => {\n      this.setState({\n        title: treeNode.titleLabel,\n      });\n    });\n    treeNode.onConditionChanged(() => {\n      this.setState({\n        condition: treeNode.condition,\n      });\n    });\n    treeNode.onHiddenChanged((hidden: boolean) => {\n      this.setState({\n        visible: !hidden,\n      });\n    });\n    treeNode.onFilterResultChanged(() => {\n      const { filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf } = treeNode.filterReult;\n      this.setState({ filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf });\n    });\n  }\n  deleteClick = () => {\n    const { treeNode } = this.props;\n    const { node } = treeNode;\n    treeNode.deleteNode(node);\n  };\n  render() {\n    const { treeNode, isModal } = this.props;\n    const { pluginContext } = treeNode;\n    const { editing, filterWorking, matchSelf, keywords } = this.state;\n    const isCNode = !treeNode.isRoot();\n    const { node } = treeNode;\n    const { componentMeta } = node;\n    const availableActions = componentMeta ? componentMeta.availableActions.map((availableAction) => availableAction.name) : [];\n    const isNodeParent = node.isParentalNode;\n    const isContainer = node.isContainerNode;\n    let style: any;\n    if (isCNode) {\n      const { depth } = treeNode;\n      const indent = depth * 12;\n      style = {\n        paddingLeft: indent + (isModal ? 12 : 0),\n        marginLeft: -indent,\n      };\n    }\n    const Extra = pluginContext.extraTitle;\n    const { intlNode, common, config } = pluginContext;\n    const { Tip, Title } = common.editorCabin;\n    const couldHide = availableActions.includes('hide');\n    const couldLock = availableActions.includes('lock');\n    const couldUnlock = availableActions.includes('unlock');\n    const shouldShowHideBtn = isCNode && isNodeParent && !isModal && couldHide;\n    const shouldShowLockBtn = config.get('enableCanvasLock', false) && isContainer && isCNode && isNodeParent && ((couldLock && !node.isLocked) || (couldUnlock && node.isLocked));\n    const shouldEditBtn = isCNode && isNodeParent;\n    const shouldDeleteBtn = isCNode && isNodeParent && node?.canPerformAction('remove');\n    return (\n      <div\n        className={classNames('tree-node-title', { editing })}\n        style={style}\n        data-id={treeNode.nodeId}\n        onClick={() => {\n          if (isModal) {\n            if (this.state.visible) {\n              node.document?.modalNodesManager?.setInvisible(node);\n            } else {\n              node.document?.modalNodesManager?.setVisible(node);\n            }\n            return;\n          }\n          if (node.conditionGroup) {\n            node.setConditionalVisible();\n          }\n        }}\n      >\n        {isModal && this.state.visible && (\n          <div onClick={() => {\n            node.document?.modalNodesManager?.setInvisible(node);\n          }}\n          >\n            <IconRadioActive className=\"tree-node-modal-radio-active\" />\n          </div>\n        )}\n        {isModal && !this.state.visible && (\n          <div onClick={() => {\n            node.document?.modalNodesManager?.setVisible(node);\n          }}\n          >\n            <IconRadio className=\"tree-node-modal-radio\" />\n          </div>\n        )}\n        {isCNode && <ExpandBtn expandable={this.props.expandable} expanded={this.props.expanded} treeNode={treeNode} />}\n        <div className=\"tree-node-icon\">{createIcon(treeNode.icon)}</div>\n        <div className=\"tree-node-title-label\">\n          {editing ? (\n            <input\n              className=\"tree-node-title-input\"\n              defaultValue={this.state.title}\n              onBlur={this.saveEdit}\n              ref={this.setCaret}\n              onKeyUp={this.handleKeyUp}\n            />\n          ) : (\n            <Fragment>\n              {/* @ts-ignore */}\n              <Title\n                title={this.state.title}\n                match={filterWorking && matchSelf}\n                keywords={keywords}\n              />\n              {Extra && <Extra node={treeNode?.node} />}\n              {node.slotFor && (\n                <a className=\"tree-node-tag slot\">\n                  {/* todo: click redirect to prop */}\n                  {/* @ts-ignore */}\n                  <Tip>{intlNode('Slot for {prop}', { prop: node.slotFor.key })}</Tip>\n                </a>\n              )}\n              {node.hasLoop() && (\n                <a className=\"tree-node-tag loop\">\n                  {/* todo: click todo something */}\n                  <IconLoop />\n                  {/* @ts-ignore */}\n                  <Tip>{intlNode('Loop')}</Tip>\n                </a>\n              )}\n              {this.state.condition && (\n                <a className=\"tree-node-tag cond\">\n                  {/* todo: click todo something */}\n                  <IconCond />\n                  {/* @ts-ignore */}\n                  <Tip>{intlNode('Conditional')}</Tip>\n                </a>\n              )}\n            </Fragment>\n          )}\n        </div>\n        {shouldShowHideBtn && <HideBtn hidden={this.props.hidden} treeNode={treeNode} />}\n        {shouldShowLockBtn && <LockBtn locked={this.props.locked} treeNode={treeNode} />}\n        {shouldEditBtn && <RenameBtn treeNode={treeNode} onClick={this.enableEdit} />}\n        {shouldDeleteBtn && <DeleteBtn treeNode={treeNode} onClick={this.deleteClick} />}\n      </div>\n    );\n  }\n}\n\nclass DeleteBtn extends PureComponent<{\n  treeNode: TreeNode;\n  onClick: () => void;\n}> {\n  render() {\n    const { intl, common } = this.props.treeNode.pluginContext;\n    const { Tip } = common.editorCabin;\n    return (\n      <div\n        className=\"tree-node-delete-btn\"\n        onClick={this.props.onClick}\n      >\n        <IconDelete />\n        {/* @ts-ignore */}\n        <Tip>{intl('Delete')}</Tip>\n      </div>\n    );\n  }\n}\n\nclass RenameBtn extends PureComponent<{\n  treeNode: TreeNode;\n  onClick: (e: any) => void;\n}> {\n  render() {\n    const { intl, common } = this.props.treeNode.pluginContext;\n    const { Tip } = common.editorCabin;\n    return (\n      <div\n        className=\"tree-node-rename-btn\"\n        onClick={this.props.onClick}\n      >\n        <IconSetting />\n        {/* @ts-ignore */}\n        <Tip>{intl('Rename')}</Tip>\n      </div>\n    );\n  }\n}\n\nclass LockBtn extends PureComponent<{\n  treeNode: TreeNode;\n  locked: boolean;\n}> {\n  render() {\n    const { treeNode, locked } = this.props;\n    const { intl, common } = this.props.treeNode.pluginContext;\n    const { Tip } = common.editorCabin;\n    return (\n      <div\n        className=\"tree-node-lock-btn\"\n        onClick={(e) => {\n          e.stopPropagation();\n          treeNode.setLocked(!locked);\n        }}\n      >\n        {locked ? <IconUnlock /> : <IconLock /> }\n        {/* @ts-ignore */}\n        <Tip>{locked ? intl('Unlock') : intl('Lock')}</Tip>\n      </div>\n    );\n  }\n}\n\nclass HideBtn extends PureComponent<{\n  treeNode: TreeNode;\n  hidden: boolean;\n}, {\n  hidden: boolean;\n}> {\n  render() {\n    const { treeNode, hidden } = this.props;\n    const { intl, common } = treeNode.pluginContext;\n    const { Tip } = common.editorCabin;\n    return (\n      <div\n        className=\"tree-node-hide-btn\"\n        onClick={(e) => {\n          e.stopPropagation();\n          emitOutlineEvent(treeNode.pluginContext.event, hidden ? 'show' : 'hide', treeNode);\n          treeNode.setHidden(!hidden);\n        }}\n      >\n        {hidden ? <IconEye /> : <IconEyeClose />}\n        {/* @ts-ignore */}\n        <Tip>{hidden ? intl('Show') : intl('Hide')}</Tip>\n      </div>\n    );\n  }\n}\n\nclass ExpandBtn extends PureComponent<{\n  treeNode: TreeNode;\n  expanded: boolean;\n  expandable: boolean;\n}> {\n  render() {\n    const { treeNode, expanded, expandable } = this.props;\n    if (!expandable) {\n      return <i className=\"tree-node-expand-placeholder\" />;\n    }\n    return (\n      <div\n        className=\"tree-node-expand-btn\"\n        onClick={(e) => {\n          if (expanded) {\n            e.stopPropagation();\n          }\n          emitOutlineEvent(treeNode.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode);\n          treeNode.setExpanded(!expanded);\n        }}\n      >\n        <IconArrowRight size=\"small\" />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/plugin-outline-pane/src/views/tree.tsx",
    "content": "import { MouseEvent as ReactMouseEvent, PureComponent } from 'react';\nimport { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils';\nimport { Tree } from '../controllers/tree';\nimport TreeNodeView from './tree-node';\nimport { IPublicEnumDragObjectType, IPublicModelNode } from '@alilc/lowcode-types';\nimport TreeNode from '../controllers/tree-node';\n\nfunction getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string {\n  let target: Element | null = e.target as Element;\n  if (!target || !stop.contains(target)) {\n    return null;\n  }\n  target = target.closest('[data-id]');\n  if (!target || !stop.contains(target)) {\n    return null;\n  }\n\n  return (target as HTMLDivElement).dataset.id || null;\n}\n\nexport default class TreeView extends PureComponent<{\n  tree: Tree;\n}> {\n  private shell: HTMLDivElement | null = null;\n\n  private ignoreUpSelected = false;\n\n  private boostEvent?: MouseEvent;\n\n  state: {\n    root: TreeNode | null;\n  } = {\n    root: null,\n  };\n\n  private hover(e: ReactMouseEvent) {\n    const { project } = this.props.tree.pluginContext;\n    const detecting = project.currentDocument?.detecting;\n    if (detecting?.enable) {\n      return;\n    }\n    const node = this.getTreeNodeFromEvent(e)?.node;\n    node?.id && detecting?.capture(node.id);\n  }\n\n  private onClick = (e: ReactMouseEvent) => {\n    if (this.ignoreUpSelected) {\n      this.boostEvent = undefined;\n      return;\n    }\n    if (this.boostEvent && isShaken(this.boostEvent, e.nativeEvent)) {\n      this.boostEvent = undefined;\n      return;\n    }\n    this.boostEvent = undefined;\n    const treeNode = this.getTreeNodeFromEvent(e);\n    if (!treeNode) {\n      return;\n    }\n    const { node } = treeNode;\n\n    if (!canClickNode(node, e)) {\n      return;\n    }\n\n    const { project, event, canvas } = this.props.tree.pluginContext;\n    const doc = project.currentDocument;\n    const selection = doc?.selection;\n    const focusNode = doc?.focusNode;\n    const { id } = node;\n    const isMulti = e.metaKey || e.ctrlKey || e.shiftKey;\n    canvas.activeTracker?.track(node);\n    if (isMulti && focusNode && !node.contains(focusNode) && selection?.has(id)) {\n      if (!isFormEvent(e.nativeEvent)) {\n        selection.remove(id);\n      }\n    } else {\n      selection?.select(id);\n      const selectedNode = selection?.getNodes()?.[0];\n      const npm = selectedNode?.componentMeta?.npm;\n      const selected =\n        [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||\n        selectedNode?.componentMeta?.componentName ||\n        '';\n      event.emit('outlinePane.select', {\n        selected,\n      });\n    }\n  };\n\n  private onDoubleClick = (e: ReactMouseEvent) => {\n    e.preventDefault();\n    const treeNode = this.getTreeNodeFromEvent(e);\n    if (treeNode?.nodeId === this.state.root?.nodeId) {\n      return;\n    }\n    if (!treeNode?.expanded) {\n      this.props.tree.expandAllDecendants(treeNode);\n    } else {\n      this.props.tree.collapseAllDecendants(treeNode);\n    }\n  };\n\n  private onMouseOver = (e: ReactMouseEvent) => {\n    this.hover(e);\n  };\n\n  private getTreeNodeFromEvent(e: ReactMouseEvent) {\n    if (!this.shell) {\n      return;\n    }\n    const id = getTreeNodeIdByEvent(e, this.shell);\n    if (!id) {\n      return;\n    }\n\n    const { tree } = this.props;\n    return tree.getTreeNodeById(id);\n  }\n\n  private onMouseDown = (e: ReactMouseEvent) => {\n    if (isFormEvent(e.nativeEvent)) {\n      return;\n    }\n    const treeNode = this.getTreeNodeFromEvent(e);\n    if (!treeNode) {\n      return;\n    }\n\n    const { node } = treeNode;\n\n    if (!canClickNode(node, e)) {\n      return;\n    }\n    const { project, canvas } = this.props.tree.pluginContext;\n    const selection = project.currentDocument?.selection;\n    const focusNode = project.currentDocument?.focusNode;\n\n    // TODO: shift selection\n    const isMulti = e.metaKey || e.ctrlKey || e.shiftKey;\n    const isLeftButton = e.button === 0;\n\n    if (isLeftButton && focusNode && !node.contains(focusNode)) {\n      let nodes: IPublicModelNode[] = [node];\n      this.ignoreUpSelected = false;\n      if (isMulti) {\n        // multi select mode, directily add\n        if (!selection?.has(node.id)) {\n          canvas.activeTracker?.track(node);\n          selection?.add(node.id);\n          this.ignoreUpSelected = true;\n        }\n        // todo: remove rootNodes id\n        selection?.remove(focusNode.id);\n        // 获得顶层 nodes\n        if (selection) {\n          nodes = selection.getTopNodes();\n        }\n      } else if (selection?.has(node.id)) {\n        nodes = selection.getTopNodes();\n      }\n      this.boostEvent = e.nativeEvent;\n      canvas.dragon?.boost(\n        {\n          type: IPublicEnumDragObjectType.Node,\n          nodes,\n        },\n        this.boostEvent,\n      );\n    }\n  };\n\n  private onMouseLeave = () => {\n    const { pluginContext } = this.props.tree;\n    const { project } = pluginContext;\n    const doc = project.currentDocument;\n    doc?.detecting.leave();\n  };\n\n  componentDidMount() {\n    const { tree } = this.props;\n    const { root } = tree;\n    const { project } = tree.pluginContext;\n    this.setState({ root });\n    const doc = project.currentDocument;\n    doc?.onFocusNodeChanged(() => {\n      this.setState({\n        root: tree.root,\n      });\n    });\n    doc?.onImportSchema(() => {\n      this.setState({\n        root: tree.root,\n      });\n    });\n  }\n\n  render() {\n    if (!this.state.root) {\n      return null;\n    }\n    return (\n      <div\n        className=\"lc-outline-tree\"\n        ref={(shell) => { this.shell = shell; }}\n        onMouseDownCapture={this.onMouseDown}\n        onMouseOver={this.onMouseOver}\n        onClick={this.onClick}\n        onDoubleClick={this.onDoubleClick}\n        onMouseLeave={this.onMouseLeave}\n      >\n        <TreeNodeView\n          key={this.state.root?.id}\n          treeNode={this.state.root}\n          isRootNode\n        />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/react-renderer/README.md",
    "content": ""
  },
  {
    "path": "packages/react-renderer/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"build-plugin-fusion\",\n    [\"build-plugin-moment-locales\", {\n      \"locales\": [\"zh-cn\"]\n    }]\n  ]\n}\n"
  },
  {
    "path": "packages/react-renderer/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/react-renderer/build.umd.json",
    "content": "{\n  \"entry\": {\n    \"react-renderer\": \"src/index\"\n  },\n  \"sourceMap\": true,\n  \"library\": \"AliLowCodeReactRenderer\",\n  \"libraryTarget\": \"umd\",\n  \"externals\": {\n    \"react\": \"var window.React\",\n    \"react-dom\": \"var window.ReactDOM\",\n    \"prop-types\": \"var window.PropTypes\",\n    \"@alifd/next\": \"var Next\",\n    \"moment\": \"var window.moment\"\n  },\n  \"polyfill\": false,\n  \"outputDir\": \"dist\",\n  \"vendor\": false,\n  \"ignoreHtmlTemplate\": true,\n  \"plugins\": [\n    \"build-plugin-react-app\",\n    [\"build-plugin-fusion\", {\n      \"externalNext\": \"umd\"\n    }],\n    [\"build-plugin-moment-locales\", {\n      \"locales\": [\"zh-cn\"]\n    }]\n  ]\n}"
  },
  {
    "path": "packages/react-renderer/demo/compose.md",
    "content": "---\ntitle: 复杂组件\norder: 2\n---\n\n````jsx\nimport React, { PureComponent } from 'react';\nimport ReactDOM from 'react-dom';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport schema from './schemas/compose';\nimport components from './config/components/index';\nimport utils from './config/utils';\nimport constants from './config/constants';\n\nclass Demo extends PureComponent {\n  static displayName = 'renderer-demo';\n  render() {\n    return (\n      <div className=\"demo\">\n        <ReactRenderer\n          key={schema.fileName}\n          schema={schema}\n          components={components}\n          appHelper={{\n            utils,\n            constants\n          }}\n        />\n      </div>\n    );\n  }\n}\n\nReactDOM.render((\n  <Demo />\n), mountNode);\n````\n"
  },
  {
    "path": "packages/react-renderer/demo/config/components/A.jsx",
    "content": "import React, { PureComponent } from 'react';\n\nexport default class AView extends PureComponent {\n  static displayName = 'A';\n\n  static version = '0.0.0';\n\n  render() {\n    return <a {...this.props} />;\n  }\n}\n"
  },
  {
    "path": "packages/react-renderer/demo/config/components/Div.jsx",
    "content": "import React, { PureComponent } from 'react';\n\nexport default class DivView extends PureComponent {\n  static displayName = 'Div';\n\n  static version = '0.0.0';\n\n  render() {\n    return <div {...this.props} />;\n  }\n}\n"
  },
  {
    "path": "packages/react-renderer/demo/config/components/Image.jsx",
    "content": "import React, { PureComponent } from 'react';\n\nexport default class ImageView extends PureComponent {\n  static displayName = 'Image';\n\n  static version = '0.0.0';\n\n  static defaultProps = {\n    src: '//img.alicdn.com/tfs/TB1knm4bqNj0u4jSZFyXXXgMVXa-240-240.png_100x100.jpg',\n  };\n\n  render() {\n    return <img {...this.props} />;\n  }\n}\n"
  },
  {
    "path": "packages/react-renderer/demo/config/components/Text.jsx",
    "content": "import React, { PureComponent } from 'react';\nimport PropTypes from 'prop-types';\n\nexport default class TextView extends PureComponent {\n  static displayName = 'Text';\n\n  static version = '0.0.0';\n\n  static propTypes = {\n    text: PropTypes.string,\n  };\n\n  render() {\n    const { text, ...restProps } = this.props;\n    let textNode = text;\n    // 强制类型转换\n    try {\n      textNode = text.toString();\n    } catch (e) {\n      textNode = '';\n    }\n    if (window.__ctx && window.__ctx.canvasAppHelper) {\n      textNode = textNode || 'Text';\n    }\n    return <span {...restProps}>{textNode}</span>;\n  }\n}\n"
  },
  {
    "path": "packages/react-renderer/demo/config/components/index.js",
    "content": "import Div from './Div';\nimport Text from './Text';\nimport A from './A';\nimport Image from './Image';\n\nimport {\n  Balloon,\n  Button,\n  Checkbox,\n  Dropdown,\n  Grid,\n  Menu,\n  Select,\n  Tab,\n  Table,\n  Radio,\n  Pagination,\n  Input,\n  Icon,\n  Switch,\n  Tree,\n  NumberPicker,\n  Collapse,\n  Range,\n  Dialog,\n  Overlay,\n  Search,\n  Loading,\n  MenuButton,\n  Badge,\n  Message,\n  Slider,\n  SplitButton,\n  Paragraph,\n  Nav,\n  Breadcrumb,\n  Step,\n  DatePicker,\n  TimePicker,\n  Rating,\n  Upload,\n  Tag,\n  Card,\n  Calendar,\n  Progress,\n  Cascader,\n  ConfigProvider,\n  Animate,\n  CascaderSelect,\n  Transfer,\n  TreeSelect,\n  Timeline,\n  VirtualList,\n} from '@alifd/next';\n\nconst { Row, Col } = Grid;\nconst {\n  Item: MenuItem,\n  Group: MenuGroup,\n  SubMenu,\n  PopupItem: MenuPopupItem,\n  CheckboxItem: MenuCheckboxItem,\n  RadioItem: MenuRadioItem,\n  Divider: MenuDivider,\n} = Menu;\nconst { Item: TabItem } = Tab;\nconst { Column: TableColumn, ColumnGroup: TableColumnGroup } = Table;\nconst { Group: ButtonGroup } = Button;\nconst { Group: RadioGroup } = Radio;\nconst { Node: TreeNode } = Tree;\nconst { Panel: CollapsePanel } = Collapse;\nconst { Tooltip } = Balloon;\nconst { AutoComplete: SelectAutoComplete, OptionGroup: SelectOptionGroup, Option: SelectOption } = Select;\nconst { Item: MenuButtonItem } = MenuButton;\nconst { Item: StepItem } = Step;\nconst { Item: NavItem, SubNav, PopupItem: NavPopItem, Group: NavGroup } = Nav;\nconst { Item: BreadcrumbItem } = Breadcrumb;\nconst { MonthPicker, RangePicker, YearPicker } = DatePicker;\nconst { Card: UploadCard, Dragger: UploadDragger, Selecter: UploadSelecter } = Upload;\nconst { Closeable: TagCloseable, Selectable: TagSelectable } = Tag;\nconst { Popup } = Overlay;\nconst { Node: TreeSelectNode } = TreeSelect;\nconst { Item: TimelineItem } = Timeline;\n\nexport default {\n  Div,\n  A,\n  Text,\n  Image,\n\n  Balloon,\n  Tooltip,\n  Button,\n  ButtonGroup,\n  Checkbox,\n  Row,\n  Col,\n  Select,\n  SelectAutoComplete,\n  SelectOptionGroup,\n  SelectOption,\n  Dropdown,\n  Menu,\n  MenuItem,\n  MenuGroup,\n  MenuDivider,\n  SubMenu,\n  MenuPopupItem,\n  MenuCheckboxItem,\n  MenuRadioItem,\n  MenuButton,\n  MenuButtonItem,\n  Loading,\n  Tab,\n  TabItem,\n  Table,\n  TableColumn,\n  TableColumnGroup,\n  Radio,\n  RadioGroup,\n  Pagination,\n  Input,\n  Icon,\n  Switch,\n  Tree,\n  TreeNode,\n  NumberPicker,\n  Collapse,\n  Dialog,\n  Overlay,\n  Popup,\n  CollapsePanel,\n  Range,\n  Search,\n  Badge,\n  Message,\n  Slider,\n  SplitButton,\n  Paragraph,\n  Nav,\n  NavItem,\n  NavPopItem,\n  NavGroup,\n  SubNav,\n  Breadcrumb,\n  BreadcrumbItem,\n  Rating,\n  Step,\n  StepItem,\n  DatePicker,\n  MonthPicker,\n  RangePicker,\n  YearPicker,\n  TimePicker,\n  Upload,\n  UploadCard,\n  UploadDragger,\n  UploadSelecter,\n  Tag,\n  TagCloseable,\n  TagSelectable,\n  Card,\n  Calendar,\n  Progress,\n  Cascader,\n  ConfigProvider,\n  Animate,\n  CascaderSelect,\n  Transfer,\n  TreeSelect,\n  TreeSelectNode,\n  Timeline,\n  TimelineItem,\n  VirtualList,\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/config/constants.js",
    "content": "export default {\n  name: 'renderer-demo',\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/config/utils.js",
    "content": "import { Message } from '@alifd/next';\nimport moment from 'moment';\n\nexport default {\n  Message,\n  moment,\n  test(msg) {\n    this.Message.notice(msg);\n  },\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/dataSource.md",
    "content": "---\ntitle: 数据源使用\norder: 4\n---\n\n````jsx\nimport React, { PureComponent } from 'react';\nimport ReactDOM from 'react-dom';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport schema from './schemas/dataSource';\nimport components from './config/components/index';\nimport utils from './config/utils';\nimport constants from './config/constants';\n\nclass Demo extends PureComponent {\n  static displayName = 'renderer-demo';\n  render() {\n    return (\n      <div className=\"demo\">\n        <ReactRenderer\n          key={schema.fileName}\n          schema={schema}\n          components={components}\n          appHelper={{\n            utils,\n            constants\n          }}\n        />\n      </div>\n    );\n  }\n}\n\nReactDOM.render((\n  <Demo />\n), mountNode);\n````\n"
  },
  {
    "path": "packages/react-renderer/demo/i18n.md",
    "content": "---\ntitle: 国际化\norder: 5\n---\n\n````jsx\nimport React, { PureComponent } from 'react';\nimport ReactDOM from 'react-dom';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport schema from './schemas/i18n';\nimport components from './config/components/index';\nimport utils from './config/utils';\nimport constants from './config/constants';\n\nclass Demo extends PureComponent {\n  static displayName = 'renderer-demo';\n  render() {\n    return (\n      <div className=\"demo\">\n        <ReactRenderer\n          key={schema.fileName}\n          schema={schema}\n          components={components}\n          appHelper={{\n            utils,\n            constants\n          }}\n          locale=\"zh-CN\"\n          messages={{\n            \"hello\": \"你好\",\n            \"china\": \"中国\"\n          }}\n        />\n      </div>\n    );\n  }\n}\n\nReactDOM.render((\n  <Demo />\n), mountNode);\n````\n"
  },
  {
    "path": "packages/react-renderer/demo/list.md",
    "content": "---\ntitle: 列表\norder: 1\n---\n\n````jsx\nimport React, { PureComponent } from 'react';\nimport ReactDOM from 'react-dom';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport schema from './schemas/list';\nimport components from './config/components/index';\nimport utils from './config/utils';\nimport constants from './config/constants';\n\nclass Demo extends PureComponent {\n  static displayName = 'renderer-demo';\n  render() {\n    return (\n      <div className=\"demo\">\n        <ReactRenderer\n          key={schema.fileName}\n          schema={schema}\n          components={components}\n          appHelper={{\n            utils,\n            constants\n          }}\n        />\n      </div>\n    );\n  }\n}\n\nReactDOM.render((\n  <Demo />\n), mountNode);\n````\n"
  },
  {
    "path": "packages/react-renderer/demo/schemas/compose.js",
    "content": "/* eslint-disable */\nexport default {\n  componentName: 'Page',\n  fileName: 'compose',\n  props: {\n  },\n  children: [\n    {\n      \"componentName\": \"Dropdown\",\n      \"props\": {\n        \"trigger\": [\n          {\n            \"componentName\": \"Button\",\n            \"props\": {\n              \"type\": \"primary\"\n            },\n            \"children\": \"确定\"  \n          }\n        ],  \n        \"triggerType\": \"click\"\n      },\n      \"children\": [\n        {\n          \"componentName\": \"Menu\",\n          \"props\": {\n            \"style\": {\n              \"width\": 200\n            }  \n          },\n          \"children\": [\n            { \"componentName\": \"MenuItem\", \"props\": {}, \"children\": \"Option 1\"  },\n            { \"componentName\": \"MenuItem\", \"props\": { \"disabled\": false }, \"children\": \"option 2\" },\n            { \"componentName\": \"MenuItem\", \"props\": { \"disabled\": false }, \"children\": \"option 3\" }\n          ]\n        }\n      ]\n    },\n    {\n      \"componentName\": \"Menu\",\n      \"props\": {\n        \"style\": {\n          \"width\": 200\n        }\n      },\n      \"children\": [\n        {\n          \"componentName\": \"MenuItem\",\n          \"props\": {\n          },\n          \"children\": \"Option 1\"\n        }, \n        {\n          \"componentName\": \"MenuItem\",\n          \"props\": {\n          },\n          \"children\": \"Option 2\"\n        }\n      ]\n    }\n  ]\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/schemas/dataSource.js",
    "content": "export default {\n  componentName: 'Page',\n  fileName: 'dataSource',\n  props: {},\n  children: [{\n    componentName: 'Div',\n    props: {},\n    children: [{\n      componentName: 'Text',\n      props: {\n        text: '{{this.item.title}}',\n      },\n    }, {\n      componentName: 'Switch',\n      props: {\n        checkedChildren: '开',\n        unCheckedChildren: '关',\n        checked: '{{this.item.done}}',\n      },\n    }],\n    loop: '{{this.dataSourceMap.todos.data}}',\n  }],\n  dataSource: {\n    list: [{\n      id: 'todos',\n      isInit: true,\n      type: 'jsonp',\n      options: {\n        method: 'GET',\n        uri: 'https://mocks.alibaba-inc.com/mock/D8iUX7zB/todo_getAll',\n      },\n      dataHandler: function dataHandler(data) {\n        return data.data;\n      },\n    }],\n  },\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/schemas/i18n.js",
    "content": "export default {\n  componentName: 'Page',\n  fileName: 'i18n',\n  props: {},\n  children: [{\n    componentName: 'Div',\n    props: {},\n    children: [{\n      componentName: 'Text',\n      props: {\n        text: \"{{this.i18n('hello')}}\",\n      },\n    }, {\n      componentName: 'Text',\n      props: {\n        text: \"{{this.i18n('china')}}\",\n      },\n    }],\n  }],\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/schemas/list.js",
    "content": "/* eslint-disable */\nexport default {\n  componentName: 'Page',\n  fileName: 'tab_article',\n  props: {\n    style: {\n      paddingTop: 20,\n      paddingRight: 20,\n      paddingLeft: 20\n    }\n  },\n  children: [\n    {\n      componentName: 'Div',\n      props: {\n        style: {\n          marginTop: 5,\n          marginBottom: 15,\n          borderBottom: '1px solid rgba(244,244,244)'\n        }\n      },\n      children: [\n        {\n          componentName: 'Div',\n          props: {\n            style: {\n              marginBottom: 15\n            }\n          },\n          children: [\n            {\n              componentName: 'Text',\n              props: {\n                text: '{{this.item.title}}',\n                style: {\n                  color: 'rgba(51,51,51)'\n                }\n              }\n            },\n            {\n              componentName: 'Text',\n              props: {\n                text: '{{this.item.datetime}}',\n                style: {\n                  fontSize: '12px',\n                  color: '#666',\n                  float: 'right'\n                }\n              }\n            }\n          ]\n        },\n        {\n          componentName: 'Div',\n          props: {\n            style: {\n              paddingBottom: 15,\n              fontSize: '13px',\n              color: '#666'\n            }\n          },\n          children: '{{this.item.description}}'\n        },\n        {\n          componentName: 'Div',\n          props: {\n            style: {\n              marginBottom: 15\n            }\n          },\n          children: [\n            {\n              componentName: 'Button',\n              props: {\n                type: 'normal',\n                style: {\n                  marginRight: 5,\n                  marginLeft: 5\n                },\n                size: 'small'\n              },\n              children: '{{this.item}}',\n              loop: '{{this.item.tags}}'\n            },\n            {\n              componentName: 'Div',\n              props: {\n                style: {\n                  marginBottom: 15,\n                  float: 'right'\n                }\n              },\n              children: [\n                {\n                  componentName: 'Div',\n                  props: {\n                    style: {\n                      display: 'inline-block',\n                      marginRight: 5,\n                      marginBottom: 15,\n                      marginLeft: 5,\n                      fontSize: 12,\n                      color: '#666',\n                      float: 'none'\n                    }\n                  },\n                  children: '{{\"点赞：\"+this.item.star}}'\n                },\n                {\n                  componentName: 'Div',\n                  props: {\n                    style: {\n                      display: 'inline-block',\n                      marginRight: 5,\n                      marginBottom: 15,\n                      marginLeft: 5,\n                      fontSize: 12,\n                      color: '#666',\n                      float: 'none'\n                    }\n                  },\n                  children: '{{\"喜爱：\"+this.item.like}}'\n                },\n                {\n                  componentName: 'Div',\n                  props: {\n                    style: {\n                      display: 'inline-block',\n                      marginRight: 5,\n                      marginBottom: 15,\n                      marginLeft: 5,\n                      fontSize: 12,\n                      color: '#66',\n                      float: 'none'\n                    }\n                  },\n                  children: '{{\"评论：\"+this.item.comment}}'\n                }\n              ]\n            }\n          ]\n        }\n      ],\n      loop: '{{this.state.dataSource}}'\n    },\n    {\n      componentName: 'Pagination',\n      props: {\n        shape: 'normal',\n        type: 'normal',\n        size: 'medium',\n        style: {\n          marginTop: 10,\n          marginBottom: 30,\n          textAlign: 'right'\n        },\n        onChange: function onChange(current, e) {\n          //页码发生改变时的回调函数\n          //@param {Number} current 改变后的页码数\n          //@param {Object} e 点击事件对象\n          this.page.reloadDataSource();\n        }\n      }\n    }\n  ],\n  dataSource: {\n    dataHandler: function dataHandler(dataMap) {\n      const dataSource = [\n        {\n          title: '越夏越嗨皮-7月官方营销活动-技能提升方向',\n          description:\n            '商家通过V任务选择主播并达成合作，费用按照商品链接计算，一个商品为一个价格，建议主播在一场直播里最多接60个商品，并提供不少于两个小时的直播服务，每个商品讲解时间不少于5分钟。 ',\n          tags: ['直播', '大促', '简介'],\n          datetime: '2017年12月12日 18:00',\n          star: Math.floor(Math.random() * 100) + 100,\n          like: Math.floor(Math.random() * 100) + 200,\n          comment: Math.floor(Math.random() * 100) + 100\n        },\n        {\n          title: '越夏越嗨皮-7月官方营销活动-技能提升方向',\n          description:\n            '商家通过V任务选择主播并达成合作，费用按照商品链接计算，一个商品为一个价格，建议主播在一场直播里最多接60个商品，并提供不少于两个小时的直播服务，每个商品讲解时间不少于5分钟。 ',\n          tags: ['直播', '大促', '简介'],\n          datetime: '2017年12月12日 18:00',\n          star: Math.floor(Math.random() * 100) + 100,\n          like: Math.floor(Math.random() * 100) + 200,\n          comment: Math.floor(Math.random() * 100) + 100\n        },\n        {\n          title: '越夏越嗨皮-7月官方营销活动-技能提升方向',\n          description:\n            '商家通过V任务选择主播并达成合作，费用按照商品链接计算，一个商品为一个价格，建议主播在一场直播里最多接60个商品，并提供不少于两个小时的直播服务，每个商品讲解时间不少于5分钟。 ',\n          tags: ['直播', '大促', '简介'],\n          datetime: '2017年12月12日 18:00',\n          star: Math.floor(Math.random() * 100) + 100,\n          like: Math.floor(Math.random() * 100) + 200,\n          comment: Math.floor(Math.random() * 100) + 100\n        },\n        {\n          title: '越夏越嗨皮-7月官方营销活动-技能提升方向',\n          description:\n            '商家通过V任务选择主播并达成合作，费用按照商品链接计算，一个商品为一个价格，建议主播在一场直播里最多接60个商品，并提供不少于两个小时的直播服务，每个商品讲解时间不少于5分钟。 ',\n          tags: ['直播', '大促', '简介'],\n          datetime: '2017年12月12日 18:00',\n          star: Math.floor(Math.random() * 100) + 100,\n          like: Math.floor(Math.random() * 100) + 200,\n          comment: Math.floor(Math.random() * 100) + 100\n        },\n        {\n          title: '越夏越嗨皮-7月官方营销活动-技能提升方向',\n          description:\n            '商家通过V任务选择主播并达成合作，费用按照商品链接计算，一个商品为一个价格，建议主播在一场直播里最多接60个商品，并提供不少于两个小时的直播服务，每个商品讲解时间不少于5分钟。 ',\n          tags: ['直播', '大促', '简介'],\n          datetime: '2017年12月12日 18:00',\n          star: Math.floor(Math.random() * 100) + 100,\n          like: Math.floor(Math.random() * 100) + 200,\n          comment: Math.floor(Math.random() * 100) + 100\n        }\n      ];\n      return {\n        dataSource\n      };\n    }\n  }\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/schemas/table.js",
    "content": "/* eslint-disable */\nexport default {\n  componentName: 'Page',\n  fileName: 'filterTable',\n  props: {\n    style: {\n      paddingRight: 20,\n      paddingLeft: 20\n    }\n  },\n  children: [\n    {\n      componentName: 'Table',\n      props: {\n        hasBorder: false,\n        hasHeader: true,\n        dataSource: [\n          {\n            id: 1,\n            title: '2017秋冬新款背带裙复古格子连衣裙清新背心裙a字裙短裙子',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          },\n          {\n            id: 2,\n            title: '2017秋冬新款 高质感特定纱线欧美宽松马海毛羊毛毛衣',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          },\n          {\n            id: 3,\n            title: '日式天然玉米皮草编碗垫锅垫隔热垫茶垫加厚餐垫GD-29',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          },\n          {\n            id: 4,\n            title: '2017秋冬新款 绑带腰封设计感超顺滑质感落肩铜氨丝连衣裙',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          },\n          {\n            id: 5,\n            title: '日式糖果色陶瓷柄不锈钢餐具西餐牛扒刀叉勺子咖啡勺',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          },\n          {\n            id: 6,\n            title: '日式和风深蓝素色文艺餐巾餐垫围裙锅垫隔热手套厨房桌布',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          },\n          {\n            id: 7,\n            title: '日式雪点樱花手绘陶瓷餐具米饭碗拉面碗寿司盘子汤碗',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          },\n          {\n            id: 8,\n            title: '川岛屋 釉下彩复古日式陶瓷盘子菜盘圆盘调味碟 米饭碗日式餐具',\n            url: 'https://item.taobao.com/item.htm?id=558559528377',\n            type: '清单',\n            publishTime: '17-04-28 20:29:20',\n            publishStatus: '已发布',\n            pushStatus: '已推送至订阅号',\n            operation: {\n              edit: true\n            }\n          }\n        ]\n      },\n      children: [\n        {\n          componentName: 'TableColumn',\n          props: {\n            dataIndex: 'title',\n            title: '问题描述',\n            resizable: false\n          }\n        },\n        {\n          componentName: 'TableColumn',\n          props: {\n            title: '问题分类',\n            dataIndex: 'type'\n          }\n        },\n        {\n          componentName: 'TableColumn',\n          props: {\n            title: '发布时间',\n            dataIndex: 'publishTime'\n          }\n        },\n        {\n          componentName: 'TableColumn',\n          props: {\n            title: '状态',\n            dataIndex: 'publishStatus',\n            cell: [\n              {\n                componentName: 'Button',\n                props: {\n                  type: 'normal',\n                  size: 'small',\n                  component: 'div',\n                  text: true,\n                  ghost: false,\n                  style: {\n                    width: '30px',\n                    fontSize: '12px',\n                    color: '#666',\n                    cursor: 'auto',\n                    background: '#f7f8fa'\n                  }\n                },\n                children: '已发布',\n                condition: false\n              },\n              {\n                componentName: 'Text',\n                props: {\n                  text: '已发布',\n                  style: {\n                    paddingTop: 2,\n                    paddingRight: 5,\n                    paddingBottom: 2,\n                    paddingLeft: 5,\n                    fontSize: '12px',\n                    color: '#666',\n                    borderRadius: 3,\n                    cursor: 'auto',\n                    background: '#f7f8fa'\n                  }\n                }\n              }\n            ]\n          }\n        },\n        {\n          componentName: 'TableColumn',\n          props: {\n            title: '操作',\n            cell: [\n              {\n                componentName: 'Button',\n                props: {\n                  type: 'normal',\n                  component: 'a',\n                  size: 'medium',\n                  loading: false,\n                  text: true,\n                  style: {\n                    paddingRight: 10,\n                    paddingLeft: 10,\n                    color: '#2077ff'\n                  }\n                },\n                children: '解决'\n              },\n              {\n                componentName: 'Button',\n                props: {\n                  type: 'normal',\n                  component: 'a',\n                  text: true,\n                  style: {\n                    paddingRight: 10,\n                    paddingLeft: 10,\n                    color: '#2077ff'\n                  }\n                },\n                children: '详情'\n              },\n              {\n                componentName: 'Button',\n                props: {\n                  type: 'normal',\n                  text: true,\n                  component: 'a',\n                  style: {\n                    paddingRight: 10,\n                    paddingLeft: 10,\n                    color: '#2077ff'\n                  }\n                },\n                children: '分类'\n              }\n            ]\n          }\n        }\n      ],\n      loopArgs: ['', '']\n    },\n    {\n      componentName: 'Div',\n      props: {\n        style: {\n          textAlign: 'right'\n        }\n      },\n      children: [\n        {\n          componentName: 'Pagination',\n          props: {\n            shape: 'normal',\n            type: 'normal',\n            size: 'medium',\n            style: {\n              marginTop: 20\n            }\n          }\n        }\n      ]\n    }\n  ],\n  dataSource: {\n    dataHandler: function dataHandler(dataMap) {\n      let dataSource = [\n        {\n          id: 1,\n          title: '2017秋冬新款背带裙复古格子连衣裙清新背心裙a字裙短裙子',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        },\n        {\n          id: 2,\n          title: '2017秋冬新款 高质感特定纱线欧美宽松马海毛羊毛毛衣',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        },\n        {\n          id: 3,\n          title: '日式天然玉米皮草编碗垫锅垫隔热垫茶垫加厚餐垫GD-29',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        },\n        {\n          id: 4,\n          title: '2017秋冬新款 绑带腰封设计感超顺滑质感落肩铜氨丝连衣裙',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        },\n        {\n          id: 5,\n          title: '日式糖果色陶瓷柄不锈钢餐具西餐牛扒刀叉勺子咖啡勺',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        },\n        {\n          id: 6,\n          title: '日式和风深蓝素色文艺餐巾餐垫围裙锅垫隔热手套厨房桌布',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        },\n        {\n          id: 7,\n          title: '日式雪点樱花手绘陶瓷餐具米饭碗拉面碗寿司盘子汤碗',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        },\n        {\n          id: 8,\n          title: '川岛屋 釉下彩复古日式陶瓷盘子菜盘圆盘调味碟 米饭碗日式餐具',\n          url: 'https://item.taobao.com/item.htm?id=558559528377',\n          type: '清单',\n          publishTime: '17-04-28 20:29:20',\n          publishStatus: '已发布',\n          pushStatus: '已推送至订阅号',\n          operation: {\n            edit: true\n          }\n        }\n      ];\n      return {\n        ...dataMap,\n        dataSource\n      };\n    }\n  }\n};\n"
  },
  {
    "path": "packages/react-renderer/demo/table.md",
    "content": "---\ntitle: 表格\norder: 1\n---\n\n````jsx\nimport React, { PureComponent } from 'react';\nimport ReactDOM from 'react-dom';\nimport ReactRenderer from '@alilc/lowcode-react-renderer';\nimport schema from './schemas/table';\nimport components from './config/components/index';\nimport utils from './config/utils';\nimport constants from './config/constants';\n\nclass Demo extends PureComponent {\n  static displayName = 'renderer-demo';\n  render() {\n    return (\n      <div className=\"demo\">\n        <ReactRenderer\n          key={schema.fileName}\n          schema={schema}\n          components={components}\n          appHelper={{\n            utils,\n            constants\n          }}\n        />\n      </div>\n    );\n  }\n}\n\nReactDOM.render((\n  <Demo />\n), mountNode);\n````\n"
  },
  {
    "path": "packages/react-renderer/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  // transform: {\n  //   '^.+\\\\.[jt]sx?$': 'babel-jest',\n  //   // '^.+\\\\.(ts|tsx)$': 'ts-jest',\n  //   // '^.+\\\\.(js|jsx)$': 'babel-jest',\n  // },\n  // testMatch: ['**/document/node/node.test.ts'],\n  // testMatch: ['**/designer/builtin-hotkey.test.ts'],\n  // testMatch: ['**/plugin/plugin-manager.test.ts'],\n  // testMatch: ['(/tests?/.*(test))\\\\.[jt]s$'],\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: true,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    '!src/**/*.d.ts',\n    '!**/node_modules/**',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/react-renderer/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-react-renderer\",\n  \"version\": \"1.3.2\",\n  \"description\": \"react renderer for ali lowcode engine\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"lib\",\n    \"es\",\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"test\": \"build-scripts test --config build.test.json\",\n    \"start\": \"build-scripts start\",\n    \"build\": \"build-scripts build\",\n    \"build:umd\": \"NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json\"\n  },\n  \"keywords\": [\n    \"lowcode\",\n    \"engine\",\n    \"react\"\n  ],\n  \"dependencies\": {\n    \"@alifd/next\": \"^1.21.16\",\n    \"@alilc/lowcode-renderer-core\": \"1.3.2\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@alifd/next\": \"^1.19.17\",\n    \"build-plugin-fusion\": \"^0.1.0\",\n    \"build-plugin-moment-locales\": \"^0.1.0\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-test-renderer\": \"^16\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/react-renderer\"\n  },\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\",\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\"\n}\n"
  },
  {
    "path": "packages/react-renderer/src/index.ts",
    "content": "import React, { Component, PureComponent, createElement, createContext, forwardRef, ReactInstance, ContextType } from 'react';\nimport ReactDOM from 'react-dom';\nimport {\n  adapter,\n  pageRendererFactory,\n  componentRendererFactory,\n  blockRendererFactory,\n  addonRendererFactory,\n  tempRendererFactory,\n  rendererFactory,\n  types,\n} from '@alilc/lowcode-renderer-core';\nimport ConfigProvider from '@alifd/next/lib/config-provider';\n\nwindow.React = React;\n(window as any).ReactDom = ReactDOM;\n\nadapter.setRuntime({\n  Component,\n  PureComponent,\n  createContext,\n  createElement,\n  forwardRef,\n  findDOMNode: ReactDOM.findDOMNode,\n});\n\nadapter.setRenderers({\n  PageRenderer: pageRendererFactory(),\n  ComponentRenderer: componentRendererFactory(),\n  BlockRenderer: blockRendererFactory(),\n  AddonRenderer: addonRendererFactory(),\n  TempRenderer: tempRendererFactory(),\n  DivRenderer: blockRendererFactory(),\n});\n\nadapter.setConfigProvider(ConfigProvider);\n\nfunction factory(): types.IRenderComponent {\n  const Renderer = rendererFactory();\n  return class ReactRenderer extends Renderer implements Component {\n    readonly props: types.IRendererProps;\n\n    context: ContextType<any>;\n\n    setState: (\n      state: types.IRendererState,\n      callback?: () => void,\n    ) => void;\n\n    forceUpdate: (callback?: () => void) => void;\n\n    refs: {\n      [key: string]: ReactInstance;\n    };\n\n    constructor(props: types.IRendererProps, context: ContextType<any>) {\n      super(props, context);\n    }\n\n    isValidComponent(obj: any) {\n      return obj?.prototype?.isReactComponent || obj?.prototype instanceof Component;\n    }\n  };\n}\n\nexport default factory();\n"
  },
  {
    "path": "packages/react-renderer/tests/__snapshots__/index.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`React Renderer render basic case 1`] = `\n<div\n  className=\"lce-page lce-test\"\n  style={\n    Object {\n      \"padding\": \"0 5px 0 5px\",\n    }\n  }\n>\n  <div\n    __id=\"node_dockcy8n9xed\"\n    className=\"next-box\"\n    style={\n      Object {\n        \"backgroundColor\": \"rgba(31,56,88,0.1)\",\n        \"flexDirection\": \"column\",\n        \"flexWrap\": \"nowrap\",\n        \"msFlexDirection\": \"column\",\n        \"msFlexWrap\": \"none\",\n        \"padding\": \"12px 12px 12px 12px\",\n      }\n    }\n  >\n    <div\n      __id=\"node_dockcy8n9xee\"\n      className=\"next-box\"\n      style={\n        Object {\n          \"backgroundColor\": \"#ffffff\",\n          \"flexDirection\": \"column\",\n          \"flexWrap\": \"nowrap\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n          \"padding\": \"12px 12px 12px 12px\",\n        }\n      }\n    >\n      <nav\n        __id=\"node_dockcy8n9xef\"\n        aria-label=\"Breadcrumb\"\n        style={\n          Object {\n            \"position\": \"relative\",\n          }\n        }\n      >\n        <ul\n          className=\"next-breadcrumb\"\n        >\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xeg\"\n              className=\"next-breadcrumb-text\"\n            >\n              首页\n            </span>\n            <span\n              className=\"next-breadcrumb-separator\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep\"\n                style={Object {}}\n              />\n            </span>\n          </li>\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xei\"\n              className=\"next-breadcrumb-text\"\n            >\n              品质中台\n            </span>\n            <span\n              className=\"next-breadcrumb-separator\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep\"\n                style={Object {}}\n              />\n            </span>\n          </li>\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xek\"\n              className=\"next-breadcrumb-text\"\n            >\n              商家品质页面管理\n            </span>\n            <span\n              className=\"next-breadcrumb-separator\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep\"\n                style={Object {}}\n              />\n            </span>\n          </li>\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xem\"\n              aria-current=\"page\"\n              className=\"next-breadcrumb-text activated\"\n            >\n              质检知识条配置\n            </span>\n          </li>\n        </ul>\n      </nav>\n    </div>\n    <div\n      __id=\"node_dockcy8n9xeo\"\n      className=\"next-box\"\n      style={\n        Object {\n          \"backgroundColor\": \"#ffffff\",\n          \"flexDirection\": \"column\",\n          \"flexWrap\": \"nowrap\",\n          \"marginTop\": \"12px\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n        }\n      }\n    >\n      <form\n        __events={Array []}\n        __id=\"node_dockcy8n9xep\"\n        className=\"next-form next-inline next-medium\"\n        onSubmit={[Function]}\n        role=\"grid\"\n        style={\n          Object {\n            \"marginLeft\": \"12px\",\n            \"marginRight\": \"12px\",\n            \"marginTop\": \"12px\",\n          }\n        }\n      >\n        <div\n          __id=\"node_dockcy8n9xeq\"\n          className=\"next-form-item next-left next-medium\"\n          style={\n            Object {\n              \"marginBottom\": \"0\",\n            }\n          }\n        >\n          <div\n            className=\"next-form-item-label\"\n          >\n            <label>\n              类目名：\n            </label>\n          </div>\n          <div\n            className=\"next-form-item-control\"\n          >\n            <span\n              aria-haspopup={true}\n              className=\"next-select next-select-trigger next-select-single next-medium next-inactive next-no-search\"\n              onClick={[Function]}\n              onKeyDown={[Function]}\n              onMouseDown={[Function]}\n              onMouseEnter={[Function]}\n              onMouseLeave={[Function]}\n              style={\n                Object {\n                  \"width\": \"150px\",\n                }\n              }\n            >\n              <span\n                className=\"next-input next-medium next-select-inner\"\n              >\n                <span\n                  className=\"next-select-values next-input-text-field\"\n                >\n                  <span\n                    className=\"next-select-trigger-search\"\n                  >\n                    <input\n                      __id=\"node_dockcy8n9xer\"\n                      autoComplete=\"off\"\n                      disabled={false}\n                      height=\"100%\"\n                      maxLength={null}\n                      onBlur={[Function]}\n                      onChange={[Function]}\n                      onFocus={[Function]}\n                      onKeyDown={[Function]}\n                      placeholder=\"请选择\"\n                      readOnly={true}\n                      role=\"combobox\"\n                      size=\"1\"\n                      tabIndex={0}\n                      value=\"\"\n                    />\n                    <span\n                      aria-hidden={true}\n                    >\n                      <span>\n                        请选择\n                      </span>\n                      <span>\n                         \n                      </span>\n                    </span>\n                  </span>\n                </span>\n                <span\n                  className=\"next-input-control\"\n                >\n                  <span\n                    aria-hidden={true}\n                    className=\"next-select-arrow\"\n                    onClick={[Function]}\n                  >\n                    <i\n                      className=\"next-icon next-icon-arrow-down next-medium next-select-symbol-fold\"\n                      style={Object {}}\n                    />\n                  </span>\n                </span>\n              </span>\n              <span\n                aria-live=\"polite\"\n                className=\"next-sr-only\"\n              >\n                \n              </span>\n            </span>\n             \n             \n          </div>\n        </div>\n        <div\n          __id=\"node_dockcy8n9xes\"\n          className=\"next-form-item next-left next-medium\"\n          style={\n            Object {\n              \"marginBottom\": \"0\",\n            }\n          }\n        >\n          <div\n            className=\"next-form-item-label\"\n          >\n            <label>\n              项目类型：\n            </label>\n          </div>\n          <div\n            className=\"next-form-item-control\"\n          >\n            <span\n              aria-haspopup={true}\n              className=\"next-select next-select-trigger next-select-single next-medium next-inactive next-no-search\"\n              onClick={[Function]}\n              onKeyDown={[Function]}\n              onMouseDown={[Function]}\n              onMouseEnter={[Function]}\n              onMouseLeave={[Function]}\n              style={\n                Object {\n                  \"width\": \"200px\",\n                }\n              }\n            >\n              <span\n                className=\"next-input next-medium next-select-inner\"\n              >\n                <span\n                  className=\"next-select-values next-input-text-field\"\n                >\n                  <span\n                    className=\"next-select-trigger-search\"\n                  >\n                    <input\n                      __id=\"node_dockcy8n9xet\"\n                      autoComplete=\"off\"\n                      disabled={false}\n                      height=\"100%\"\n                      maxLength={null}\n                      onBlur={[Function]}\n                      onChange={[Function]}\n                      onFocus={[Function]}\n                      onKeyDown={[Function]}\n                      placeholder=\"请选择\"\n                      readOnly={true}\n                      role=\"combobox\"\n                      size=\"1\"\n                      tabIndex={0}\n                      value=\"\"\n                    />\n                    <span\n                      aria-hidden={true}\n                    >\n                      <span>\n                        请选择\n                      </span>\n                      <span>\n                         \n                      </span>\n                    </span>\n                  </span>\n                </span>\n                <span\n                  className=\"next-input-control\"\n                >\n                  <span\n                    aria-hidden={true}\n                    className=\"next-select-arrow\"\n                    onClick={[Function]}\n                  >\n                    <i\n                      className=\"next-icon next-icon-arrow-down next-medium next-select-symbol-fold\"\n                      style={Object {}}\n                    />\n                  </span>\n                </span>\n              </span>\n              <span\n                aria-live=\"polite\"\n                className=\"next-sr-only\"\n              >\n                \n              </span>\n            </span>\n             \n             \n          </div>\n        </div>\n        <div\n          __id=\"node_dockcy8n9xeu\"\n          className=\"next-form-item next-left next-medium\"\n          style={\n            Object {\n              \"marginBottom\": \"0\",\n            }\n          }\n        >\n          <div\n            className=\"next-form-item-label\"\n          >\n            <label>\n              项目 ID：\n            </label>\n          </div>\n          <div\n            className=\"next-form-item-control\"\n          >\n            <span\n              className=\"next-input next-medium\"\n              style={\n                Object {\n                  \"width\": \"200px\",\n                }\n              }\n            >\n              <input\n                __id=\"node_dockcy8n9xev\"\n                autoComplete=\"off\"\n                disabled={false}\n                height=\"100%\"\n                maxLength={null}\n                onBlur={[Function]}\n                onChange={[Function]}\n                onFocus={[Function]}\n                onKeyDown={[Function]}\n                readOnly={false}\n                value=\"\"\n              />\n            </span>\n             \n             \n          </div>\n        </div>\n        <div\n          __id=\"node_dockcy8n9xew\"\n          className=\"next-btn-group\"\n        >\n          <button\n            __id=\"node_dockcy8n9xex\"\n            className=\"next-btn next-medium next-btn-primary\"\n            disabled={false}\n            onClick={[Function]}\n            onMouseUp={[Function]}\n            style={\n              Object {\n                \"margin\": \"0 5px 0 5px\",\n              }\n            }\n            type=\"submit\"\n          >\n            <span\n              className=\"next-btn-helper\"\n            >\n              搜索\n            </span>\n          </button>\n          <button\n            __id=\"node_dockcy8n9xe10\"\n            className=\"next-btn next-medium next-btn-normal\"\n            disabled={false}\n            onClick={[Function]}\n            onMouseUp={[Function]}\n            style={\n              Object {\n                \"margin\": \"0 5px 0 5px\",\n              }\n            }\n            type=\"reset\"\n          >\n            <span\n              className=\"next-btn-helper\"\n            >\n              清空\n            </span>\n          </button>\n        </div>\n      </form>\n    </div>\n    <div\n      __id=\"node_dockcy8n9xe1f\"\n      className=\"next-box\"\n      style={\n        Object {\n          \"backgroundColor\": \"#ffffff\",\n          \"display\": \"flex\",\n          \"flexDirection\": \"row\",\n          \"flexWrap\": \"nowrap\",\n          \"justifyContent\": \"flex-end\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n          \"paddingBottom\": \"24px\",\n        }\n      }\n    >\n      <button\n        __events={\n          Array [\n            Object {\n              \"name\": \"onClick\",\n              \"relatedEventName\": \"onClick\",\n              \"type\": \"componentEvent\",\n            },\n          ]\n        }\n        __id=\"node_dockd5nrh9p4\"\n        className=\"next-btn next-medium next-btn-primary\"\n        disabled={false}\n        onClick={[Function]}\n        onMouseUp={[Function]}\n        style={Object {}}\n        type=\"button\"\n      >\n        <span\n          className=\"next-btn-helper\"\n        >\n          新建配置\n        </span>\n      </button>\n    </div>\n    <div\n      __id=\"node_dockd5nrh9p5\"\n      className=\"next-box\"\n      style={\n        Object {\n          \"flexDirection\": \"column\",\n          \"flexWrap\": \"nowrap\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n        }\n      }\n    >\n      <div\n        __id=\"node_dockjielosj1\"\n        actionBar={\n          Array [\n            Object {\n              \"title\": \"新增\",\n              \"type\": \"primary\",\n            },\n            Object {\n              \"title\": \"编辑\",\n            },\n          ]\n        }\n        actionColumn={\n          Array [\n            Object {\n              \"callback\": [Function],\n              \"device\": Array [\n                \"desktop\",\n              ],\n              \"title\": \"编辑\",\n            },\n            Object {\n              \"callback\": [Function],\n              \"mode\": \"EDIT\",\n              \"title\": \"保存\",\n            },\n          ]\n        }\n        actionFixed=\"right\"\n        actionHidden={false}\n        actionTitle=\"操作\"\n        actionType=\"link\"\n        actionWidth={180}\n        className=\"next-table next-table-medium\"\n        data={\n          Array [\n            Object {\n              \"age\": 15000,\n              \"email\": \"aaa@abc.com\",\n              \"id\": \"1\",\n              \"name\": \"王小\",\n            },\n            Object {\n              \"age\": 25000,\n              \"email\": \"bbb@abc.com\",\n              \"id\": \"2\",\n              \"name\": \"王中\",\n            },\n            Object {\n              \"age\": 35000,\n              \"email\": \"ccc@abc.com\",\n              \"id\": \"3\",\n              \"name\": \"王大\",\n            },\n          ]\n        }\n        maxWebShownActionCount={2}\n        showActionBar={true}\n        showMiniPager={true}\n        style={Object {}}\n      >\n        <table\n          role=\"table\"\n          style={\n            Object {\n              \"width\": undefined,\n            }\n          }\n        >\n          <colgroup>\n            <col\n              style={\n                Object {\n                  \"width\": 200,\n                }\n              }\n            />\n            <col\n              style={\n                Object {\n                  \"width\": 200,\n                }\n              }\n            />\n            <col\n              style={\n                Object {\n                  \"width\": 200,\n                }\n              }\n            />\n          </colgroup>\n          <thead\n            className=\"next-table-header\"\n          >\n            <tr>\n              <th\n                className=\"next-table-cell next-table-header-node\"\n                dataKey=\"name\"\n                editType=\"text\"\n                role=\"gridcell\"\n                rowSpan={1}\n                style={\n                  Object {\n                    \"textAlign\": \"center\",\n                  }\n                }\n              >\n                <div\n                  className=\"next-table-cell-wrapper\"\n                  data-next-table-col={0}\n                >\n                  姓名\n                </div>\n              </th>\n              <th\n                className=\"next-table-cell next-table-header-node\"\n                dataKey=\"age\"\n                role=\"gridcell\"\n                rowSpan={1}\n                style={\n                  Object {\n                    \"textAlign\": \"center\",\n                  }\n                }\n              >\n                <div\n                  className=\"next-table-cell-wrapper\"\n                  data-next-table-col={1}\n                >\n                  年龄\n                </div>\n              </th>\n              <th\n                className=\"next-table-cell next-table-header-node\"\n                dataKey=\"email\"\n                role=\"gridcell\"\n                rowSpan={1}\n                style={\n                  Object {\n                    \"textAlign\": \"center\",\n                  }\n                }\n              >\n                <div\n                  className=\"next-table-cell-wrapper\"\n                  data-next-table-col={2}\n                >\n                  邮箱\n                </div>\n              </th>\n            </tr>\n          </thead>\n          <tbody\n            className=\"next-table-body\"\n          >\n            <tr>\n              <td\n                colSpan={3}\n              >\n                <div\n                  className=\"next-table-empty\"\n                  style={\n                    Object {\n                      \"left\": 0,\n                      \"overflow\": \"hidden\",\n                      \"position\": \"sticky\",\n                      \"width\": -1,\n                    }\n                  }\n                >\n                  没有数据\n                </div>\n              </td>\n            </tr>\n          </tbody>\n        </table>\n      </div>\n      <div\n        __id=\"node_dockd5nrh9pg\"\n        className=\"next-box\"\n        style={\n          Object {\n            \"display\": \"flex\",\n            \"flexDirection\": \"row\",\n            \"flexWrap\": \"nowrap\",\n            \"justifyContent\": \"flex-end\",\n            \"msFlexDirection\": \"column\",\n            \"msFlexWrap\": \"none\",\n          }\n        }\n      >\n        <div\n          __id=\"node_dockd5nrh9pf\"\n          className=\"next-pagination next-medium next-normal\"\n          style={Object {}}\n        >\n          <div\n            className=\"next-pagination-pages\"\n          >\n            <button\n              aria-label=\"上一页，当前第1页\"\n              className=\"next-btn next-medium next-btn-normal next-pagination-item next-prev\"\n              disabled={true}\n              onClick={[Function]}\n              onMouseUp={[Function]}\n              type=\"button\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-left next-xs next-btn-icon next-icon-first next-pagination-icon-prev\"\n                style={Object {}}\n              />\n              <span\n                className=\"next-btn-helper\"\n              >\n                上一页\n              </span>\n            </button>\n            <div\n              className=\"next-pagination-list\"\n            >\n              <button\n                aria-label=\"第1页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item next-current\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  1\n                </span>\n              </button>\n              <button\n                aria-label=\"第2页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  2\n                </span>\n              </button>\n              <button\n                aria-label=\"第3页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  3\n                </span>\n              </button>\n              <button\n                aria-label=\"第4页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  4\n                </span>\n              </button>\n              <i\n                className=\"next-icon next-icon-ellipsis next-medium next-pagination-ellipsis next-pagination-icon-ellipsis\"\n                style={Object {}}\n              />\n              <button\n                aria-label=\"第10页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  10\n                </span>\n              </button>\n            </div>\n            <button\n              aria-label=\"下一页，当前第1页\"\n              className=\"next-btn next-medium next-btn-normal next-pagination-item next-next\"\n              disabled={false}\n              onClick={[Function]}\n              onMouseUp={[Function]}\n              type=\"button\"\n            >\n              <span\n                className=\"next-btn-helper\"\n              >\n                下一页\n              </span>\n              <i\n                className=\"next-icon next-icon-arrow-right next-xs next-btn-icon next-icon-last next-pagination-icon-next\"\n                style={Object {}}\n              />\n            </button>\n            <span\n              className=\"next-pagination-display\"\n            >\n              <em>\n                1\n              </em>\n              /\n              10\n            </span>\n            <span\n              className=\"next-pagination-jump-text\"\n            >\n              到第\n            </span>\n            <span\n              className=\"next-input next-medium next-pagination-jump-input\"\n            >\n              <input\n                aria-label=\"请输入跳转到第几页\"\n                autoComplete=\"off\"\n                disabled={false}\n                height=\"100%\"\n                maxLength={null}\n                onBlur={[Function]}\n                onChange={[Function]}\n                onFocus={[Function]}\n                onKeyDown={[Function]}\n                readOnly={false}\n                value=\"\"\n              />\n            </span>\n            <span\n              className=\"next-pagination-jump-text\"\n            >\n              页\n            </span>\n            <button\n              className=\"next-btn next-medium next-btn-normal next-pagination-jump-go\"\n              disabled={false}\n              onClick={[Function]}\n              onMouseUp={[Function]}\n              type=\"button\"\n            >\n              <span\n                className=\"next-btn-helper\"\n              >\n                确定\n              </span>\n            </button>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n  <div\n    __id=\"node_dockd5nrh9pr\"\n    name=\"error\"\n  >\n    Component Not Found\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/react-renderer/tests/fixtures/schema/basic.ts",
    "content": "export default {\n  componentName: 'Page',\n  id: 'node_dockcviv8fo1',\n  props: {\n    ref: 'outterView',\n    autoLoading: true,\n    style: {\n      padding: '0 5px 0 5px',\n    },\n  },\n  fileName: 'test',\n  dataSource: {\n    list: [],\n  },\n  state: {\n    text: 'outter',\n    isShowDialog: false,\n  },\n  css: 'body {font-size: 12px;} .botton{width:100px;color:#ff00ff}',\n  lifeCycles: {\n    componentDidMount: {\n      type: 'JSFunction',\n      value: \"function() {\\n    console.log('did mount');\\n  }\",\n    },\n    componentWillUnmount: {\n      type: 'JSFunction',\n      value: \"function() {\\n    console.log('will umount');\\n  }\",\n    },\n  },\n  methods: {\n    testFunc: {\n      type: 'JSFunction',\n      value: \"function() {\\n    console.log('test func');\\n  }\",\n    },\n    onClick: {\n      type: 'JSFunction',\n      value: 'function() {\\n    this.setState({\\n      isShowDialog: true\\n    })\\n  }',\n    },\n    closeDialog: {\n      type: 'JSFunction',\n      value: 'function() {\\n    this.setState({\\n      isShowDialog: false\\n    })\\n  }',\n    },\n  },\n  children: [\n    {\n      componentName: 'Box',\n      id: 'node_dockcy8n9xed',\n      props: {\n        style: {\n          backgroundColor: 'rgba(31,56,88,0.1)',\n          padding: '12px 12px 12px 12px',\n        },\n      },\n      children: [\n        {\n          componentName: 'Box',\n          id: 'node_dockcy8n9xee',\n          props: {\n            style: {\n              padding: '12px 12px 12px 12px',\n              backgroundColor: '#ffffff',\n            },\n          },\n          children: [\n            {\n              componentName: 'Breadcrumb',\n              id: 'node_dockcy8n9xef',\n              props: {\n                prefix: 'next-',\n                maxNode: 100,\n                component: 'nav',\n              },\n              children: [\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xeg',\n                  props: {\n                    prefix: 'next-',\n                    children: '首页',\n                  },\n                },\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xei',\n                  props: {\n                    prefix: 'next-',\n                    children: '品质中台',\n                  },\n                },\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xek',\n                  props: {\n                    prefix: 'next-',\n                    children: '商家品质页面管理',\n                  },\n                },\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xem',\n                  props: {\n                    prefix: 'next-',\n                    children: '质检知识条配置',\n                  },\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'Box',\n          id: 'node_dockcy8n9xeo',\n          props: {\n            style: {\n              marginTop: '12px',\n              backgroundColor: '#ffffff',\n            },\n          },\n          children: [\n            {\n              componentName: 'Form',\n              id: 'node_dockcy8n9xep',\n              props: {\n                inline: true,\n                style: {\n                  marginTop: '12px',\n                  marginRight: '12px',\n                  marginLeft: '12px',\n                },\n                __events: [],\n              },\n              children: [\n                {\n                  componentName: 'Form.Item',\n                  id: 'node_dockcy8n9xeq',\n                  props: {\n                    style: {\n                      marginBottom: '0',\n                    },\n                    label: '类目名：',\n                  },\n                  children: [\n                    {\n                      componentName: 'Select',\n                      id: 'node_dockcy8n9xer',\n                      props: {\n                        mode: 'single',\n                        hasArrow: true,\n                        cacheValue: true,\n                        style: {\n                          width: '150px',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Form.Item',\n                  id: 'node_dockcy8n9xes',\n                  props: {\n                    style: {\n                      marginBottom: '0',\n                    },\n                    label: '项目类型：',\n                  },\n                  children: [\n                    {\n                      componentName: 'Select',\n                      id: 'node_dockcy8n9xet',\n                      props: {\n                        mode: 'single',\n                        hasArrow: true,\n                        cacheValue: true,\n                        style: {\n                          width: '200px',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Form.Item',\n                  id: 'node_dockcy8n9xeu',\n                  props: {\n                    style: {\n                      marginBottom: '0',\n                    },\n                    label: '项目 ID：',\n                  },\n                  children: [\n                    {\n                      componentName: 'Input',\n                      id: 'node_dockcy8n9xev',\n                      props: {\n                        hasBorder: true,\n                        size: 'medium',\n                        autoComplete: 'off',\n                        style: {\n                          width: '200px',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Button.Group',\n                  id: 'node_dockcy8n9xew',\n                  props: {},\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node_dockcy8n9xex',\n                      props: {\n                        type: 'primary',\n                        style: {\n                          margin: '0 5px 0 5px',\n                        },\n                        htmlType: 'submit',\n                        children: '搜索',\n                      },\n                    },\n                    {\n                      componentName: 'Button',\n                      id: 'node_dockcy8n9xe10',\n                      props: {\n                        type: 'normal',\n                        style: {\n                          margin: '0 5px 0 5px',\n                        },\n                        htmlType: 'reset',\n                        children: '清空',\n                      },\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'Box',\n          id: 'node_dockcy8n9xe1f',\n          props: {\n            style: {\n              backgroundColor: '#ffffff',\n              paddingBottom: '24px',\n              display: 'flex',\n              flexDirection: 'row',\n              justifyContent: 'flex-end',\n            },\n          },\n          children: [\n            {\n              componentName: 'Button',\n              id: 'node_dockd5nrh9p4',\n              props: {\n                type: 'primary',\n                size: 'medium',\n                htmlType: 'button',\n                component: 'button',\n                children: '新建配置',\n                style: {},\n                __events: [\n                  {\n                    type: 'componentEvent',\n                    name: 'onClick',\n                    relatedEventName: 'onClick',\n                  },\n                ],\n                onClick: {\n                  type: 'JSFunction',\n                  value: 'function(){ this.onClick() }',\n                },\n              },\n            },\n          ],\n        },\n        {\n          componentName: 'Box',\n          id: 'node_dockd5nrh9p5',\n          props: {},\n          children: [\n            {\n              componentName: 'Table',\n              id: 'node_dockjielosj1',\n              props: {\n                showMiniPager: true,\n                showActionBar: true,\n                actionBar: [\n                  {\n                    title: '新增',\n                    type: 'primary',\n                  },\n                  {\n                    title: '编辑',\n                  },\n                ],\n                columns: [\n                  {\n                    dataKey: 'name',\n                    width: 200,\n                    align: 'center',\n                    title: '姓名',\n                    editType: 'text',\n                  },\n                  {\n                    dataKey: 'age',\n                    width: 200,\n                    align: 'center',\n                    title: '年龄',\n                  },\n                  {\n                    dataKey: 'email',\n                    width: 200,\n                    align: 'center',\n                    title: '邮箱',\n                  },\n                ],\n                data: [\n                  {\n                    name: '王小',\n                    id: '1',\n                    age: 15000,\n                    email: 'aaa@abc.com',\n                  },\n                  {\n                    name: '王中',\n                    id: '2',\n                    age: 25000,\n                    email: 'bbb@abc.com',\n                  },\n                  {\n                    name: '王大',\n                    id: '3',\n                    age: 35000,\n                    email: 'ccc@abc.com',\n                  },\n                ],\n                actionTitle: '操作',\n                actionWidth: 180,\n                actionType: 'link',\n                actionFixed: 'right',\n                actionHidden: false,\n                maxWebShownActionCount: 2,\n                actionColumn: [\n                  {\n                    title: '编辑',\n                    callback: {\n                      type: 'JSFunction',\n                      value: '(rowData, action, table) => {\\n return table.editRow(rowData).then((row) => {\\n console.log(row);\\n });\\n }',\n                    },\n                    device: [\n                      'desktop',\n                    ],\n                  },\n                  {\n                    title: '保存',\n                    callback: {\n                      type: 'JSFunction',\n                      value: '(rowData, action, table) => { \\nreturn table.saveRow(rowData).then((row) => { \\nconsole.log(row); \\n}); \\n}',\n                    },\n                    mode: 'EDIT',\n                  },\n                ],\n              },\n            },\n            {\n              componentName: 'Box',\n              id: 'node_dockd5nrh9pg',\n              props: {\n                style: {\n                  display: 'flex',\n                  flexDirection: 'row',\n                  justifyContent: 'flex-end',\n                },\n              },\n              children: [\n                {\n                  componentName: 'Pagination',\n                  id: 'node_dockd5nrh9pf',\n                  props: {\n                    prefix: 'next-',\n                    type: 'normal',\n                    shape: 'normal',\n                    size: 'medium',\n                    defaultCurrent: 1,\n                    total: 100,\n                    pageShowCount: 5,\n                    pageSize: 10,\n                    pageSizePosition: 'start',\n                    showJump: true,\n                    style: {},\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'Dialog',\n      id: 'node_dockcy8n9xe1h',\n      props: {\n        prefix: 'next-',\n        footerAlign: 'right',\n        footerActions: [\n          'ok',\n          'cancel',\n        ],\n        closeable: 'esc,close',\n        hasMask: true,\n        align: 'cc cc',\n        minMargin: 40,\n        visible: {\n          type: 'JSExpression',\n          value: 'this.state.isShowDialog',\n        },\n        title: '标题',\n        events: [],\n        __events: [\n          {\n            type: 'componentEvent',\n            name: 'onCancel',\n            relatedEventName: 'closeDialog',\n          },\n          {\n            type: 'componentEvent',\n            name: 'onClose',\n            relatedEventName: 'closeDialog',\n          },\n          {\n            type: 'componentEvent',\n            name: 'onOk',\n            relatedEventName: 'testFunc',\n          },\n        ],\n        onCancel: {\n          type: 'JSFunction',\n          value: 'function(){ this.closeDialog() }',\n        },\n        onClose: {\n          type: 'JSFunction',\n          value: 'function(){ this.closeDialog() }',\n        },\n        onOk: {\n          type: 'JSFunction',\n          value: 'function(){ this.testFunc() }',\n        },\n      },\n      children: [\n        {\n          componentName: 'Form',\n          id: 'node_dockd5nrh9pi',\n          props: {\n            inline: false,\n            labelAlign: 'top',\n            labelTextAlign: 'right',\n            size: 'medium',\n          },\n          children: [\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pj',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node_dockd5nrh9pk',\n                  props: {\n                    mode: 'single',\n                    hasArrow: true,\n                    cacheValue: true,\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pl',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node_dockd5nrh9pm',\n                  props: {\n                    mode: 'single',\n                    hasArrow: true,\n                    cacheValue: true,\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pn',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n                asterisk: true,\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node_dockd5nrh9po',\n                  props: {\n                    mode: 'single',\n                    hasArrow: true,\n                    cacheValue: true,\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pp',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n              },\n              children: [\n                {\n                  componentName: 'Input',\n                  id: 'node_dockd5nrh9pr',\n                  props: {\n                    hasBorder: true,\n                    size: 'medium',\n                    autoComplete: 'off',\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'ErrorComponent',\n      id: 'node_dockd5nrh9pr',\n      props: {\n        name: 'error',\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/react-renderer/tests/index.test.tsx",
    "content": "import React from 'react';\nimport renderer from 'react-test-renderer';\nimport { Box, Breadcrumb, Form, Select, Input, Button, Table, Pagination, Dialog } from '@alifd/next';\nimport ReactRenderer from '../src';\nimport schema from './fixtures/schema/basic';\n\ndescribe('React Renderer', () => {\n  it('render basic case', () => {\n    const components = {\n      Box,\n      Breadcrumb,\n      'Breadcrumb.Item': Breadcrumb.Item,\n      Form,\n      'Form.Item': Form.Item,\n      Select,\n      Input,\n      Button,\n      'Button.Group': Button.Group,\n      Table,\n      Pagination,\n      Dialog,\n    };\n    const content = (\n      <ReactRenderer\n        schema={schema}\n        components={components}\n      />);\n    const tree = renderer.create(content).toJSON();\n    expect(tree).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/react-renderer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/.babelrc",
    "content": "{\n  \"plugins\": [\n    [\"@babel/plugin-proposal-decorators\", { \"legacy\": true }],\n    [\"@babel/plugin-proposal-class-properties\", { \"loose\": true }]\n  ]\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/babel.config.js",
    "content": "module.exports = require('../../babel.config');"
  },
  {
    "path": "packages/react-simulator-renderer/build.json",
    "content": "{\n  \"plugins\": [\"@alilc/build-plugin-lce\", \"./build.plugin.js\"]\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/build.plugin.js",
    "content": "module.exports = ({ onGetWebpackConfig }) => {\n  onGetWebpackConfig((config) => {\n    config.performance.hints(false);\n  });\n};\n"
  },
  {
    "path": "packages/react-simulator-renderer/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/build.umd.json",
    "content": "{\n  \"entry\": {\n    \"react-simulator-renderer\": \"src/index\"\n  },\n  \"sourceMap\": true,\n  \"library\": \"___ReactSimulatorRenderer___\",\n  \"libraryTarget\": \"umd\",\n  \"externals\": {\n    \"react\": \"var window.React\",\n    \"react-dom\": \"var window.ReactDOM\",\n    \"prop-types\": \"var window.PropTypes\",\n    \"@alifd/next\": \"var Next\",\n    \"@alilc/lowcode-engine-ext\": \"var window.AliLowCodeEngineExt\",\n    \"moment\": \"var moment\",\n    \"lodash\": \"var _\"\n  },\n  \"polyfill\": false,\n  \"outputDir\": \"dist\",\n  \"vendor\": false,\n  \"ignoreHtmlTemplate\": true,\n  \"plugins\": [\n    \"build-plugin-react-app\",\n    [\n      \"build-plugin-fusion\",\n      {\n        \"externalNext\": \"umd\"\n      }\n    ],\n    [\n      \"build-plugin-moment-locales\",\n      {\n        \"locales\": [\"zh-cn\"]\n      }\n    ],\n    \"./build.plugin.js\"\n  ]\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  // transform: {\n  //   '^.+\\\\.[jt]sx?$': 'babel-jest',\n  //   // '^.+\\\\.(ts|tsx)$': 'ts-jest',\n  //   // '^.+\\\\.(js|jsx)$': 'babel-jest',\n  // },\n  // testMatch: ['**/document/node/node.test.ts'],\n  // testMatch: ['**/designer/builtin-hotkey.test.ts'],\n  // testMatch: ['**/plugin/plugin-manager.test.ts'],\n  // testMatch: ['(/tests?/.*(test))\\\\.[jt]s$'],\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  setupFiles: ['./test/utils/host.ts'],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: true,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    '!src/**/*.d.ts',\n    '!**/node_modules/**',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/react-simulator-renderer/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-react-simulator-renderer\",\n  \"version\": \"1.3.2\",\n  \"description\": \"react simulator renderer for alibaba lowcode designer\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"license\": \"MIT\",\n  \"files\": [\n    \"es\",\n    \"lib\",\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"test\": \"build-scripts test --config build.test.json\",\n    \"build\": \"NODE_OPTIONS=--max_old_space_size=8192 build-scripts build\",\n    \"build:umd\": \"NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json\",\n    \"test:cov\": \"build-scripts test --config build.test.json --jest-coverage\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-designer\": \"1.3.2\",\n    \"@alilc/lowcode-react-renderer\": \"1.3.2\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"mobx\": \"^6.3.0\",\n    \"mobx-react\": \"^7.2.0\",\n    \"react\": \"^16\",\n    \"react-dom\": \"^16.7.0\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@types/classnames\": \"^2.2.7\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\",\n    \"@types/react-dom\": \"^16\",\n    \"@types/react-router\": \"5.1.18\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/react-simulator-renderer\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/README.md",
    "content": "沙箱环境\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/builtin-components/builtin-components.ts",
    "content": "import { ReactElement, createElement, ReactType } from 'react';\nimport classNames from 'classnames';\n\nconst supportedEvents = [\n  // MouseEvents\n  {\n    name: 'onClick',\n    description: '点击时',\n  },\n  {\n    name: 'onDoubleClick',\n    description: '双击时',\n  },\n  {\n    name: 'onMouseDown',\n    description: '鼠标按下',\n  },\n  {\n    name: 'onMouseEnter',\n    description: '鼠标进入',\n  },\n  {\n    name: 'onMouseMove',\n    description: '鼠标移动',\n  },\n  {\n    name: 'onMouseOut',\n    description: '鼠标移出',\n  },\n  {\n    name: 'onMouseOver',\n    description: '鼠标悬停',\n  },\n  {\n    name: 'onMouseUp',\n    description: '鼠标松开',\n  },\n  // Focus Events\n  {\n    name: 'onFocus',\n    description: '获得焦点',\n    snippet: '',\n  },\n  {\n    name: 'onBlur',\n    description: '失去焦点',\n    snippet: '',\n  },\n  // Form Events\n  {\n    name: 'onChange',\n    description: '值改变时',\n    snippet: '',\n  },\n  {\n    name: 'onSelect',\n    description: '选择',\n  },\n  {\n    name: 'onInput',\n    description: '输入',\n    snippet: '',\n  },\n  {\n    name: 'onReset',\n    description: '重置',\n    snippet: '',\n  },\n  {\n    name: 'onSubmit',\n    description: '提交',\n    snippet: '',\n  },\n  // Clipboard Events\n  {\n    name: 'onCopy',\n    description: '复制',\n    snippet: '',\n  },\n  {\n    name: 'onCut',\n    description: '剪切',\n    snippet: '',\n  },\n  {\n    name: 'onPaste',\n    description: '粘贴',\n    snippet: '',\n  },\n\n  // Keyboard Events\n  {\n    name: 'onKeyDown',\n    description: '键盘按下',\n    snippet: '',\n  },\n  {\n    name: 'onKeyPress',\n    description: '键盘按下并释放',\n    snippet: '',\n  },\n  {\n    name: 'onKeyUp',\n    description: '键盘松开',\n    snippet: '',\n  },\n  // Touch Events\n  {\n    name: 'onTouchCancel',\n    description: '触摸退出',\n    snippet: '',\n  },\n  {\n    name: 'onTouchEnd',\n    description: '触摸结束',\n    snippet: '',\n  },\n  {\n    name: 'onTouchMove',\n    description: '触摸移动',\n    snippet: '',\n  },\n  {\n    name: 'onTouchStart',\n    description: '触摸开始',\n    snippet: '',\n  },\n  // UI Events\n  {\n    name: 'onScroll',\n    description: '滚动',\n    snippet: '',\n  },\n  {\n    name: 'onLoad',\n    description: '加载完毕',\n    snippet: '',\n  },\n  {\n    name: 'onWheel',\n    description: '滚轮事件',\n    snippet: '',\n  },\n  // Animation Events\n  {\n    name: 'onAnimationStart',\n    description: '动画开始',\n  },\n  {\n    name: 'onAnimationEnd',\n    description: '动画结束',\n  },\n];\n\n// eslint-disable-next-line func-call-spacing\nconst builtinComponents = new Map<string, (props: any) => ReactElement>();\nfunction getBlockElement(tag: string): (props: any) => ReactElement {\n  if (builtinComponents.has(tag)) {\n    return builtinComponents.get(tag)!;\n  }\n  const mock = ({ className, children, ...rest }: any = {}) => {\n    const props = {\n      ...rest,\n      className: classNames('lc-block-container', className),\n    };\n    return createElement(tag, props, children);\n  };\n\n  mock.metadata = {\n    componentName: tag,\n    // selfControlled: true,\n    configure: {\n      props: [],\n      events: {\n        supportedEvents,\n      },\n      styles: {\n        supportClassName: true,\n        supportInlineStyle: true,\n      },\n      component: {\n        ...metasMap[tag],\n      },\n    },\n  };\n\n  builtinComponents.set(tag, mock);\n  return mock;\n}\n\nconst HTMLBlock = [\n  'div',\n  'p',\n  'article',\n  'h1',\n  'h2',\n  'h3',\n  'h4',\n  'h5',\n  'h6',\n  'aside',\n  'blockquote',\n  'footer',\n  'form',\n  'header',\n  'table',\n  'tbody',\n  'section',\n  'ul',\n  'li',\n];\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst HTMLInlineBlock = ['a', 'b', 'span', 'em'];\nexport function getIntrinsicMock(tag: string): ReactType {\n  if (HTMLBlock.indexOf(tag) > -1) {\n    return getBlockElement(tag);\n  }\n\n  return tag as any;\n}\n\nconst metasMap: any = {\n  div: {\n    isContainer: true,\n    nesting: {\n      ancestorBlacklist: 'p',\n    },\n  },\n  ul: {\n    isContainer: true,\n    nesting: {\n      childWhitelist: 'li',\n    },\n  },\n  p: {\n    isContainer: true,\n    nesting: {\n      ancestorBlacklist: 'button,p',\n    },\n  },\n  li: {\n    isContainer: true,\n    nesting: {\n      parentWhitelist: 'ui,ol',\n    },\n  },\n  span: {\n    isContainer: true,\n    selfControlled: true,\n  },\n  a: {\n    isContainer: true,\n    nesting: {\n      ancestorBlacklist: 'a',\n    },\n  },\n  b: {\n    isContainer: true,\n  },\n  strong: {\n    isContainer: true,\n  },\n  em: {\n    isContainer: true,\n  },\n  i: {\n    isContainer: true,\n  },\n  form: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'form,button',\n    },\n  },\n  table: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  caption: {\n    isContainer: true,\n    selfControlled: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  select: {\n    isContainer: true,\n    selfControlled: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  button: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  input: {\n    isContainer: false,\n    nestingRule: {\n      ancestorBlacklist: 'button,h1,h2,h3,h4,h5,h6',\n    },\n  },\n  textarea: {\n    isContainer: false,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  image: {\n    isContainer: false,\n  },\n  canvas: {\n    isContainer: false,\n  },\n  br: {\n    isContainer: false,\n  },\n  h1: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'p,h1,h2,h3,h4,h5,h6,button',\n    },\n  },\n  h2: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'p,h1,h2,h3,h4,h5,h6,button',\n    },\n  },\n  h3: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'p,h1,h2,h3,h4,h5,h6,button',\n    },\n  },\n  h4: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'p,h1,h2,h3,h4,h5,h6,button',\n    },\n  },\n  h5: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'p,h1,h2,h3,h4,h5,h6,button',\n    },\n  },\n  h6: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'p,h1,h2,h3,h4,h5,h6,button',\n    },\n  },\n  article: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  aside: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  footer: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  header: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  blockquote: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  address: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  section: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'p,h1,h2,h3,h4,h5,h6,button',\n    },\n  },\n  summary: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n  nav: {\n    isContainer: true,\n    nestingRule: {\n      ancestorBlacklist: 'button',\n    },\n  },\n};\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/builtin-components/leaf.tsx",
    "content": "import { Component } from 'react';\n\nclass Leaf extends Component {\n  static displayName = 'Leaf';\n\n  static componentMetadata = {\n    componentName: 'Leaf',\n    configure: {\n      props: [{\n        name: 'children',\n        setter: 'StringSetter',\n      }],\n      // events/className/style/general/directives\n      supports: false,\n    },\n  };\n\n  render() {\n    const { children } = this.props;\n    return children;\n  }\n}\n\nexport default Leaf;\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/builtin-components/slot.tsx",
    "content": "import { Component } from 'react';\n\nclass Slot extends Component {\n  static displayName = 'Slot';\n\n  static componentMetadata = {\n    componentName: 'Slot',\n    configure: {\n      props: [\n        {\n          name: '___title',\n          title: {\n            type: 'i18n',\n            'en-US': 'Slot Title',\n            'zh-CN': '插槽标题',\n          },\n          setter: 'StringSetter',\n          defaultValue: '插槽容器',\n        },\n        {\n          name: '___params',\n          title: {\n            type: 'i18n',\n            'en-US': 'Slot Params',\n            'zh-CN': '插槽入参',\n          },\n          setter: {\n            componentName: 'ArraySetter',\n            props: {\n              itemSetter: {\n                componentName: 'StringSetter',\n                props: {\n                  placeholder: {\n                    type: 'i18n',\n                    'zh-CN': '参数名称',\n                    'en-US': 'Argument Name',\n                  },\n                },\n              },\n            },\n          },\n        },\n      ],\n      component: {\n        isContainer: true,\n      },\n      // events/className/style/general/directives\n      supports: false,\n    },\n  };\n\n  render() {\n    const { children } = this.props;\n    return <>{children}</>;\n  }\n}\n\nexport default Slot;\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/host.ts",
    "content": "// NOTE: 仅做类型标注，切勿做其它用途\nimport { BuiltinSimulatorHost } from '@alilc/lowcode-designer';\n\nexport const host: BuiltinSimulatorHost = (window as any).LCSimulatorHost;\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/index.ts",
    "content": "import { runInAction } from 'mobx';\nimport renderer from './renderer';\n\nif (typeof window !== 'undefined') {\n  (window as any).SimulatorRenderer = renderer;\n}\n\nwindow.addEventListener('beforeunload', () => {\n  runInAction(() => {\n    (window as any).LCSimulatorHost = null;\n    renderer.dispose?.();\n    (window as any).SimulatorRenderer = null;\n    (window as any).ReactDOM.unmountComponentAtNode(document.getElementById('app'));\n  });\n});\n\nexport default renderer;\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/locale/en-US.json",
    "content": "{\n  \"Drag and drop components or templates here\": \"Drag and drop components or templates here\",\n  \"Locked elements and child elements cannot be edited\": \"Locked elements and child elements cannot be edited\"\n}"
  },
  {
    "path": "packages/react-simulator-renderer/src/locale/index.ts",
    "content": "import { createElement } from 'react';\nimport enUS from './en-US.json';\nimport zhCN from './zh-CN.json';\n\nconst instance: Record<string, Record<string, string>> = {\n  'zh-CN': zhCN as Record<string, string>,\n  'en-US': enUS as Record<string, string>,\n};\n\nexport function createIntl(locale: string = 'zh-CN') {\n  const intl = (id: string) => {\n    return instance[locale]?.[id] || id;\n  };\n\n  const intlNode = (id: string) => createElement('span', instance[locale]?.[id] || id);\n\n  return {\n    intl,\n    intlNode,\n  };\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/locale/zh-CN.json",
    "content": "{\n  \"Drag and drop components or templates here\": \"拖拽组件或模板到这里\",\n  \"Locked elements and child elements cannot be edited\": \"锁定元素及子元素无法编辑\"\n}"
  },
  {
    "path": "packages/react-simulator-renderer/src/renderer-view.tsx",
    "content": "import { ReactInstance, Fragment, Component, createElement } from 'react';\nimport { Router, Route, Switch } from 'react-router';\nimport cn from 'classnames';\nimport { Node } from '@alilc/lowcode-designer';\nimport LowCodeRenderer from '@alilc/lowcode-react-renderer';\nimport { observer } from 'mobx-react';\nimport { getClosestNode, isFromVC, isReactComponent } from '@alilc/lowcode-utils';\nimport { GlobalEvent } from '@alilc/lowcode-types';\nimport { SimulatorRendererContainer, DocumentInstance } from './renderer';\nimport { host } from './host';\nimport { isRendererDetached } from './utils/misc';\nimport './renderer.less';\nimport { createIntl } from './locale';\n\n// patch cloneElement avoid lost keyProps\nconst originCloneElement = window.React.cloneElement;\n(window as any).React.cloneElement = (child: any, { _leaf, ...props }: any = {}, ...rest: any[]) => {\n  if (child.ref && props.ref) {\n    const dRef = props.ref;\n    const cRef = child.ref;\n    props.ref = (x: any) => {\n      if (cRef) {\n        if (typeof cRef === 'function') {\n          cRef(x);\n        } else {\n          try {\n            cRef.current = x;\n          } catch (e) {\n            console.error(e);\n          }\n        }\n      }\n      if (dRef) {\n        if (typeof dRef === 'function') {\n          dRef(x);\n        } else {\n          try {\n            dRef.current = x;\n          } catch (e) {\n            console.error(e);\n          }\n        }\n      }\n    };\n  }\n  return originCloneElement(child, props, ...rest);\n};\n\nexport default class SimulatorRendererView extends Component<{ rendererContainer: SimulatorRendererContainer }> {\n  render() {\n    const { rendererContainer } = this.props;\n    return (\n      <Router history={rendererContainer.history}>\n        <Layout rendererContainer={rendererContainer}>\n          <Routes rendererContainer={rendererContainer} />\n        </Layout>\n      </Router>\n    );\n  }\n}\n\n@observer\nexport class Routes extends Component<{ rendererContainer: SimulatorRendererContainer }> {\n  render() {\n    const { rendererContainer } = this.props;\n    return (\n      <Switch>\n        {rendererContainer.documentInstances.map((instance) => {\n          return (\n            <Route\n              path={instance.path}\n              key={instance.id}\n              render={(routeProps) => <Renderer documentInstance={instance} rendererContainer={rendererContainer} {...routeProps} />}\n            />\n          );\n        })}\n      </Switch>\n    );\n  }\n}\nfunction ucfirst(s: string) {\n  return s.charAt(0).toUpperCase() + s.substring(1);\n}\nfunction getDeviceView(view: any, device: string, mode: string) {\n  if (!view || typeof view === 'string') {\n    return view;\n  }\n\n  // compatible vision Mobile | Preview\n  device = ucfirst(device);\n  if (device === 'Mobile' && view.hasOwnProperty(device)) {\n    view = view[device];\n  }\n  mode = ucfirst(mode);\n  if (mode === 'Preview' && view.hasOwnProperty(mode)) {\n    view = view[mode];\n  }\n  return view;\n}\n\n@observer\nclass Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> {\n  render() {\n    const { rendererContainer, children } = this.props;\n    const { layout } = rendererContainer;\n    if (layout) {\n      const { Component, props, componentName } = layout;\n      if (Component) {\n        return <Component key=\"layout\" props={props}>{children}</Component>;\n      }\n      if (componentName && rendererContainer.getComponent(componentName)) {\n        return createElement(\n          rendererContainer.getComponent(componentName),\n          {\n            ...props,\n            rendererContainer,\n            key: 'layout',\n          },\n          [children],\n        );\n      }\n    }\n\n    return <Fragment>{children}</Fragment>;\n  }\n}\n\n@observer\nclass Renderer extends Component<{\n  rendererContainer: SimulatorRendererContainer;\n  documentInstance: DocumentInstance;\n}> {\n  startTime: number | null = null;\n  schemaChangedSymbol = false;\n\n  componentDidUpdate() {\n    this.recordTime();\n  }\n\n  recordTime() {\n    if (this.startTime) {\n      const time = Date.now() - this.startTime;\n      const nodeCount = host.designer.currentDocument?.getNodeCount?.();\n      host.designer.editor?.eventBus.emit(GlobalEvent.Node.Rerender, {\n        componentName: 'Renderer',\n        type: 'All',\n        time,\n        nodeCount,\n      });\n    }\n  }\n\n  componentDidMount() {\n    this.recordTime();\n  }\n\n  getSchemaChangedSymbol = () => {\n    return this.schemaChangedSymbol;\n  };\n\n  setSchemaChangedSymbol = (symbol: boolean) => {\n    this.schemaChangedSymbol = symbol;\n  };\n\n  render() {\n    const { documentInstance, rendererContainer: renderer } = this.props;\n    const { container, document } = documentInstance;\n    const { designMode, device, locale } = container;\n    const messages = container.context?.utils?.i18n?.messages || {};\n    this.startTime = Date.now();\n    this.schemaChangedSymbol = false;\n\n    if (!container.autoRender || isRendererDetached()) {\n      return null;\n    }\n\n    const { intl } = createIntl(locale);\n\n    return (\n      <LowCodeRenderer\n        locale={locale}\n        messages={messages}\n        schema={documentInstance.schema}\n        components={container.components}\n        appHelper={container.context}\n        designMode={designMode}\n        device={device}\n        documentId={document.id}\n        suspended={renderer.suspended}\n        self={renderer.scope}\n        getSchemaChangedSymbol={this.getSchemaChangedSymbol}\n        setSchemaChangedSymbol={this.setSchemaChangedSymbol}\n        getNode={(id: string) => documentInstance.getNode(id) as Node}\n        rendererName=\"PageRenderer\"\n        thisRequiredInJSE={host.thisRequiredInJSE}\n        notFoundComponent={host.notFoundComponent}\n        faultComponent={host.faultComponent}\n        faultComponentMap={host.faultComponentMap}\n        customCreateElement={(Component: any, props: any, children: any) => {\n          const { __id, ...viewProps } = props;\n          viewProps.componentId = __id;\n          const leaf = documentInstance.getNode(__id) as Node;\n          if (isFromVC(leaf?.componentMeta)) {\n            viewProps._leaf = leaf.internalToShellNode();\n          }\n          viewProps._componentName = leaf?.componentName;\n          // 如果是容器 && 无children && 高宽为空 增加一个占位容器，方便拖动\n          if (\n            !viewProps.dataSource &&\n            leaf?.isContainer() &&\n            (children == null || (Array.isArray(children) && !children.length)) &&\n            (!viewProps.style || Object.keys(viewProps.style).length === 0)\n          ) {\n            let defaultPlaceholder = intl('Drag and drop components or templates here');\n            const lockedNode = getClosestNode(leaf, (node) => {\n              return node?.getExtraProp('isLocked')?.getValue() === true;\n            });\n            if (lockedNode) {\n              defaultPlaceholder = intl('Locked elements and child elements cannot be edited');\n            }\n            children = (\n              <div className={cn('lc-container-placeholder', { 'lc-container-locked': !!lockedNode })} style={viewProps.placeholderStyle}>\n                {viewProps.placeholder || defaultPlaceholder}\n              </div>\n            );\n          }\n          if (viewProps._componentName === 'a') {\n            delete viewProps.href;\n          }\n          // FIXME: 渲染仍有问题\n          if (viewProps._componentName === 'Menu') {\n            Object.assign(viewProps, {\n              _componentName: 'Menu',\n              className: '_css_pesudo_menu_kbrzyh0f',\n              context: { VE: (window as any).VisualEngine },\n              direction: undefined,\n              events: { ignored: true },\n              fieldId: 'menu_kbrzyh0f',\n              footer: '',\n              header: '',\n              mode: 'inline',\n              onItemClick: { ignored: true },\n              onSelect: { ignored: true },\n              popupAlign: 'follow',\n              selectMode: false,\n              triggerType: 'click',\n            });\n          }\n\n          if (!isReactComponent(Component)) {\n            console.error(`${viewProps._componentName} is not a react component!`);\n            return null;\n          }\n\n          return createElement(\n            getDeviceView(Component, device, designMode),\n            viewProps,\n            leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : children,\n          );\n        }}\n        __host={host}\n        __container={container}\n        onCompGetRef={(schema: any, ref: ReactInstance | null) => {\n          documentInstance.mountInstance(schema.id, ref);\n        }}\n        enableStrictNotFoundMode={host.enableStrictNotFoundMode}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/renderer.less",
    "content": "body, html {\n  display: block;\n  background: white;\n  padding: 0;\n  margin: 0;\n}\n\nhtml.engine-design-mode {\n  padding-bottom: 0;\n}\n\nhtml.engine-cursor-move, html.engine-cursor-move * {\n  cursor: grabbing !important;\n}\n\nhtml.engine-cursor-copy, html.engine-cursor-copy * {\n  cursor: copy !important;\n}\n\nhtml.engine-cursor-ew-resize, html.engine-cursor-ew-resize * {\n  cursor: ew-resize !important;\n}\n\n::-webkit-scrollbar {\n  width: 5px;\n  height: 5px;\n}\n\n::-webkit-scrollbar-thumb {\n  background-color: rgba(0, 0, 0, 0.3);\n  border-radius: 5px;\n}\n\n.lc-container {\n  &:empty {\n    background: #f2f3f5;\n    color: #a7b1bd;\n    outline: 1px dashed rgba(31, 56, 88, 0.2);\n    outline-offset: -1px !important;\n    height: 66px;\n    max-height: 100%;\n    min-width: 140px;\n    text-align: center;\n    overflow: hidden;\n    display: flex;\n    align-items: center;\n    &:before {\n      content: '\\62D6\\62FD\\7EC4\\4EF6\\6216\\6A21\\677F\\5230\\8FD9\\91CC';\n      font-size: 14px;\n      z-index: 1;\n      width: 100%;\n      white-space: nowrap;\n    }\n  }\n}\n\n.lc-container-placeholder {\n  min-height: 60px;\n  height: 100%;\n  width: 100%;\n  background-color: rgb(240, 240, 240);\n  border: 1px dotted;\n  color: rgb(167, 177, 189);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 14px;\n\n  &.lc-container-locked {\n    background: #eccfcf;\n  }\n}\n\nbody.engine-document {\n  &:after, &:before {\n    content: \"\";\n    display: table;\n  }\n  &:after {\n    clear: both;\n  }\n}\n\n.engine-live-editing {\n  cursor: text;\n  outline: none;\n  box-shadow: 0 0 0 2px rgb(102, 188, 92);\n  user-select: text;\n}\n\n#app {\n  height: 100vh;\n}\n\n\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/renderer.ts",
    "content": "import React, { createElement, ReactInstance } from 'react';\nimport { render as reactRender } from 'react-dom';\nimport { host } from './host';\nimport SimulatorRendererView from './renderer-view';\nimport { computed, observable as obx, untracked, makeObservable, configure } from 'mobx';\nimport { getClientRects } from './utils/get-client-rects';\nimport { reactFindDOMNodes, getReactInternalFiber } from './utils/react-find-dom-nodes';\nimport {\n  Asset,\n  isElement,\n  cursor,\n  setNativeSelection,\n  buildComponents,\n  getSubComponent,\n  compatibleLegaoSchema,\n  isPlainObject,\n  AssetLoader,\n  getProjectUtils,\n} from '@alilc/lowcode-utils';\nimport { IPublicTypeComponentSchema, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types';\n// just use types\nimport { BuiltinSimulatorRenderer, Component, IDocumentModel, INode } from '@alilc/lowcode-designer';\nimport LowCodeRenderer from '@alilc/lowcode-react-renderer';\nimport { createMemoryHistory, MemoryHistory } from 'history';\nimport Slot from './builtin-components/slot';\nimport Leaf from './builtin-components/leaf';\nimport { withQueryParams, parseQuery } from './utils/url';\nimport { merge } from 'lodash';\n\nconst loader = new AssetLoader();\nconfigure({ enforceActions: 'never' });\n\nexport class DocumentInstance {\n  instancesMap = new Map<string, ReactInstance[]>();\n\n  get schema(): any {\n    return this.document.export(IPublicEnumTransformStage.Render);\n  }\n\n  private disposeFunctions: Array<() => void> = [];\n\n  @obx.ref private _components: any = {};\n\n  @computed get components(): object {\n    // 根据 device 选择不同组件，进行响应式\n    // 更好的做法是，根据 device 选择加载不同的组件资源，甚至是 simulatorUrl\n    return this._components;\n  }\n\n  // context from: utils、constants、history、location、match\n  @obx.ref private _appContext = {};\n\n  @computed get context(): any {\n    return this._appContext;\n  }\n\n  @obx.ref private _designMode = 'design';\n\n  @computed get designMode(): any {\n    return this._designMode;\n  }\n\n  @obx.ref private _requestHandlersMap = null;\n\n  @computed get requestHandlersMap(): any {\n    return this._requestHandlersMap;\n  }\n\n  @obx.ref private _device = 'default';\n\n  @computed get device() {\n    return this._device;\n  }\n\n  @obx.ref private _componentsMap = {};\n\n  @computed get componentsMap(): any {\n    return this._componentsMap;\n  }\n\n  @computed get suspended(): any {\n    return false;\n  }\n\n  @computed get scope(): any {\n    return null;\n  }\n\n  get path(): string {\n    return `/${this.document.fileName}`;\n  }\n\n  get id() {\n    return this.document.id;\n  }\n\n  constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) {\n    makeObservable(this);\n  }\n\n  private unmountInstance(id: string, instance: ReactInstance) {\n    const instances = this.instancesMap.get(id);\n    if (instances) {\n      const i = instances.indexOf(instance);\n      if (i > -1) {\n        instances.splice(i, 1);\n        host.setInstance(this.document.id, id, instances);\n      }\n    }\n  }\n\n  mountInstance(id: string, instance: ReactInstance | null) {\n    const docId = this.document.id;\n    const { instancesMap } = this;\n    if (instance == null) {\n      let instances = this.instancesMap.get(id);\n      if (instances) {\n        instances = instances.filter(checkInstanceMounted);\n        if (instances.length > 0) {\n          instancesMap.set(id, instances);\n          host.setInstance(this.document.id, id, instances);\n        } else {\n          instancesMap.delete(id);\n          host.setInstance(this.document.id, id, null);\n        }\n      }\n      return;\n    }\n    const unmountInstance = this.unmountInstance.bind(this);\n    const origId = (instance as any)[SYMBOL_VNID];\n    if (origId && origId !== id) {\n      // 另外一个节点的 instance 在此被复用了，需要从原来地方卸载\n      unmountInstance(origId, instance);\n    }\n    if (isElement(instance)) {\n      cacheReactKey(instance);\n    } else if (origId !== id) {\n      // 涵盖 origId == null || origId !== id 的情况\n      let origUnmount: any = instance.componentWillUnmount;\n      if (origUnmount && origUnmount.origUnmount) {\n        origUnmount = origUnmount.origUnmount;\n      }\n      // hack! delete instance from map\n      const newUnmount = function (this: any) {\n        unmountInstance(id, instance);\n        origUnmount && origUnmount.call(this);\n      };\n      (newUnmount as any).origUnmount = origUnmount;\n      instance.componentWillUnmount = newUnmount;\n    }\n\n    (instance as any)[SYMBOL_VNID] = id;\n    (instance as any)[SYMBOL_VDID] = docId;\n    let instances = this.instancesMap.get(id);\n    if (instances) {\n      const l = instances.length;\n      instances = instances.filter(checkInstanceMounted);\n      let updated = instances.length !== l;\n      if (!instances.includes(instance)) {\n        instances.push(instance);\n        updated = true;\n      }\n      if (!updated) {\n        return;\n      }\n    } else {\n      instances = [instance];\n    }\n    instancesMap.set(id, instances);\n    host.setInstance(this.document.id, id, instances);\n  }\n\n  mountContext() {\n  }\n\n  getNode(id: string): INode | null {\n    return this.document.getNode(id);\n  }\n\n  dispose() {\n    this.disposeFunctions.forEach(fn => fn());\n    this.instancesMap = new Map();\n  }\n}\n\nexport class SimulatorRendererContainer implements BuiltinSimulatorRenderer {\n  readonly isSimulatorRenderer = true;\n  private disposeFunctions: Array<() => void> = [];\n  readonly history: MemoryHistory;\n\n  @obx.ref private _documentInstances: DocumentInstance[] = [];\n  private _requestHandlersMap: any;\n  get documentInstances() {\n    return this._documentInstances;\n  }\n\n  @obx private _layout: any = null;\n\n  @computed get layout(): any {\n    // TODO: parse layout Component\n    return this._layout;\n  }\n\n  set layout(value: any) {\n    this._layout = value;\n  }\n\n  private _libraryMap: { [key: string]: string } = {};\n\n  private _components: Record<string, React.FC | React.ComponentClass> | null = {};\n\n  get components(): Record<string, React.FC | React.ComponentClass> {\n    // 根据 device 选择不同组件，进行响应式\n    // 更好的做法是，根据 device 选择加载不同的组件资源，甚至是 simulatorUrl\n    return this._components || {};\n  }\n  // context from: utils、constants、history、location、match\n  @obx.ref private _appContext: any = {};\n  @computed get context(): any {\n    return this._appContext;\n  }\n  @obx.ref private _designMode: string = 'design';\n  @computed get designMode(): any {\n    return this._designMode;\n  }\n  @obx.ref private _device: string = 'default';\n  @computed get device() {\n    return this._device;\n  }\n  @obx.ref private _locale: string | undefined = undefined;\n  @computed get locale() {\n    return this._locale;\n  }\n  @obx.ref private _componentsMap = {};\n  @computed get componentsMap(): any {\n    return this._componentsMap;\n  }\n\n  /**\n   * 是否为画布自动渲染\n   */\n  autoRender = true;\n\n  /**\n   * 画布是否自动监听事件来重绘节点\n   */\n  autoRepaintNode = true;\n\n  private _running = false;\n\n  constructor() {\n    makeObservable(this);\n    this.autoRender = host.autoRender;\n\n    this.disposeFunctions.push(host.connect(this, () => {\n      // sync layout config\n      this._layout = host.project.get('config').layout;\n\n      // todo: split with others, not all should recompute\n      if (this._libraryMap !== host.libraryMap\n        || this._componentsMap !== host.designer.componentsMap) {\n        this._libraryMap = host.libraryMap || {};\n        this._componentsMap = host.designer.componentsMap;\n        this.buildComponents();\n      }\n\n      // sync designMode\n      this._designMode = host.designMode;\n\n      this._locale = host.locale;\n\n      // sync requestHandlersMap\n      this._requestHandlersMap = host.requestHandlersMap;\n\n      // sync device\n      this._device = host.device;\n    }));\n    const documentInstanceMap = new Map<string, DocumentInstance>();\n    let initialEntry = '/';\n    let firstRun = true;\n    this.disposeFunctions.push(host.autorun(() => {\n      this._documentInstances = host.project.documents.map((doc) => {\n        let inst = documentInstanceMap.get(doc.id);\n        if (!inst) {\n          inst = new DocumentInstance(this, doc);\n          documentInstanceMap.set(doc.id, inst);\n        }\n        return inst;\n      });\n      const path = host.project.currentDocument\n        ? documentInstanceMap.get(host.project.currentDocument.id)!.path\n        : '/';\n      if (firstRun) {\n        initialEntry = path;\n        firstRun = false;\n      } else if (this.history.location.pathname !== path) {\n        this.history.replace(path);\n      }\n    }));\n    const history = createMemoryHistory({\n      initialEntries: [initialEntry],\n    });\n    this.history = history;\n    history.listen((location) => {\n      const docId = location.pathname.slice(1);\n      docId && host.project.open(docId);\n    });\n    host.componentsConsumer.consume(async (componentsAsset) => {\n      if (componentsAsset) {\n        await this.load(componentsAsset);\n        this.buildComponents();\n      }\n    });\n    this._appContext = {\n      utils: {\n        router: {\n          push(path: string, params?: object) {\n            history.push(withQueryParams(path, params));\n          },\n          replace(path: string, params?: object) {\n            history.replace(withQueryParams(path, params));\n          },\n        },\n        legaoBuiltins: {\n          getUrlParams() {\n            const { search } = history.location;\n            return parseQuery(search);\n          },\n        },\n        i18n: {\n          setLocale: (loc: string) => {\n            this._appContext.utils.i18n.currentLocale = loc;\n            this._locale = loc;\n          },\n          currentLocale: this.locale,\n          messages: {},\n        },\n        ...getProjectUtils(this._libraryMap, host.get('utilsMetadata')),\n      },\n      constants: {},\n      requestHandlersMap: this._requestHandlersMap,\n    };\n\n    host.injectionConsumer.consume((data) => {\n      // TODO: sync utils, i18n, contants,... config\n      const newCtx = {\n        ...this._appContext,\n      };\n      merge(newCtx, data.appHelper || {});\n      this._appContext = newCtx;\n    });\n\n    host.i18nConsumer.consume((data) => {\n      const newCtx = {\n        ...this._appContext,\n      };\n      newCtx.utils.i18n.messages = data || {};\n      this._appContext = newCtx;\n    });\n  }\n\n  private buildComponents() {\n    this._components = buildComponents(\n        this._libraryMap,\n        this._componentsMap,\n        this.createComponent.bind(this),\n      );\n    this._components = {\n      ...builtinComponents,\n      ...this._components,\n    };\n  }\n\n  /**\n   * 加载资源\n   */\n  load(asset: Asset): Promise<any> {\n    return loader.load(asset);\n  }\n\n  async loadAsyncLibrary(asyncLibraryMap: Record<string, any>) {\n    await loader.loadAsyncLibrary(asyncLibraryMap);\n    this.buildComponents();\n  }\n\n  getComponent(componentName: string) {\n    const paths = componentName.split('.');\n    const subs: string[] = [];\n\n    while (true) {\n      const component = this._components?.[componentName];\n      if (component) {\n        return getSubComponent(component, subs);\n      }\n\n      const sub = paths.pop();\n      if (!sub) {\n        return null;\n      }\n      subs.unshift(sub);\n      componentName = paths.join('.');\n    }\n  }\n\n  getClosestNodeInstance(from: ReactInstance, nodeId?: string): IPublicTypeNodeInstance<ReactInstance> | null {\n    return getClosestNodeInstance(from, nodeId);\n  }\n\n  findDOMNodes(instance: ReactInstance): Array<Element | Text> | null {\n    return reactFindDOMNodes(instance);\n  }\n\n  getClientRects(element: Element | Text) {\n    return getClientRects(element);\n  }\n\n  setNativeSelection(enableFlag: boolean) {\n    setNativeSelection(enableFlag);\n  }\n\n  setDraggingState(state: boolean) {\n    cursor.setDragging(state);\n  }\n\n  setCopyState(state: boolean) {\n    cursor.setCopy(state);\n  }\n\n  clearState() {\n    cursor.release();\n  }\n\n  createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null {\n    const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = {\n      ...schema,\n      componentsTree: schema.componentsTree.map(compatibleLegaoSchema),\n    };\n\n    const componentsTreeSchema = _schema.componentsTree[0];\n\n    if (componentsTreeSchema.componentName === 'Component' && componentsTreeSchema.css) {\n      const doc = window.document;\n      const s = doc.createElement('style');\n      s.setAttribute('type', 'text/css');\n      s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`);\n      s.appendChild(doc.createTextNode(componentsTreeSchema.css || ''));\n      doc.getElementsByTagName('head')[0].appendChild(s);\n    }\n\n    const renderer = this;\n\n    class LowCodeComp extends React.Component<any, any> {\n      render() {\n        const extraProps = getLowCodeComponentProps(this.props);\n        return createElement(LowCodeRenderer, {\n          ...extraProps, // 防止覆盖下面内置属性\n          // 使用 _schema 为了使低代码组件在页面设计中使用变量，同 react 组件使用效果一致\n          schema: componentsTreeSchema,\n          components: renderer.components,\n          designMode: '',\n          locale: renderer.locale,\n          messages: _schema.i18n || {},\n          device: renderer.device,\n          appHelper: renderer.context,\n          rendererName: 'LowCodeRenderer',\n          thisRequiredInJSE: host.thisRequiredInJSE,\n          faultComponent: host.faultComponent,\n          faultComponentMap: host.faultComponentMap,\n          customCreateElement: (Comp: any, props: any, children: any) => {\n            const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName);\n            if (componentMeta?.isModal) {\n              return null;\n            }\n\n            const { __id, __designMode, ...viewProps } = props;\n            // mock _leaf，减少性能开销\n            const _leaf = {\n              isEmpty: () => false,\n              isMock: true,\n            };\n            viewProps._leaf = _leaf;\n            return createElement(Comp, viewProps, children);\n          },\n        });\n      }\n    }\n\n    return LowCodeComp;\n  }\n\n  run() {\n    if (this._running) {\n      return;\n    }\n    this._running = true;\n    const containerId = 'app';\n    let container = document.getElementById(containerId);\n    if (!container) {\n      container = document.createElement('div');\n      document.body.appendChild(container);\n      container.id = containerId;\n    }\n\n    // ==== compatible vision\n    document.documentElement.classList.add('engine-page');\n    document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends\n\n    reactRender(createElement(SimulatorRendererView, { rendererContainer: this }), container);\n    host.project.setRendererReady(this);\n  }\n\n  /**\n   * 刷新渲染器\n   */\n  rerender() {\n    this.autoRender = true;\n    // TODO: 不太优雅\n    this._appContext = { ...this._appContext };\n  }\n\n  stopAutoRepaintNode() {\n    this.autoRepaintNode = false;\n  }\n\n  enableAutoRepaintNode() {\n    this.autoRepaintNode = true;\n  }\n\n  dispose() {\n    this.disposeFunctions.forEach((fn) => fn());\n    this.documentInstances.forEach((docInst) => docInst.dispose());\n    untracked(() => {\n      this._componentsMap = {};\n      this._components = null;\n      this._appContext = null;\n    });\n  }\n}\n\n// Slot/Leaf and Fragment|FunctionComponent polyfill(ref)\n\nconst builtinComponents = {\n  Slot,\n  Leaf,\n};\n\nlet REACT_KEY = '';\nfunction cacheReactKey(el: Element): Element {\n  if (REACT_KEY !== '') {\n    return el;\n  }\n  // react17 采用 __reactFiber 开头\n  REACT_KEY = Object.keys(el).find(\n    (key) => key.startsWith('__reactInternalInstance$') || key.startsWith('__reactFiber$'),\n  ) || '';\n  if (!REACT_KEY && (el as HTMLElement).parentElement) {\n    return cacheReactKey((el as HTMLElement).parentElement!);\n  }\n  return el;\n}\n\nconst SYMBOL_VNID = Symbol('_LCNodeId');\nconst SYMBOL_VDID = Symbol('_LCDocId');\n\nfunction getClosestNodeInstance(\n    from: ReactInstance,\n    specId?: string,\n  ): IPublicTypeNodeInstance<ReactInstance> | null {\n  let el: any = from;\n  if (el) {\n    if (isElement(el)) {\n      el = cacheReactKey(el);\n    } else {\n      return getNodeInstance(getReactInternalFiber(el), specId);\n    }\n  }\n  while (el) {\n    if (SYMBOL_VNID in el) {\n      const nodeId = el[SYMBOL_VNID];\n      const docId = el[SYMBOL_VDID];\n      if (!specId || specId === nodeId) {\n        return {\n          docId,\n          nodeId,\n          instance: el,\n        };\n      }\n    }\n    // get fiberNode from element\n    if (el[REACT_KEY]) {\n      return getNodeInstance(el[REACT_KEY], specId);\n    }\n    el = el.parentElement;\n  }\n  return null;\n}\n\nfunction getNodeInstance(fiberNode: any, specId?: string): IPublicTypeNodeInstance<ReactInstance> | null {\n  const instance = fiberNode?.stateNode;\n  if (instance && SYMBOL_VNID in instance) {\n    const nodeId = instance[SYMBOL_VNID];\n    const docId = instance[SYMBOL_VDID];\n    if (!specId || specId === nodeId) {\n      return {\n        docId,\n        nodeId,\n        instance,\n      };\n    }\n  }\n  if (!instance && !fiberNode?.return) return null;\n  return getNodeInstance(fiberNode?.return);\n}\n\nfunction checkInstanceMounted(instance: any): boolean {\n  if (isElement(instance)) {\n    return instance.parentElement != null && window.document.contains(instance);\n  }\n  return true;\n}\n\nfunction getLowCodeComponentProps(props: any) {\n  if (!props || !isPlainObject(props)) {\n    return props;\n  }\n  const newProps: any = {};\n  Object.keys(props).forEach((k) => {\n    if (['children', 'componentId', '__designMode', '_componentName', '_leaf'].includes(k)) {\n      return;\n    }\n    newProps[k] = props[k];\n  });\n  newProps['componentName'] = props['_componentName'];\n  return newProps;\n}\n\nexport default new SimulatorRendererContainer();\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/utils/get-client-rects.ts",
    "content": "import { isElement } from '@alilc/lowcode-utils';\n\n// a range for test TextNode clientRect\nconst cycleRange = document.createRange();\n\nexport function getClientRects(node: Element | Text) {\n  if (isElement(node)) {\n    return [node.getBoundingClientRect()];\n  }\n\n  cycleRange.selectNode(node);\n  return Array.from(cycleRange.getClientRects());\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/utils/is-dom-node.ts",
    "content": "export function isDOMNode(node: any): node is Element | Text {\n  return node.nodeType && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE);\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/utils/misc.ts",
    "content": "interface UtilsMetadata {\n  name: string;\n  npm: {\n    package: string;\n    version?: string;\n    exportName: string;\n    subName?: string;\n    destructuring?: boolean;\n    main?: string;\n  };\n}\n\ninterface LibrayMap {\n  [key: string]: string;\n}\n\nexport function getProjectUtils(librayMap: LibrayMap, utilsMetadata: UtilsMetadata[]) {\n  const projectUtils: { [packageName: string]: any } = {};\n  if (utilsMetadata) {\n    utilsMetadata.forEach(meta => {\n      if (librayMap[meta?.npm.package]) {\n        const lib = window[librayMap[meta?.npm.package]];\n      }\n    });\n  }\n}\n\n/**\n * judges if current simulator renderer deteched or not\n * @returns detached or not\n */\nexport function isRendererDetached() {\n  // if current iframe detached from host document, the `window.parent` will be undefined.\n  return !window.parent;\n}"
  },
  {
    "path": "packages/react-simulator-renderer/src/utils/react-find-dom-nodes.ts",
    "content": "import { ReactInstance } from 'react';\nimport { findDOMNode } from 'react-dom';\nimport { isElement } from '@alilc/lowcode-utils';\nimport { isDOMNode } from './is-dom-node';\n\nexport const getReactInternalFiber = (el: any) => {\n  return el._reactInternals || el._reactInternalFiber;\n};\n\nfunction elementsFromFiber(fiber: any, elements: Array<Element | Text>) {\n  if (fiber) {\n    if (fiber.stateNode && isDOMNode(fiber.stateNode)) {\n      elements.push(fiber.stateNode);\n    } else if (fiber.child) {\n      // deep fiberNode.child\n      elementsFromFiber(fiber.child, elements);\n    }\n\n    if (fiber.sibling) {\n      elementsFromFiber(fiber.sibling, elements);\n    }\n  }\n}\n\nexport function reactFindDOMNodes(elem: ReactInstance | null): Array<Element | Text> | null {\n  if (!elem) {\n    return null;\n  }\n  if (isElement(elem)) {\n    return [elem];\n  }\n  const elements: Array<Element | Text> = [];\n  const fiberNode = getReactInternalFiber(elem);\n  elementsFromFiber(fiberNode?.child, elements);\n  if (elements.length > 0) return elements;\n  try {\n    return [findDOMNode(elem)];\n  } catch (e) {\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/src/utils/url.ts",
    "content": "/**\n * Parse queryString\n * @param  {String} str '?q=query&b=test'\n * @return {Object}\n */\nexport function parseQuery(str: string): object {\n  const ret: any = {};\n\n  if (typeof str !== 'string') {\n    return ret;\n  }\n\n  const s = str.trim().replace(/^(\\?|#|&)/, '');\n\n  if (!s) {\n    return ret;\n  }\n\n  s.split('&').forEach((param) => {\n    const parts = param.replace(/\\+/g, ' ').split('=');\n    let key = parts.shift()!;\n    let val: any = parts.length > 0 ? parts.join('=') : undefined;\n\n    key = decodeURIComponent(key);\n\n    val = val === undefined ? null : decodeURIComponent(val);\n\n    if (ret[key] === undefined) {\n      ret[key] = val;\n    } else if (Array.isArray(ret[key])) {\n      ret[key].push(val);\n    } else {\n      ret[key] = [ret[key], val];\n    }\n  });\n\n  return ret;\n}\n\n/**\n * Stringify object to query parammeters\n * @param  {Object} obj\n * @return {String}\n */\nexport function stringifyQuery(obj: any): string {\n  const param: string[] = [];\n  Object.keys(obj).forEach((key) => {\n    let value = obj[key];\n    if (value && typeof value === 'object') {\n      value = JSON.stringify(value);\n    }\n    param.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n  });\n  return param.join('&');\n}\n\nexport function uriEncode(uri: string) {\n  return encodeURIComponent(uri);\n}\n\nexport function uriDecode(uri: string) {\n  return decodeURIComponent(uri);\n}\n\nexport function withQueryParams(url: string, params?: object) {\n  const queryStr = params ? stringifyQuery(params) : '';\n  if (queryStr === '') {\n    return url;\n  }\n  const urlSplit = url.split('#');\n  const hash = urlSplit[1] ? `#${urlSplit[1]}` : '';\n  const urlWithoutHash = urlSplit[0];\n  return `${urlWithoutHash}${~urlWithoutHash.indexOf('?') ? '&' : '?'}${queryStr}${hash}`;\n}\n"
  },
  {
    "path": "packages/react-simulator-renderer/test/schema/basic.ts",
    "content": "export default {\n  id: 'node_ockvuu8u911',\n  css: 'body{background-color:#f2f3f5}',\n  flows: [],\n  props: {\n    className: 'page_kvuu9hym',\n    pageStyle: {\n      backgroundColor: '#f2f3f5',\n    },\n    containerStyle: {},\n    templateVersion: '1.0.0',\n  },\n  state: {},\n  title: '',\n  methods: {\n    __initMethods__: {\n      type: 'JSExpression',\n      value: \"function (exports, module) { \\\"use strict\\\";\\n\\nexports.__esModule = true;\\nexports.func1 = func1;\\nexports.helloPage = helloPage;\\n\\nfunction func1() {\\n  console.info('hello, this is a page function');\\n}\\n\\nfunction helloPage() {\\n  // 你可以这么调用其他函数\\n  this.func1(); // 你可以这么调用组件的函数\\n  // this.$('textField_xxx').getValue();\\n  // 你可以这么使用「数据源面板」定义的「变量」\\n  // this.state.xxx\\n  // 你可以这么发送一个在「数据源面板」定义的「远程 API」\\n  // this.dataSourceMap['xxx'].load(data)\\n  // API 详见：https://go.alibaba-inc.com/help3/API\\n} \\n}\",\n    },\n  },\n  children: [\n    {\n      id: 'node_ockvuu8u915',\n      props: {\n        fieldId: 'div_kvuu9gl1',\n        behavior: 'NORMAL',\n        __style__: {},\n        customClassName: '',\n        useFieldIdAsDomId: false,\n      },\n      title: '',\n      children: [\n        {\n          id: 'node_ockvuu8u916',\n          props: {\n            content: {\n              use: 'zh-CN',\n              type: 'JSExpression',\n              'en-US': 'Tips content',\n              value: '\"我是一个简单的测试页面\"',\n              'zh-CN': '我是一个简单的测试页面',\n              extType: 'i18n',\n            },\n            fieldId: 'text_kvuu9gl2',\n            maxLine: 0,\n            behavior: 'NORMAL',\n            __style__: {},\n            showTitle: false,\n          },\n          title: '',\n          condition: true,\n          componentName: 'Text',\n        },\n      ],\n      condition: true,\n      componentName: 'Div',\n    },\n  ],\n  condition: true,\n  dataSource: {\n    list: [],\n    sync: true,\n    online: [],\n    offline: [],\n    globalConfig: {\n      fit: {\n        type: 'JSExpression',\n        value: \"function main(){\\n  'use strict';\\n\\nvar __compiledFunc__ = function fit(response) {\\n  var content = response.content !== undefined ? response.content : response;\\n  var error = {\\n    message: response.errorMsg || response.errors && response.errors[0] && response.errors[0].msg || response.content || '远程数据源请求出错，success is false'\\n  };\\n  var success = true;\\n  if (response.success !== undefined) {\\n    success = response.success;\\n  } else if (response.hasError !== undefined) {\\n    success = !response.hasError;\\n  }\\n  return {\\n    content: content,\\n    success: success,\\n    error: error\\n  };\\n};\\n  return __compiledFunc__.apply(this, arguments);\\n}\",\n        extType: 'function',\n      },\n    },\n  },\n  lifeCycles: {\n    constructor: {\n      type: 'JSExpression',\n      value: \"function constructor() {\\nvar module = { exports: {} };\\nvar _this = this;\\nthis.__initMethods__(module.exports, module);\\nObject.keys(module.exports).forEach(function(item) {\\n  if(typeof module.exports[item] === 'function'){\\n    _this[item] = module.exports[item];\\n  }\\n});\\n\\n}\",\n      extType: 'function',\n    },\n  },\n  componentName: 'Page',\n};\n"
  },
  {
    "path": "packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Base should be render NotFoundComponent 1`] = `\n<div\n  className=\"lce-page page_kvuu9hym\"\n  style={Object {}}\n>\n  <div\n    componentName=\"Div\"\n  >\n    <div\n      componentName=\"Text\"\n    >\n      Text Component Not Found\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Base should be render Text 1`] = `\n<div\n  className=\"lce-page page_kvuu9hym\"\n  style={Object {}}\n>\n  <div\n    componentName=\"Div\"\n  >\n    <div\n      __designMode=\"design\"\n      __style__={Object {}}\n      behavior=\"NORMAL\"\n      componentId=\"node_ockvuu8u916\"\n      fieldId=\"text_kvuu9gl2\"\n      forwardRef={[Function]}\n      maxLine={0}\n      showTitle={false}\n    >\n      我是一个简单的测试页面\n    </div>\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/react-simulator-renderer/test/src/renderer/demo.test.tsx",
    "content": "import renderer from 'react-test-renderer';\nimport rendererContainer from '../../../src/renderer';\nimport SimulatorRendererView from '../../../src/renderer-view';\nimport { Text } from '../../utils/components';\n\ndescribe('Base', () => {\n  const component = renderer.create(\n    <SimulatorRendererView\n      rendererContainer={rendererContainer}\n    />\n  );\n\n  it('should be render NotFoundComponent', () => {\n    let tree = component.toJSON();\n    expect(tree).toMatchSnapshot();\n  });\n\n  it('should be render Text', () => {\n    // 更新 _componentsMap 值\n    (rendererContainer as any)._componentsMap.Text = Text;//  = host.designer.componentsMap;\n    // 更新 components 列表\n    (rendererContainer as any).buildComponents();\n\n    expect(!!(rendererContainer.components as any).Text).toBeTruthy();\n\n    rendererContainer.rerender();\n\n    let tree = component.toJSON();\n    expect(tree).toMatchSnapshot();\n  });\n})"
  },
  {
    "path": "packages/react-simulator-renderer/test/utils/components.tsx",
    "content": "export const Text = ({\n  __tag,\n  content,\n  ...props\n}: any) => (<div {...props}>{content}</div>);\n\nexport const Page = (props: any) => (<div>{props.children}</div>);"
  },
  {
    "path": "packages/react-simulator-renderer/test/utils/host.ts",
    "content": "import { Box, Breadcrumb, Form, Select, Input, Button, Table, Pagination, Dialog } from '@alifd/next';\nimport defaultSchema from '../schema/basic';\nimport { Page } from './components';\n\nclass Designer {\n  componentsMap = {\n    Box,\n    Breadcrumb,\n    'Breadcrumb.Item': Breadcrumb.Item,\n    Form,\n    'Form.Item': Form.Item,\n    Select,\n    Input,\n    Button,\n    'Button.Group': Button.Group,\n    Table,\n    Pagination,\n    Dialog,\n    Page,\n  }\n}\n\nclass Host {\n  designer = new Designer();\n\n  connect = () => {}\n\n  autorun = (fn: Function) => {\n    fn();\n  }\n\n  autoRender = true;\n\n  componentsConsumer = {\n    consume() {}\n  }\n\n  schema = defaultSchema;\n\n  project = {\n    documents: [\n      {\n        id: '1',\n        path: '/',\n        fileName: '',\n        export: () => {\n          return this.schema;\n        },\n        getNode: () => {},\n      }\n    ],\n    get: () => ({}),\n  }\n\n  setInstance() {}\n\n  designMode = 'design'\n\n  get() {}\n\n  injectionConsumer = {\n    consume() {}\n  }\n\n  i18nConsumer = {\n    consume() {}\n  }\n\n  /** 下列的函数或者方法是方便测试用 */\n  mockSchema = (schema: any) => {\n    this.schema = schema;\n  };\n}\n\nif (!(window as any).LCSimulatorHost) {\n  (window as any).LCSimulatorHost = new Host();\n}\n\nexport default (window as any).LCSimulatorHost;"
  },
  {
    "path": "packages/react-simulator-renderer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\", \"../../index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/renderer-core/babel.config.js",
    "content": "module.exports = require('../../babel.config');"
  },
  {
    "path": "packages/renderer-core/build.json",
    "content": "{\n  \"plugins\": [\n    [\n      \"@alilc/build-plugin-lce\",\n      {\n        \"babelPlugins\": [\"@babel/plugin-transform-typescript\"]\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": "packages/renderer-core/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/renderer-core/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst esModules = [].join('|');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  // transform: {\n  //   // '^.+\\\\.[jt]sx?$': 'babel-jest',\n  //   '^.+\\\\.(ts|tsx)$': 'ts-jest',\n  //   // '^.+\\\\.(js|jsx)$': 'babel-jest',\n  // },\n  // testMatch: ['(/tests?/.*(test))\\\\.[jt]s$'],\n  // testMatch: ['**/*/base.test.tsx'],\n  // testMatch: ['**/utils/common.test.ts'],\n  // testMatch: ['**/*/leaf.test.tsx'],\n  // testMatch: ['**/*/is-use-loop.test.ts'],\n  transformIgnorePatterns: [\n    `/node_modules/(?!${esModules})/`,\n  ],\n  setupFiles: [\n    './tests/fixtures/unhandled-rejection.ts',\n    './tests/setup.ts',\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: true,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    'src/**/*.tsx',\n    '!src/utils/logger.ts',\n    '!src/types/index.ts',\n  ],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/renderer-core/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-renderer-core\",\n  \"version\": \"1.3.2\",\n  \"description\": \"renderer core\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"scripts\": {\n    \"build\": \"build-scripts build\",\n    \"test\": \"build-scripts test --config build.test.json\",\n    \"test:cov\": \"build-scripts test --config build.test.json --jest-coverage\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-engine\": \"^1.0.0\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"debug\": \"^4.1.1\",\n    \"fetch-jsonp\": \"^1.1.3\",\n    \"intl-messageformat\": \"^9.3.1\",\n    \"jsonuri\": \"^2.1.2\",\n    \"lodash\": \"^4.17.11\",\n    \"prop-types\": \"^15.7.2\",\n    \"react-is\": \"^16.10.1\",\n    \"socket.io-client\": \"^2.2.0\",\n    \"whatwg-fetch\": \"^3.0.0\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@alifd/next\": \"^1.26.0\",\n    \"@alilc/lowcode-designer\": \"1.3.2\",\n    \"@babel/plugin-transform-typescript\": \"^7.16.8\",\n    \"@testing-library/react\": \"^11.2.2\",\n    \"@types/classnames\": \"^2.2.11\",\n    \"@types/debug\": \"^4.1.5\",\n    \"@types/jest\": \"^26.0.16\",\n    \"@types/lodash\": \"^4.14.167\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/prop-types\": \"^15.7.3\",\n    \"@types/react-is\": \"^17.0.3\",\n    \"@types/react-test-renderer\": \"^17.0.1\",\n    \"jest\": \"^26.6.3\",\n    \"react-test-renderer\": \"^17.0.2\",\n    \"ts-jest\": \"^26.5.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/renderer-core\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/renderer-core/src/adapter/index.ts",
    "content": "import { IRuntime, IRendererModules, IGeneralConstructor } from '../types';\n\nexport enum Env {\n  React = 'react',\n}\n\nclass Adapter {\n  runtime: IRuntime;\n\n  builtinModules = ['Component', 'PureComponent', 'createElement', 'createContext', 'forwardRef', 'findDOMNode'];\n\n  env: Env;\n\n  renderers: IRendererModules;\n\n  configProvider: any;\n\n  constructor() {\n    this.initRuntime();\n  }\n\n  initRuntime() {\n    const Component: IGeneralConstructor = class <T = any, S = any> {\n      state: Readonly<S>;\n      props: Readonly<T> & Readonly<{ children?: any | undefined }>;\n      refs: Record<string, unknown>;\n      context: Record<string, unknown>;\n      setState() {}\n      forceUpdate() {}\n      render() {}\n    };\n    const PureComponent = class <T = any, S = any> {\n      state: Readonly<S>;\n      props: Readonly<T> & Readonly<{ children?: any | undefined }>;\n      refs: Record<string, unknown>;\n      context: Record<string, unknown>;\n      setState() {}\n      forceUpdate() {}\n      render() {}\n    };\n    const createElement = () => {};\n    const createContext = () => {};\n    const forwardRef = () => {};\n    const findDOMNode = () => {};\n    this.runtime = {\n      Component,\n      PureComponent,\n      createElement,\n      createContext,\n      forwardRef,\n      findDOMNode,\n    };\n  }\n\n  setRuntime(runtime: IRuntime) {\n    if (this.isValidRuntime(runtime)) {\n      this.runtime = runtime;\n    }\n  }\n\n  isValidRuntime(runtime: IRuntime) {\n    if (typeof runtime !== 'object' || Array.isArray(runtime)) {\n      return false;\n    }\n\n    return this.builtinModules.every((m) => {\n      const flag = !!runtime[m];\n      if (!flag) {\n        throw new Error(`runtime is invalid, module '${m}' does not exist`);\n      }\n      return flag;\n    });\n  }\n\n  getRuntime() {\n    return this.runtime;\n  }\n\n  setEnv(env: Env) {\n    this.env = env;\n  }\n\n  isReact() {\n    return this.env === Env.React;\n  }\n\n  setRenderers(renderers: IRendererModules) {\n    this.renderers = renderers;\n  }\n\n  getRenderers() {\n    return this.renderers || {};\n  }\n\n  setConfigProvider(Comp: any) {\n    this.configProvider = Comp;\n  }\n\n  getConfigProvider() {\n    return this.configProvider;\n  }\n}\n\nexport default new Adapter();\n"
  },
  {
    "path": "packages/renderer-core/src/components/Div.tsx",
    "content": "import adapter from '../adapter';\nimport { IGeneralConstructor } from '../types';\n\nexport default function divFactory(): IGeneralConstructor {\n  const { PureComponent, createElement } = adapter.getRuntime();\n  return class Div extends PureComponent {\n    static displayName = 'Div';\n\n    static version = '0.0.0';\n\n    render() {\n      return createElement('div', this.props);\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/components/VisualDom/index.css",
    "content": ".visual-dom .panel-container {\n  box-sizing: border-box;\n  border: 1px solid #e9e9e9;\n}\n\n.visual-dom .panel-container .title {\n  display: block;\n  font-size: 12px;\n  color: #333;\n  background-color: #ebecf0;\n  line-height: 28px;\n  padding: 0 12px;\n  border-bottom: 1px solid #e9e9e9;\n}\n\n.visual-dom .panel-container .content {\n  min-height: 20px;\n  padding: 5px;\n}\n"
  },
  {
    "path": "packages/renderer-core/src/components/VisualDom/index.tsx",
    "content": "import PropTypes from 'prop-types';\nimport adapter from '../../adapter';\nimport { IGeneralConstructor } from '../../types';\nimport './index.css';\n\nexport default function visualDomFactory(): IGeneralConstructor {\n  const { PureComponent, createElement } = adapter.getRuntime();\n  return class VisualDom extends PureComponent {\n    static displayName = 'VisualDom';\n\n    static propTypes = {\n      children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),\n    };\n\n    static defaultProps = {\n      children: null,\n    };\n\n    render() {\n      const { children, cell, title, label, text, __componentName } = this.props;\n      let mainContent = children;\n      if (cell && typeof cell === 'function') {\n        mainContent = cell();\n      }\n      return createElement('div', { className: 'visual-dom' },\n        createElement('div', { className: 'panel-container' },\n          [\n            createElement('span', { className: 'title' }, title || label || text || __componentName),\n            createElement('div', { className: 'content' }, mainContent),\n          ]));\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/context/index.ts",
    "content": "import adapter from '../adapter';\n\n\nexport default function contextFactory() {\n  const { createContext } = adapter.getRuntime();\n\n  let context = (window as any).__appContext;\n  if (!context) {\n    context = createContext({});\n    (window as any).__appContext = context;\n  }\n  return context;\n}\n"
  },
  {
    "path": "packages/renderer-core/src/hoc/index.tsx",
    "content": "import { cloneEnumerableProperty } from '@alilc/lowcode-utils';\nimport adapter from '../adapter';\nimport { IBaseRendererInstance, IRendererProps } from '../types';\n\ninterface Options {\n  baseRenderer: IBaseRendererInstance;\n  schema: any;\n}\n\nfunction patchDidCatch(Comp: any, { baseRenderer }: Options) {\n  if (Comp.patchedCatch) {\n    return;\n  }\n  Comp.patchedCatch = true;\n  const { PureComponent } = adapter.getRuntime();\n  // Rax 的 getDerivedStateFromError 有 BUG，这里先用 componentDidCatch 来替代\n  // @see https://github.com/alibaba/rax/issues/2211\n  const originalDidCatch = Comp.prototype.componentDidCatch;\n  Comp.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) {\n    this.setState({ engineRenderError: true, error });\n    if (originalDidCatch && typeof originalDidCatch === 'function') {\n      originalDidCatch.call(this, error, errorInfo);\n    }\n  };\n\n  const { engine } = baseRenderer.context;\n  const originRender = Comp.prototype.render;\n  Comp.prototype.render = function () {\n    if (this.state && this.state.engineRenderError) {\n      this.state.engineRenderError = false;\n      return engine.createElement(engine.getFaultComponent(), {\n        ...this.props,\n        error: this.state.error,\n        componentName: this.props._componentName,\n      });\n    }\n    return originRender.call(this);\n  };\n  if (!(Comp.prototype instanceof PureComponent)) {\n    const originShouldComponentUpdate = Comp.prototype.shouldComponentUpdate;\n    Comp.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) {\n      if (nextState && nextState.engineRenderError) {\n        return true;\n      }\n      return originShouldComponentUpdate\n        ? originShouldComponentUpdate.call(this, nextProps, nextState)\n        : true;\n    };\n  }\n}\n\nconst cache = new Map<string, { Comp: any; WrapperComponent: any }>();\n\nexport function compWrapper(Comp: any, options: Options) {\n  const { createElement, Component, forwardRef } = adapter.getRuntime();\n  if (\n    Comp?.prototype?.isReactComponent || // react\n    Comp?.prototype?.setState || // rax\n    Comp?.prototype instanceof Component\n  ) {\n    patchDidCatch(Comp, options);\n    return Comp;\n  }\n\n  if (cache.has(options.schema.id) && cache.get(options.schema.id)?.Comp === Comp) {\n    return cache.get(options.schema.id)?.WrapperComponent;\n  }\n\n  class Wrapper extends Component {\n    render() {\n      return createElement(Comp, { ...this.props, ref: this.props.forwardRef });\n    }\n  }\n  (Wrapper as any).displayName = Comp.displayName;\n\n  patchDidCatch(Wrapper, options);\n\n  const WrapperComponent = cloneEnumerableProperty(\n    forwardRef((props: any, ref: any) => {\n      return createElement(Wrapper, { ...props, forwardRef: ref });\n    }),\n    Comp,\n  );\n\n  cache.set(options.schema.id, { WrapperComponent, Comp });\n\n  return WrapperComponent;\n}\n"
  },
  {
    "path": "packages/renderer-core/src/hoc/leaf.tsx",
    "content": "import { INode, IPublicTypePropChangeOptions } from '@alilc/lowcode-designer';\nimport { GlobalEvent, IPublicEnumTransformStage, IPublicTypeNodeSchema, IPublicTypeEngineOptions } from '@alilc/lowcode-types';\nimport { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils';\nimport { debounce } from '../utils/common';\nimport adapter from '../adapter';\nimport * as types from '../types/index';\nimport logger from '../utils/logger';\n\nexport interface IComponentHocInfo {\n  schema: any;\n  baseRenderer: types.IBaseRendererInstance;\n  componentInfo: any;\n  scope: any;\n}\n\nexport interface IComponentHocProps {\n  __tag: any;\n  componentId: any;\n  _leaf: any;\n  forwardedRef?: any;\n}\n\nexport interface IComponentHocState {\n  childrenInState: boolean;\n  nodeChildren: any;\n  nodeCacheProps: any;\n\n  /** 控制是否显示隐藏 */\n  visible: boolean;\n\n  /** 控制是否渲染 */\n  condition: boolean;\n  nodeProps: any;\n}\n\ntype DesignMode = Pick<IPublicTypeEngineOptions, 'designMode'>['designMode'];\n\nexport interface IComponentHoc {\n  designMode: DesignMode | DesignMode[];\n  hoc: IComponentConstruct;\n}\n\nexport type IComponentConstruct = (Comp: types.IBaseRenderComponent, info: IComponentHocInfo) => types.IGeneralConstructor;\n\ninterface IProps {\n  _leaf: INode | undefined;\n\n  visible: boolean;\n\n  componentId: number;\n\n  children?: INode[];\n\n  __tag: number;\n\n  forwardedRef?: any;\n}\n\nenum RerenderType {\n  All = 'All',\n  ChildChanged = 'ChildChanged',\n  PropsChanged = 'PropsChanged',\n  VisibleChanged = 'VisibleChanged',\n  MinimalRenderUnit = 'MinimalRenderUnit',\n}\n\n// 缓存 Leaf 层组件，防止重新渲染问题\nclass LeafCache {\n\n  /** 组件缓存 */\n  component = new Map();\n\n  /**\n   * 状态缓存，场景：属性变化后，改组件被销毁，state 为空，没有展示修改后的属性\n   */\n  state = new Map();\n\n  /**\n   * 订阅事件缓存，导致 rerender 的订阅事件\n   */\n  event = new Map();\n\n  ref = new Map();\n\n  constructor(public documentId: string, public device: string) {\n  }\n}\n\nlet cache: LeafCache;\n\n/** 部分没有渲染的 node 节点进行兜底处理 or 渲染方式没有渲染 LeafWrapper */\nfunction initRerenderEvent({\n  schema,\n  __debug,\n  container,\n  getNode,\n}: any) {\n  const leaf = getNode?.(schema.id);\n  if (!leaf\n    || cache.event.get(schema.id)?.clear\n    || leaf === cache.event.get(schema.id)\n  ) {\n    return;\n  }\n  cache.event.get(schema.id)?.dispose.forEach((disposeFn: any) => disposeFn && disposeFn());\n  const debounceRerender = debounce(() => {\n    container.rerender();\n  }, 20);\n  cache.event.set(schema.id, {\n    clear: false,\n    leaf,\n    dispose: [\n      leaf?.onPropChange?.(() => {\n        if (!container.autoRepaintNode) {\n          return;\n        }\n        __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onPropsChange make rerender`);\n        debounceRerender();\n      }),\n      leaf?.onChildrenChange?.(() => {\n        if (!container.autoRepaintNode) {\n          return;\n        }\n        __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onChildrenChange make rerender`);\n        debounceRerender();\n      }) as Function,\n      leaf?.onVisibleChange?.(() => {\n        if (!container.autoRepaintNode) {\n          return;\n        }\n        __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onVisibleChange make rerender`);\n        debounceRerender();\n      }),\n    ],\n  });\n}\n\n/** 渲染的 node 节点全局注册事件清除 */\nfunction clearRerenderEvent(id: string): void {\n  if (cache.event.get(id)?.clear) {\n    return;\n  }\n  cache.event.get(id)?.dispose?.forEach((disposeFn: any) => disposeFn && disposeFn());\n  cache.event.set(id, {\n    clear: true,\n    dispose: [],\n  });\n}\n\n// 给每个组件包裹一个 HOC Leaf，支持组件内部属性变化，自响应渲染\nexport function leafWrapper(Comp: types.IBaseRenderComponent, {\n  schema,\n  baseRenderer,\n  componentInfo,\n  scope,\n}: IComponentHocInfo) {\n  const {\n    __debug,\n    __getComponentProps: getProps,\n    __getSchemaChildrenVirtualDom: getChildren,\n    __parseData,\n  } = baseRenderer;\n  const { engine } = baseRenderer.context;\n  const host = baseRenderer.props?.__host;\n  const curDocumentId = baseRenderer.props?.documentId ?? '';\n  const curDevice = baseRenderer.props?.device ?? '';\n  const getNode = baseRenderer.props?.getNode;\n  const container = baseRenderer.props?.__container;\n  const setSchemaChangedSymbol = baseRenderer.props?.setSchemaChangedSymbol;\n  const editor = host?.designer?.editor;\n  const runtime = adapter.getRuntime();\n  const { forwardRef, createElement } = runtime;\n  const Component = runtime.Component as types.IGeneralConstructor<\n    IComponentHocProps, IComponentHocState\n  >;\n\n  const componentCacheId = schema.id;\n\n  if (!cache || (curDocumentId && curDocumentId !== cache.documentId) || (curDevice && curDevice !== cache.device)) {\n    cache?.event.forEach(event => {\n      event.dispose?.forEach((disposeFn: any) => disposeFn && disposeFn());\n    });\n    cache = new LeafCache(curDocumentId, curDevice);\n  }\n\n  if (!isReactComponent(Comp)) {\n    logger.error(`${schema.componentName} component may be has errors: `, Comp);\n  }\n\n  initRerenderEvent({\n    schema,\n    __debug,\n    container,\n    getNode,\n  });\n\n  if (curDocumentId && cache.component.has(componentCacheId) && (cache.component.get(componentCacheId).Comp === Comp)) {\n    return cache.component.get(componentCacheId).LeafWrapper;\n  }\n\n  class LeafHoc extends Component {\n    recordInfo: {\n      startTime?: number | null;\n      type?: string;\n      node?: INode;\n    } = {};\n\n    private curEventLeaf: INode | undefined;\n\n    static displayName = schema.componentName;\n\n    disposeFunctions: Array<((() => void) | Function)> = [];\n\n    __component_tag = 'leafWrapper';\n\n    renderUnitInfo: {\n      minimalUnitId?: string;\n      minimalUnitName?: string;\n      singleRender?: boolean;\n    };\n\n    // 最小渲染单元做防抖处理\n    makeUnitRenderDebounced = debounce(() => {\n      this.beforeRender(RerenderType.MinimalRenderUnit);\n      const schema = this.leaf?.export?.(IPublicEnumTransformStage.Render);\n      if (!schema) {\n        return;\n      }\n      const nextProps = getProps(schema, scope, Comp, componentInfo);\n      const children = getChildren(schema, scope, Comp);\n      const nextState = {\n        nodeProps: nextProps,\n        nodeChildren: children,\n        childrenInState: true,\n      };\n      if ('children' in nextProps) {\n        nextState.nodeChildren = nextProps.children;\n      }\n\n      __debug(`${this.leaf?.componentName}(${this.props.componentId}) MinimalRenderUnit Render!`);\n      this.setState(nextState);\n    }, 20);\n\n    constructor(props: IProps, context: any) {\n      super(props, context);\n      // 监听以下事件，当变化时更新自己\n      __debug(`${schema.componentName}[${this.props.componentId}] leaf render in SimulatorRendererView`);\n      clearRerenderEvent(componentCacheId);\n      this.curEventLeaf = this.leaf;\n\n      cache.ref.set(componentCacheId, {\n        makeUnitRender: this.makeUnitRender,\n      });\n\n      let cacheState = cache.state.get(componentCacheId);\n      if (!cacheState || cacheState.__tag !== props.__tag) {\n        cacheState = this.getDefaultState(props);\n      }\n\n      this.state = cacheState;\n    }\n\n    recordTime = () => {\n      if (!this.recordInfo.startTime) {\n        return;\n      }\n      const endTime = Date.now();\n      const nodeCount = host?.designer?.currentDocument?.getNodeCount?.();\n      const componentName = this.recordInfo.node?.componentName || this.leaf?.componentName || 'UnknownComponent';\n      editor?.eventBus.emit(GlobalEvent.Node.Rerender, {\n        componentName,\n        time: endTime - this.recordInfo.startTime,\n        type: this.recordInfo.type,\n        nodeCount,\n      });\n      this.recordInfo.startTime = null;\n    };\n\n    makeUnitRender = () => {\n      this.makeUnitRenderDebounced();\n    };\n\n    get autoRepaintNode() {\n      return container?.autoRepaintNode;\n    }\n\n    componentDidUpdate() {\n      this.recordTime();\n    }\n\n    componentDidMount() {\n      const _leaf = this.leaf;\n      this.initOnPropsChangeEvent(_leaf);\n      this.initOnChildrenChangeEvent(_leaf);\n      this.initOnVisibleChangeEvent(_leaf);\n      this.recordTime();\n    }\n\n    getDefaultState(nextProps: any) {\n      const {\n        hidden = false,\n        condition = true,\n      } = nextProps.__inner__ || this.leaf?.export?.(IPublicEnumTransformStage.Render) || {};\n      return {\n        nodeChildren: null,\n        childrenInState: false,\n        visible: !hidden,\n        condition: __parseData?.(condition, scope),\n        nodeCacheProps: {},\n        nodeProps: {},\n      };\n    }\n\n    setState(state: any) {\n      cache.state.set(componentCacheId, {\n        ...this.state,\n        ...state,\n        __tag: this.props.__tag,\n      });\n      super.setState(state);\n    }\n\n    /** 由于内部属性变化，在触发渲染前，会执行该函数 */\n    beforeRender(type: string, node?: INode): void {\n      this.recordInfo.startTime = Date.now();\n      this.recordInfo.type = type;\n      this.recordInfo.node = node;\n      setSchemaChangedSymbol?.(true);\n    }\n\n    judgeMiniUnitRender() {\n      if (!this.renderUnitInfo) {\n        this.getRenderUnitInfo();\n      }\n\n      const renderUnitInfo = this.renderUnitInfo || {\n        singleRender: true,\n      };\n\n      if (renderUnitInfo.singleRender) {\n        return;\n      }\n\n      const ref = cache.ref.get(renderUnitInfo.minimalUnitId);\n\n      if (!ref) {\n        __debug('Cant find minimalRenderUnit ref! This make rerender!');\n        container?.rerender();\n        return;\n      }\n      __debug(`${this.leaf?.componentName}(${this.props.componentId}) need render, make its minimalRenderUnit ${renderUnitInfo.minimalUnitName}(${renderUnitInfo.minimalUnitId})`);\n      ref.makeUnitRender();\n    }\n\n    getRenderUnitInfo(leaf = this.leaf) {\n      // leaf 在低代码组件中存在 mock 的情况，退出最小渲染单元判断\n      if (!leaf || typeof leaf.isRoot !== 'function') {\n        return;\n      }\n\n      if (leaf.isRootNode) {\n        this.renderUnitInfo = {\n          singleRender: true,\n          ...(this.renderUnitInfo || {}),\n        };\n      }\n      if (leaf.componentMeta.isMinimalRenderUnit) {\n        this.renderUnitInfo = {\n          minimalUnitId: leaf.id,\n          minimalUnitName: leaf.componentName,\n          singleRender: false,\n        };\n      }\n      if (leaf.hasLoop()) {\n        // 含有循环配置的元素，父元素是最小渲染单元\n        this.renderUnitInfo = {\n          minimalUnitId: leaf?.parent?.id,\n          minimalUnitName: leaf?.parent?.componentName,\n          singleRender: false,\n        };\n      }\n      if (leaf.parent) {\n        this.getRenderUnitInfo(leaf.parent);\n      }\n    }\n\n    componentWillReceiveProps(nextProps: any) {\n      let { componentId } = nextProps;\n      if (nextProps.__tag === this.props.__tag) {\n        return null;\n      }\n\n      const _leaf = getNode?.(componentId);\n      if (_leaf && this.curEventLeaf && _leaf !== this.curEventLeaf) {\n        this.disposeFunctions.forEach((fn) => fn());\n        this.disposeFunctions = [];\n        this.initOnChildrenChangeEvent(_leaf);\n        this.initOnPropsChangeEvent(_leaf);\n        this.initOnVisibleChangeEvent(_leaf);\n        this.curEventLeaf = _leaf;\n      }\n\n      const {\n        visible,\n        ...resetState\n      } = this.getDefaultState(nextProps);\n      this.setState(resetState);\n    }\n\n    /** 监听参数变化 */\n    initOnPropsChangeEvent(leaf = this.leaf): void {\n      const handlePropsChange = debounce((propChangeInfo: IPublicTypePropChangeOptions) => {\n        const {\n          key,\n          newValue = null,\n        } = propChangeInfo;\n        const node = leaf;\n\n        if (key === '___condition___') {\n          const { condition = true } = this.leaf?.export(IPublicEnumTransformStage.Render) || {};\n          const conditionValue = __parseData?.(condition, scope);\n          __debug(`key is ___condition___, change condition value to [${condition}]`);\n          // 条件表达式改变\n          this.setState({\n            condition: conditionValue,\n          });\n          return;\n        }\n\n        // 如果循坏条件变化，从根节点重新渲染\n        // 目前多层循坏无法判断需要从哪一层开始渲染，故先粗暴解决\n        if (key === '___loop___') {\n          __debug('key is ___loop___, render a page!');\n          container?.rerender();\n          // 由于 scope 变化，需要清空缓存，使用新的 scope\n          cache.component.delete(componentCacheId);\n          return;\n        }\n        this.beforeRender(RerenderType.PropsChanged);\n        const { state } = this;\n        const { nodeCacheProps } = state;\n        const nodeProps = getProps(node?.export?.(IPublicEnumTransformStage.Render) as IPublicTypeNodeSchema, scope, Comp, componentInfo);\n        if (key && !(key in nodeProps) && (key in this.props)) {\n          // 当 key 在 this.props 中时，且不存在在计算值中，需要用 newValue 覆盖掉 this.props 的取值\n          nodeCacheProps[key] = newValue;\n        }\n        __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange!`, nodeProps, nodeCacheProps, key, newValue);\n        this.setState('children' in nodeProps ? {\n          nodeChildren: nodeProps.children,\n          nodeProps,\n          childrenInState: true,\n          nodeCacheProps,\n        } : {\n          nodeProps,\n          nodeCacheProps,\n        });\n\n        this.judgeMiniUnitRender();\n      });\n      const dispose = leaf?.onPropChange?.((propChangeInfo: IPublicTypePropChangeOptions) => {\n        if (!this.autoRepaintNode) {\n          return;\n        }\n        handlePropsChange(propChangeInfo);\n      });\n\n      dispose && this.disposeFunctions.push(dispose);\n    }\n\n    /**\n     * 监听显隐变化\n     */\n    initOnVisibleChangeEvent(leaf = this.leaf) {\n      const dispose = leaf?.onVisibleChange?.((flag: boolean) => {\n        if (!this.autoRepaintNode) {\n          return;\n        }\n        if (this.state.visible === flag) {\n          return;\n        }\n\n        __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange(${flag}) event`);\n        this.beforeRender(RerenderType.VisibleChanged);\n        this.setState({\n          visible: flag,\n        });\n        this.judgeMiniUnitRender();\n      });\n\n      dispose && this.disposeFunctions.push(dispose);\n    }\n\n    /**\n     * 监听子元素变化（拖拽，删除...）\n     */\n    initOnChildrenChangeEvent(leaf = this.leaf) {\n      const dispose = leaf?.onChildrenChange?.((param): void => {\n        if (!this.autoRepaintNode) {\n          return;\n        }\n        const {\n          type,\n          node,\n        } = param || {};\n        this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node);\n        // TODO: 缓存同级其他元素的 children。\n        // 缓存二级 children Next 查询筛选组件有问题\n        // 缓存一级 children Next Tab 组件有问题\n        const nextChild = getChildren(leaf?.export?.(IPublicEnumTransformStage.Render) as types.ISchema, scope, Comp);\n        __debug(`${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`, nextChild);\n        this.setState({\n          nodeChildren: nextChild,\n          childrenInState: true,\n        });\n        this.judgeMiniUnitRender();\n      });\n      dispose && this.disposeFunctions.push(dispose);\n    }\n\n    componentWillUnmount() {\n      this.disposeFunctions.forEach(fn => fn());\n    }\n\n    get hasChildren(): boolean {\n      if (!this.state.childrenInState) {\n        return 'children' in this.props;\n      }\n\n      return true;\n    }\n\n    get children(): any {\n      if (this.state.childrenInState) {\n        return this.state.nodeChildren;\n      }\n      if (this.props.children && !Array.isArray(this.props.children)) {\n        return [this.props.children];\n      }\n      if (this.props.children && this.props.children.length) {\n        return this.props.children;\n      }\n      return this.props.children;\n    }\n\n    get leaf(): INode | undefined {\n      if (this.props._leaf?.isMock) {\n        // 低代码组件作为一个整体更新，其内部的组件不需要监听相关事件\n        return undefined;\n      }\n\n      return getNode?.(componentCacheId);\n    }\n\n    render() {\n      if (!this.state.visible || !this.state.condition) {\n        return null;\n      }\n\n      const {\n        forwardedRef,\n        ...rest\n      } = this.props;\n\n      const compProps = {\n        ...rest,\n        ...(this.state.nodeCacheProps || {}),\n        ...(this.state.nodeProps || {}),\n        children: [],\n        __id: this.props.componentId,\n        ref: forwardedRef,\n      };\n\n      delete compProps.__inner__;\n\n      if (this.hasChildren) {\n        return engine.createElement(Comp, compProps, this.children);\n      }\n\n      return engine.createElement(Comp, compProps);\n    }\n  }\n\n  let LeafWrapper = forwardRef((props: any, ref: any) => {\n    return createElement(LeafHoc, {\n      ...props,\n      forwardedRef: ref,\n    });\n  });\n\n  LeafWrapper = cloneEnumerableProperty(LeafWrapper, Comp);\n\n  LeafWrapper.displayName = (Comp as any).displayName;\n\n  cache.component.set(componentCacheId, {\n    LeafWrapper,\n    Comp,\n  });\n\n  return LeafWrapper;\n}"
  },
  {
    "path": "packages/renderer-core/src/index.ts",
    "content": "import adapter from './adapter';\nimport contextFactory from './context';\n\nexport { adapter, contextFactory };\n\nexport * from './renderer';\nexport * as types from './types';\nexport * as utils from './utils';\nexport * from './hoc';\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/addon.tsx",
    "content": "import PropTypes from 'prop-types';\nimport baseRendererFactory from './base';\nimport { isEmpty } from '../utils';\nimport { IRendererAppHelper, IBaseRendererProps, IBaseRenderComponent } from '../types';\nimport logger from '../utils/logger';\n\nexport default function addonRendererFactory(): IBaseRenderComponent {\n  const BaseRenderer = baseRendererFactory();\n  return class AddonRenderer extends BaseRenderer {\n    static displayName = 'AddonRenderer';\n\n    __namespace = 'addon';\n\n    static propTypes = {\n      config: PropTypes.object,\n      __schema: PropTypes.object,\n    };\n\n    static defaultProps = {\n      config: {},\n      __schema: {},\n    };\n\n    addonKey: any;\n    appHelper: IRendererAppHelper;\n    open: () => any;\n    close: () => any;\n\n    __afterInit(props: IBaseRendererProps) {\n      this.__generateCtx({\n        component: this,\n      });\n      const schema = props.__schema || {};\n      this.state = this.__parseData(schema.state || {});\n      if (isEmpty(props.config) || !props.config?.addonKey) {\n        logger.warn('lce addon has wrong config');\n        this.setState({\n          __hasError: true,\n        });\n        return;\n      }\n      // 注册插件\n      this.addonKey = props.config.addonKey;\n      this.appHelper.addons = this.appHelper.addons || {};\n      this.appHelper.addons[this.addonKey] = this;\n      this.__initDataSource(props);\n      this.open = this.open || (() => { });\n      this.close = this.close || (() => { });\n      this.__executeLifeCycleMethod('constructor', [...arguments]);\n    }\n\n    async componentWillUnmount() {\n      super.componentWillUnmount?.apply(this, [...arguments] as any);\n      // 注销插件\n      const config = this.props.config || {};\n      if (config && this.appHelper.addons) {\n        delete this.appHelper.addons[config.addonKey];\n      }\n    }\n\n    get utils() {\n      const { utils = {} } = this.context.config || {};\n      return { ...this.appHelper.utils, ...utils };\n    }\n\n    render() {\n      const { __schema } = this.props;\n\n      if (this.__checkSchema(__schema)) {\n        return '插件 schema 结构异常！';\n      }\n\n      this.__debug(`${AddonRenderer.displayName} render - ${__schema.fileName}`);\n      this.__generateCtx({\n        component: this,\n      });\n      this.__render();\n\n      return this.__renderContent(this.__renderContextProvider({ compContext: this }));\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/base.tsx",
    "content": "/* eslint-disable no-console */\n/* eslint-disable max-len */\n/* eslint-disable react/prop-types */\nimport classnames from 'classnames';\nimport { create as createDataSourceEngine } from '@alilc/lowcode-datasource-engine/interpret';\nimport { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeJSONValue, IPublicTypeCompositeValue } from '@alilc/lowcode-types';\nimport { checkPropTypes, isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils';\nimport adapter from '../adapter';\nimport divFactory from '../components/Div';\nimport visualDomFactory from '../components/VisualDom';\nimport contextFactory from '../context';\nimport {\n  forEach,\n  getValue,\n  parseData,\n  parseExpression,\n  parseThisRequiredExpression,\n  parseI18n,\n  isEmpty,\n  isSchema,\n  isFileSchema,\n  transformArrayToMap,\n  transformStringToFunction,\n  getI18n,\n  getFileCssName,\n  capitalizeFirstLetter,\n  DataHelper,\n  isVariable,\n  isJSSlot,\n} from '../utils';\nimport { IBaseRendererProps, INodeInfo, IBaseRenderComponent, IBaseRendererContext, IRendererAppHelper, DataSource } from '../types';\nimport { compWrapper } from '../hoc';\nimport { IComponentConstruct, leafWrapper } from '../hoc/leaf';\nimport logger from '../utils/logger';\nimport isUseLoop from '../utils/is-use-loop';\n\n/**\n * execute method in schema.lifeCycles with context\n * @PRIVATE\n */\nexport function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSchema, method: string, args: any, thisRequiredInJSE: boolean | undefined): any {\n  if (!context || !isSchema(schema) || !method) {\n    return;\n  }\n  const lifeCycleMethods = getValue(schema, 'lifeCycles', {});\n  let fn = lifeCycleMethods[method];\n\n  if (!fn) {\n    return;\n  }\n\n  // TODO: cache\n  if (isJSExpression(fn) || isJSFunction(fn)) {\n    fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context);\n  }\n\n  if (typeof fn !== 'function') {\n    logger.error(`生命周期${method}类型不符`, fn);\n    return;\n  }\n\n  try {\n    return fn.apply(context, args);\n  } catch (e) {\n    logger.error(`[${schema.componentName}]生命周期${method}出错`, e);\n  }\n}\n\n/**\n * get children from a node schema\n * @PRIVATE\n */\nexport function getSchemaChildren(schema: IPublicTypeNodeSchema | undefined) {\n  if (!schema) {\n    return;\n  }\n\n  if (!schema.props) {\n    return schema.children;\n  }\n\n  if (!schema.children) {\n    return schema.props.children;\n  }\n\n  if (!schema.props.children) {\n    return schema.children;\n  }\n\n  let result = ([] as IPublicTypeNodeData[]).concat(schema.children);\n  if (Array.isArray(schema.props.children)) {\n    result = result.concat(schema.props.children);\n  } else {\n    result.push(schema.props.children);\n  }\n  return result;\n}\n\nexport default function baseRendererFactory(): IBaseRenderComponent {\n  const { BaseRenderer: customBaseRenderer } = adapter.getRenderers();\n\n  if (customBaseRenderer) {\n    return customBaseRenderer;\n  }\n\n  const { Component, createElement } = adapter.getRuntime();\n  const Div = divFactory();\n  const VisualDom = visualDomFactory();\n  const AppContext = contextFactory();\n\n  const DESIGN_MODE = {\n    EXTEND: 'extend',\n    BORDER: 'border',\n    PREVIEW: 'preview',\n  };\n  const OVERLAY_LIST = ['Dialog', 'Overlay', 'Animate', 'ConfigProvider'];\n  const DEFAULT_LOOP_ARG_ITEM = 'item';\n  const DEFAULT_LOOP_ARG_INDEX = 'index';\n  let scopeIdx = 0;\n\n  return class BaseRenderer extends Component<IBaseRendererProps, Record<string, any>> {\n    [key: string]: any;\n\n    static displayName = 'BaseRenderer';\n\n    static defaultProps = {\n      __schema: {},\n    };\n\n    static contextType = AppContext;\n\n    i18n: any;\n    getLocale: any;\n    setLocale: any;\n    dataSourceMap: Record<string, any> = {};\n\n    __namespace = 'base';\n    __compScopes: Record<string, any> = {};\n    __instanceMap: Record<string, any> = {};\n    __dataHelper: any;\n\n    /**\n     * keep track of customMethods added to this context\n     *\n     * @type {any}\n     */\n    __customMethodsList: any[] = [];\n    __parseExpression: any;\n    __ref: any;\n\n    /**\n     * reference of style element contains schema.css\n     *\n     * @type {any}\n     */\n    __styleElement: any;\n\n    constructor(props: IBaseRendererProps, context: IBaseRendererContext) {\n      super(props, context);\n      this.context = context;\n      this.__parseExpression = (str: string, self: any) => {\n        return parseExpression({ str, self, thisRequired: props?.thisRequiredInJSE, logScope: props.componentName });\n      };\n      this.__beforeInit(props);\n      this.__init(props);\n      this.__afterInit(props);\n      this.__debug(`constructor - ${props?.__schema?.fileName}`);\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    __beforeInit(_props: IBaseRendererProps) { }\n\n    __init(props: IBaseRendererProps) {\n      this.__compScopes = {};\n      this.__instanceMap = {};\n      this.__bindCustomMethods(props);\n      this.__initI18nAPIs();\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    __afterInit(_props: IBaseRendererProps) { }\n\n    static getDerivedStateFromProps(props: IBaseRendererProps, state: any) {\n      const result = executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE);\n      return result === undefined ? null : result;\n    }\n\n    async getSnapshotBeforeUpdate(...args: any[]) {\n      this.__executeLifeCycleMethod('getSnapshotBeforeUpdate', args);\n      this.__debug(`getSnapshotBeforeUpdate - ${this.props?.__schema?.fileName}`);\n    }\n\n    async componentDidMount(...args: any[]) {\n      this.reloadDataSource();\n      this.__executeLifeCycleMethod('componentDidMount', args);\n      this.__debug(`componentDidMount - ${this.props?.__schema?.fileName}`);\n    }\n\n    async componentDidUpdate(...args: any[]) {\n      this.__executeLifeCycleMethod('componentDidUpdate', args);\n      this.__debug(`componentDidUpdate - ${this.props.__schema.fileName}`);\n    }\n\n    async componentWillUnmount(...args: any[]) {\n      this.__executeLifeCycleMethod('componentWillUnmount', args);\n      this.__debug(`componentWillUnmount - ${this.props?.__schema?.fileName}`);\n    }\n\n    async componentDidCatch(...args: any[]) {\n      this.__executeLifeCycleMethod('componentDidCatch', args);\n      logger.warn(args);\n    }\n\n    reloadDataSource = () => new Promise((resolve, reject) => {\n      this.__debug('reload data source');\n      if (!this.__dataHelper) {\n        return resolve({});\n      }\n      this.__dataHelper.getInitData()\n        .then((res: any) => {\n          if (isEmpty(res)) {\n            this.forceUpdate();\n            return resolve({});\n          }\n          this.setState(res, resolve as () => void);\n        })\n        .catch((err: Error) => {\n          reject(err);\n        });\n    });\n\n    shouldComponentUpdate() {\n      if (this.props.getSchemaChangedSymbol?.() && this.props.__container?.rerender) {\n        this.props.__container?.rerender();\n        return false;\n      }\n      return true;\n    }\n\n    forceUpdate() {\n      if (this.shouldComponentUpdate()) {\n        super.forceUpdate();\n      }\n    }\n\n    /**\n     * execute method in schema.lifeCycles\n     * @PRIVATE\n     */\n    __executeLifeCycleMethod = (method: string, args?: any) => {\n      executeLifeCycleMethod(this, this.props.__schema, method, args, this.props.thisRequiredInJSE);\n    };\n\n    /**\n     * this method is for legacy purpose only, which used _ prefix instead of __ as private for some historical reasons\n     * @LEGACY\n     */\n    _getComponentView = (componentName: string) => {\n      const { __components } = this.props;\n      if (!__components) {\n        return;\n      }\n      return __components[componentName];\n    };\n\n    __bindCustomMethods = (props: IBaseRendererProps) => {\n      const { __schema } = props;\n      const customMethodsList = Object.keys(__schema.methods || {}) || [];\n      (this.__customMethodsList || []).forEach((item: any) => {\n        if (!customMethodsList.includes(item)) {\n          delete this[item];\n        }\n      });\n      this.__customMethodsList = customMethodsList;\n      forEach(__schema.methods, (val: any, key: string) => {\n        let value = val;\n        if (isJSExpression(value) || isJSFunction(value)) {\n          value = this.__parseExpression(value, this);\n        }\n        if (typeof value !== 'function') {\n          logger.error(`custom method ${key} can not be parsed to a valid function`, value);\n          return;\n        }\n        this[key] = value.bind(this);\n      });\n    };\n\n    __generateCtx = (ctx: Record<string, any>) => {\n      const { pageContext, compContext } = this.context;\n      const obj = {\n        page: pageContext,\n        component: compContext,\n        ...ctx,\n      };\n      forEach(obj, (val: any, key: string) => {\n        this[key] = val;\n      });\n    };\n\n    __parseData = (data: any, ctx?: Record<string, any>) => {\n      const { __ctx, thisRequiredInJSE, componentName } = this.props;\n      return parseData(data, ctx || __ctx || this, { thisRequiredInJSE, logScope: componentName });\n    };\n\n    __initDataSource = (props: IBaseRendererProps) => {\n      if (!props) {\n        return;\n      }\n      const schema = props.__schema || {};\n      const defaultDataSource: DataSource = {\n        list: [],\n      };\n      const dataSource = schema.dataSource || defaultDataSource;\n      // requestHandlersMap 存在才走数据源引擎方案\n      // TODO: 下面if else 抽成独立函数\n      const useDataSourceEngine = !!(props.__appHelper?.requestHandlersMap);\n      if (useDataSourceEngine) {\n        this.__dataHelper = {\n          updateConfig: (updateDataSource: any) => {\n            const { dataSourceMap, reloadDataSource } = createDataSourceEngine(\n              updateDataSource ?? {},\n              this,\n              props.__appHelper.requestHandlersMap ? { requestHandlersMap: props.__appHelper.requestHandlersMap } : undefined,\n            );\n\n            this.reloadDataSource = () => new Promise((resolve) => {\n              this.__debug('reload data source');\n              reloadDataSource().then(() => {\n                resolve({});\n              });\n            });\n            return dataSourceMap;\n          },\n        };\n        this.dataSourceMap = this.__dataHelper.updateConfig(dataSource);\n      } else {\n        const appHelper = props.__appHelper;\n        this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config: any) => this.__parseData(config));\n        this.dataSourceMap = this.__dataHelper.dataSourceMap;\n        this.reloadDataSource = () => new Promise((resolve, reject) => {\n          this.__debug('reload data source');\n          if (!this.__dataHelper) {\n            return resolve({});\n          }\n          this.__dataHelper.getInitData()\n            .then((res: any) => {\n              if (isEmpty(res)) {\n                return resolve({});\n              }\n              this.setState(res, resolve as () => void);\n            })\n            .catch((err: Error) => {\n              reject(err);\n            });\n        });\n      }\n    };\n\n    /**\n     * init i18n apis\n     * @PRIVATE\n     */\n    __initI18nAPIs = () => {\n      this.i18n = (key: string, values = {}) => {\n        const { locale, messages } = this.props;\n        return getI18n(key, values, locale, messages);\n      };\n      this.getLocale = () => this.props.locale;\n      this.setLocale = (loc: string) => {\n        const setLocaleFn = this.appHelper?.utils?.i18n?.setLocale;\n        if (!setLocaleFn || typeof setLocaleFn !== 'function') {\n          logger.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists');\n          return undefined;\n        }\n        return setLocaleFn(loc);\n      };\n    };\n\n    /**\n     * write props.__schema.css to document as a style element,\n     * which will be added once and only once.\n     * @PRIVATE\n     */\n    __writeCss = (props: IBaseRendererProps) => {\n      const css = getValue(props.__schema, 'css', '');\n      this.__debug('create this.styleElement with css', css);\n      let style = this.__styleElement;\n      if (!this.__styleElement) {\n        style = document.createElement('style');\n        style.type = 'text/css';\n        style.setAttribute('from', 'style-sheet');\n\n        const head = document.head || document.getElementsByTagName('head')[0];\n        head.appendChild(style);\n        this.__styleElement = style;\n        this.__debug('this.styleElement is created', this.__styleElement);\n      }\n\n      if (style.innerHTML === css) {\n        return;\n      }\n\n      style.innerHTML = css;\n    };\n\n    __render = () => {\n      const schema = this.props.__schema;\n      this.__executeLifeCycleMethod('render');\n      this.__writeCss(this.props);\n\n      const { engine } = this.context;\n      if (engine) {\n        engine.props.onCompGetCtx(schema, this);\n        // 画布场景才需要每次渲染bind自定义方法\n        if (this.__designModeIsDesign) {\n          this.__bindCustomMethods(this.props);\n          this.dataSourceMap = this.__dataHelper?.updateConfig(schema.dataSource);\n        }\n      }\n    };\n\n    __getRef = (ref: any) => {\n      const { engine } = this.context;\n      const { __schema } = this.props;\n      ref && engine?.props?.onCompGetRef(__schema, ref);\n      this.__ref = ref;\n    };\n\n    __createDom = () => {\n      const { __schema, __ctx, __components = {} } = this.props;\n      // merge defaultProps\n      const scopeProps = {\n        ...__schema.defaultProps,\n        ...this.props,\n      };\n      const scope: any = {\n        props: scopeProps,\n      };\n      scope.__proto__ = __ctx || this;\n\n      const _children = getSchemaChildren(__schema);\n      let Comp = __components[__schema.componentName];\n\n      if (!Comp) {\n        this.__debug(`${__schema.componentName} is invalid!`);\n      }\n      const parentNodeInfo = ({\n        schema: __schema,\n        Comp: this.__getHOCWrappedComponent(Comp, __schema, scope),\n      } as INodeInfo);\n      return this.__createVirtualDom(_children, scope, parentNodeInfo);\n    };\n\n    /**\n     * 将模型结构转换成react Element\n     * @param originalSchema schema\n     * @param originalScope scope\n     * @param parentInfo 父组件的信息，包含schema和Comp\n     * @param idx 为循环渲染的循环Index\n     */\n    __createVirtualDom = (originalSchema: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined, originalScope: any, parentInfo: INodeInfo, idx: string | number = ''): any => {\n      if (originalSchema === null || originalSchema === undefined) {\n        return null;\n      }\n      let scope = originalScope;\n      let schema = originalSchema;\n      const { engine } = this.context || {};\n      if (!engine) {\n        this.__debug('this.context.engine is invalid!');\n        return null;\n      }\n      try {\n        const { __appHelper: appHelper, __components: components = {} } = this.props || {};\n\n        if (isJSExpression(schema)) {\n          return this.__parseExpression(schema, scope);\n        }\n        if (isI18nData(schema)) {\n          return parseI18n(schema, scope);\n        }\n        if (isJSSlot(schema)) {\n          return this.__createVirtualDom(schema.value, scope, parentInfo);\n        }\n\n        if (typeof schema === 'string') {\n          return schema;\n        }\n\n        if (typeof schema === 'number' || typeof schema === 'boolean') {\n          return String(schema);\n        }\n\n        if (Array.isArray(schema)) {\n          if (schema.length === 1) {\n            return this.__createVirtualDom(schema[0], scope, parentInfo);\n          }\n          return schema.map((item, idy) => this.__createVirtualDom(item, scope, parentInfo, (item as IPublicTypeNodeSchema)?.__ctx?.lceKey ? '' : String(idy)));\n        }\n\n        // @ts-expect-error 如果直接转换好了，可以返回\n        if (schema.$$typeof) {\n          return schema;\n        }\n\n        const _children = getSchemaChildren(schema);\n        if (!schema.componentName) {\n          logger.error('The componentName in the schema is invalid, please check the schema: ', schema);\n          return;\n        }\n        // 解析占位组件\n        if (schema.componentName === 'Fragment' && _children) {\n          const tarChildren = isJSExpression(_children) ? this.__parseExpression(_children, scope) : _children;\n          return this.__createVirtualDom(tarChildren, scope, parentInfo);\n        }\n\n        if (schema.componentName === 'Text' && typeof schema.props?.text === 'string') {\n          const text: string = schema.props?.text;\n          schema = { ...schema };\n          schema.children = [text];\n        }\n\n        if (!isSchema(schema)) {\n          return null;\n        }\n        let Comp = components[schema.componentName] || this.props.__container?.components?.[schema.componentName];\n\n        // 容器类组件的上下文通过props传递，避免context传递带来的嵌套问题\n        const otherProps: any = isFileSchema(schema)\n          ? {\n            __schema: schema,\n            __appHelper: appHelper,\n            __components: components,\n          }\n          : {};\n\n        if (!Comp) {\n          logger.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components);\n          return engine.createElement(\n            engine.getNotFoundComponent(),\n            {\n              componentName: schema.componentName,\n              componentId: schema.id,\n              enableStrictNotFoundMode: engine.props.enableStrictNotFoundMode,\n              ref: (ref: any) => {\n                ref && engine.props?.onCompGetRef(schema, ref);\n              },\n            },\n            this.__getSchemaChildrenVirtualDom(schema, scope, Comp),\n          );\n        }\n\n        if (schema.loop != null) {\n          const loop = this.__parseData(schema.loop, scope);\n          if (Array.isArray(loop) && loop.length === 0) return null;\n          const useLoop = isUseLoop(loop, this.__designModeIsDesign);\n          if (useLoop) {\n            return this.__createLoopVirtualDom(\n              {\n                ...schema,\n                loop,\n              },\n              scope,\n              parentInfo,\n              idx,\n            );\n          }\n        }\n        const condition = schema.condition == null ? true : this.__parseData(schema.condition, scope);\n\n        // DesignMode 为 design 情况下，需要进入 leaf Hoc，进行相关事件注册\n        const displayInHook = this.__designModeIsDesign;\n        if (!condition && !displayInHook) {\n          return null;\n        }\n\n        let scopeKey = '';\n        // 判断组件是否需要生成scope，且只生成一次，挂在this.__compScopes上\n        if (Comp.generateScope) {\n          const key = this.__parseExpression(schema.props?.key, scope);\n          if (key) {\n            // 如果组件自己设置key则使用组件自己的key\n            scopeKey = key;\n          } else if (!schema.__ctx) {\n            // 在生产环境schema没有__ctx上下文，需要手动生成一个lceKey\n            schema.__ctx = {\n              lceKey: `lce${++scopeIdx}`,\n            };\n            scopeKey = schema.__ctx.lceKey;\n          } else {\n            // 需要判断循环的情况\n            scopeKey = schema.__ctx.lceKey + (idx !== undefined ? `_${idx}` : '');\n          }\n          if (!this.__compScopes[scopeKey]) {\n            this.__compScopes[scopeKey] = Comp.generateScope(this, schema);\n          }\n        }\n        // 如果组件有设置scope，需要为组件生成一个新的scope上下文\n        if (scopeKey && this.__compScopes[scopeKey]) {\n          const compSelf = { ...this.__compScopes[scopeKey] };\n          compSelf.__proto__ = scope;\n          scope = compSelf;\n        }\n\n        if (engine.props?.designMode) {\n          otherProps.__designMode = engine.props.designMode;\n        }\n        if (this.__designModeIsDesign) {\n          otherProps.__tag = Math.random();\n        }\n        const componentInfo: any = {};\n        const props: any = this.__getComponentProps(schema, scope, Comp, {\n          ...componentInfo,\n          props: transformArrayToMap(componentInfo.props, 'name'),\n        }) || {};\n\n        this.__componentHOCs.forEach((ComponentConstruct: IComponentConstruct) => {\n          Comp = ComponentConstruct(Comp, {\n            schema,\n            componentInfo,\n            baseRenderer: this,\n            scope,\n          });\n        });\n\n        otherProps.ref = (ref: any) => {\n          this.$(props.fieldId || props.ref, ref); // 收集ref\n          const refProps = props.ref;\n          if (refProps && typeof refProps === 'string') {\n            this[refProps] = ref;\n          }\n          ref && engine.props?.onCompGetRef(schema, ref);\n        };\n\n        // scope需要传入到组件上\n        if (scopeKey && this.__compScopes[scopeKey]) {\n          props.__scope = this.__compScopes[scopeKey];\n        }\n        if (schema?.__ctx?.lceKey) {\n          if (!isFileSchema(schema)) {\n            engine.props?.onCompGetCtx(schema, scope);\n          }\n          props.key = props.key || `${schema.__ctx.lceKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`;\n        } else if ((typeof idx === 'number' || typeof idx === 'string') && !props.key) {\n          // 仅当循环场景走这里\n          props.key = idx;\n        }\n\n        props.__id = schema.id;\n        if (!props.key) {\n          props.key = props.__id;\n        }\n\n        let child = this.__getSchemaChildrenVirtualDom(schema, scope, Comp, condition);\n        const renderComp = (innerProps: any) => engine.createElement(Comp, innerProps, child);\n        // 设计模式下的特殊处理\n        if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {\n          // 对于overlay,dialog等组件为了使其在设计模式下显示，外层需要增加一个div容器\n          if (OVERLAY_LIST.includes(schema.componentName)) {\n            const { ref, ...overlayProps } = otherProps;\n            return createElement(Div, {\n              ref,\n              __designMode: engine.props.designMode,\n            }, renderComp({ ...props, ...overlayProps }));\n          }\n          // 虚拟dom显示\n          if (componentInfo?.parentRule) {\n            const parentList = componentInfo.parentRule.split(',');\n            const { schema: parentSchema = { componentName: '' }, Comp: parentComp } = parentInfo;\n            if (\n              !parentList.includes(parentSchema.componentName) ||\n              parentComp !== components[parentSchema.componentName]\n            ) {\n              props.__componentName = schema.componentName;\n              Comp = VisualDom;\n            } else {\n              // 若虚拟dom在正常的渲染上下文中，就不显示设计模式了\n              props.__disableDesignMode = true;\n            }\n          }\n        }\n        return renderComp({\n          ...props,\n          ...otherProps,\n          __inner__: {\n            hidden: schema.hidden,\n            condition,\n          },\n        });\n      } catch (e) {\n        return engine.createElement(engine.getFaultComponent(), {\n          error: e,\n          schema,\n          self: scope,\n          parentInfo,\n          idx,\n        });\n      }\n    };\n\n    /**\n     * get Component HOCs\n     *\n     * @readonly\n     * @type {IComponentConstruct[]}\n     */\n    get __componentHOCs(): IComponentConstruct[] {\n      if (this.__designModeIsDesign) {\n        return [leafWrapper, compWrapper];\n      }\n      return [compWrapper];\n    }\n\n    __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, condition = true) => {\n      let children = condition ? getSchemaChildren(schema) : null;\n\n      // @todo 补完这里的 Element 定义 @承虎\n      let result: any = [];\n      if (children) {\n        if (!Array.isArray(children)) {\n          children = [children];\n        }\n\n        children.forEach((child: any) => {\n          const childVirtualDom = this.__createVirtualDom(\n            isJSExpression(child) ? this.__parseExpression(child, scope) : child,\n            scope,\n            {\n              schema,\n              Comp,\n            },\n          );\n\n          result.push(childVirtualDom);\n        });\n      }\n\n      if (result && result.length > 0) {\n        return result;\n      }\n      return null;\n    };\n\n    __getComponentProps = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, componentInfo?: any) => {\n      if (!schema) {\n        return {};\n      }\n      return this.__parseProps(schema?.props, scope, '', {\n        schema,\n        Comp,\n        componentInfo: {\n          ...(componentInfo || {}),\n          props: transformArrayToMap((componentInfo || {}).props, 'name'),\n        },\n      }) || {};\n    };\n\n    __createLoopVirtualDom = (schema: IPublicTypeNodeSchema, scope: any, parentInfo: INodeInfo, idx: number | string) => {\n      if (isFileSchema(schema)) {\n        logger.warn('file type not support Loop');\n        return null;\n      }\n      if (!Array.isArray(schema.loop)) {\n        return null;\n      }\n      const itemArg = (schema.loopArgs && schema.loopArgs[0]) || DEFAULT_LOOP_ARG_ITEM;\n      const indexArg = (schema.loopArgs && schema.loopArgs[1]) || DEFAULT_LOOP_ARG_INDEX;\n      const { loop } = schema;\n      return loop.map((item: IPublicTypeJSONValue | IPublicTypeCompositeValue, i: number) => {\n        const loopSelf: any = {\n          [itemArg]: item,\n          [indexArg]: i,\n        };\n        loopSelf.__proto__ = scope;\n        return this.__createVirtualDom(\n          {\n            ...schema,\n            loop: undefined,\n            props: {\n              ...schema.props,\n              // 循环下 key 不能为常量，这样会造成 key 值重复，渲染异常\n              key: isJSExpression(schema.props?.key) ? schema.props?.key : null,\n            },\n          },\n          loopSelf,\n          parentInfo,\n          idx ? `${idx}_${i}` : i,\n        );\n      });\n    };\n\n    get __designModeIsDesign() {\n      const { engine } = this.context || {};\n      return engine?.props?.designMode === 'design';\n    }\n\n    __parseProps = (originalProps: any, scope: any, path: string, info: INodeInfo): any => {\n      let props = originalProps;\n      const { schema, Comp, componentInfo = {} } = info;\n      const propInfo = getValue(componentInfo.props, path);\n      // FIXME: 将这行逻辑外置，解耦，线上环境不要验证参数，调试环境可以有，通过传参自定义\n      const propType = propInfo?.extra?.propType;\n\n      const checkProps = (value: any) => {\n        if (!propType) {\n          return value;\n        }\n        return checkPropTypes(value, path, propType, componentInfo.name) ? value : undefined;\n      };\n\n      const parseReactNode = (data: any, params: any) => {\n        if (isEmpty(params)) {\n          const virtualDom = this.__createVirtualDom(data, scope, ({ schema, Comp } as INodeInfo));\n          return checkProps(virtualDom);\n        }\n        return checkProps((...argValues: any[]) => {\n          const args: any = {};\n          if (Array.isArray(params) && params.length) {\n            params.forEach((item, idx) => {\n              if (typeof item === 'string') {\n                args[item] = argValues[idx];\n              } else if (item && typeof item === 'object') {\n                args[item.name] = argValues[idx];\n              }\n            });\n          }\n          args.__proto__ = scope;\n          return scope.__createVirtualDom(data, args, ({ schema, Comp } as INodeInfo));\n        });\n      };\n\n      if (isJSExpression(props)) {\n        props = this.__parseExpression(props, scope);\n        // 只有当变量解析出来为模型结构的时候才会继续解析\n        if (!isSchema(props) && !isJSSlot(props)) {\n          return checkProps(props);\n        }\n      }\n\n      const handleI18nData = (innerProps: any) => innerProps[innerProps.use || (this.getLocale && this.getLocale()) || 'zh-CN'];\n\n      // @LEGACY 兼容老平台设计态 i18n 数据\n      if (isI18nData(props)) {\n        const i18nProp = handleI18nData(props);\n        if (i18nProp) {\n          props = i18nProp;\n        } else {\n          return parseI18n(props, scope);\n        }\n      }\n\n      // @LEGACY 兼容老平台设计态的变量绑定\n      if (isVariable(props)) {\n        props = props.value;\n        if (isI18nData(props)) {\n          props = handleI18nData(props);\n        }\n      }\n\n      if (isJSFunction(props)) {\n        props = transformStringToFunction(props.value);\n      }\n      if (isJSSlot(props)) {\n        const { params, value } = props;\n        if (!isSchema(value) || isEmpty(value)) {\n          return undefined;\n        }\n        return parseReactNode(value, params);\n      }\n\n      // 兼容通过componentInfo判断的情况\n      if (isSchema(props)) {\n        const isReactNodeFunction = !!(propInfo?.type === 'ReactNode' && propInfo?.props?.type === 'function');\n\n        const isMixinReactNodeFunction = !!(\n          propInfo?.type === 'Mixin'\n          && propInfo?.props?.types?.indexOf('ReactNode') > -1\n          && propInfo?.props?.reactNodeProps?.type === 'function'\n        );\n\n        let params = null;\n        if (isReactNodeFunction) {\n          params = propInfo?.props?.params;\n        } else if (isMixinReactNodeFunction) {\n          params = propInfo?.props?.reactNodeProps?.params;\n        }\n        return parseReactNode(\n          props,\n          params,\n        );\n      }\n      if (Array.isArray(props)) {\n        return checkProps(props.map((item, idx) => this.__parseProps(item, scope, path ? `${path}.${idx}` : `${idx}`, info)));\n      }\n      if (typeof props === 'function') {\n        return checkProps(props.bind(scope));\n      }\n      if (props && typeof props === 'object') {\n        if (props.$$typeof) {\n          return checkProps(props);\n        }\n        const res: any = {};\n        forEach(props, (val: any, key: string) => {\n          if (key.startsWith('__')) {\n            res[key] = val;\n            return;\n          }\n          res[key] = this.__parseProps(val, scope, path ? `${path}.${key}` : key, info);\n        });\n        return checkProps(res);\n      }\n      return checkProps(props);\n    };\n\n    $(filedId: string, instance?: any) {\n      this.__instanceMap = this.__instanceMap || {};\n      if (!filedId || typeof filedId !== 'string') {\n        return this.__instanceMap;\n      }\n      if (instance) {\n        this.__instanceMap[filedId] = instance;\n      }\n      return this.__instanceMap[filedId];\n    }\n\n    __debug = (...args: any[]) => { logger.debug(...args); };\n\n    __renderContextProvider = (customProps?: object, children?: any) => {\n      return createElement(AppContext.Provider, {\n        value: {\n          ...this.context,\n          blockContext: this,\n          ...(customProps || {}),\n        },\n        children: children || this.__createDom(),\n      });\n    };\n\n    __renderContextConsumer = (children: any) => {\n      return createElement(AppContext.Consumer, {}, children);\n    };\n\n    __getHOCWrappedComponent(OriginalComp: any, schema: any, scope: any) {\n      let Comp = OriginalComp;\n      this.__componentHOCs.forEach((ComponentConstruct: IComponentConstruct) => {\n        Comp = ComponentConstruct(Comp || Div, {\n          schema,\n          componentInfo: {},\n          baseRenderer: this,\n          scope,\n        });\n      });\n\n      return Comp;\n    }\n\n    __renderComp(OriginalComp: any, ctxProps: object) {\n      let Comp = OriginalComp;\n      const { __schema, __ctx } = this.props;\n      const scope: any = {};\n      scope.__proto__ = __ctx || this;\n      Comp = this.__getHOCWrappedComponent(Comp, __schema, scope);\n      const data = this.__parseProps(__schema?.props, scope, '', {\n        schema: __schema,\n        Comp,\n        componentInfo: {},\n      });\n      const { className } = data;\n      const otherProps: any = {};\n      const { engine } = this.context || {};\n      if (!engine) {\n        return null;\n      }\n\n      if (this.__designModeIsDesign) {\n        otherProps.__tag = Math.random();\n      }\n\n      const child = engine.createElement(\n        Comp,\n        {\n          ...data,\n          ...this.props,\n          ref: this.__getRef,\n          className: classnames(getFileCssName(__schema?.fileName), className, this.props.className),\n          __id: __schema?.id,\n          ...otherProps,\n        },\n        this.__createDom(),\n      );\n      return this.__renderContextProvider(ctxProps, child);\n    }\n\n    __renderContent(children: any) {\n      const { __schema } = this.props;\n      const parsedProps = this.__parseData(__schema.props);\n      const className = classnames(`lce-${this.__namespace}`, getFileCssName(__schema.fileName), parsedProps.className, this.props.className);\n      const style = { ...(parsedProps.style || {}), ...(typeof this.props.style === 'object' ? this.props.style : {}) };\n      const id = this.props.id || parsedProps.id;\n      return createElement('div', {\n        ref: this.__getRef,\n        className,\n        id,\n        style,\n      }, children);\n    }\n\n    __checkSchema = (schema: IPublicTypeNodeSchema | undefined, originalExtraComponents: string | string[] = []) => {\n      let extraComponents = originalExtraComponents;\n      if (typeof extraComponents === 'string') {\n        extraComponents = [extraComponents];\n      }\n\n      const builtin = capitalizeFirstLetter(this.__namespace);\n      const componentNames = [builtin, ...extraComponents];\n      return !isSchema(schema) || !componentNames.includes(schema?.componentName ?? '');\n    };\n\n    get appHelper(): IRendererAppHelper {\n      return this.props.__appHelper;\n    }\n\n    get requestHandlersMap() {\n      return this.appHelper?.requestHandlersMap;\n    }\n\n    get utils() {\n      return this.appHelper?.utils;\n    }\n\n    get constants() {\n      return this.appHelper?.constants;\n    }\n\n    get history() {\n      return this.appHelper?.history;\n    }\n\n    get location() {\n      return this.appHelper?.location;\n    }\n\n    get match() {\n      return this.appHelper?.match;\n    }\n\n    render() {\n      return null;\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/block.tsx",
    "content": "import baseRendererFactory from './base';\nimport { IBaseRendererProps, IBaseRenderComponent } from '../types';\n\nexport default function blockRendererFactory(): IBaseRenderComponent {\n  const BaseRenderer = baseRendererFactory();\n  return class BlockRenderer extends BaseRenderer {\n    static displayName = 'BlockRenderer';\n\n    __namespace = 'block';\n\n    __afterInit(props: IBaseRendererProps) {\n      this.__generateCtx({});\n      const schema = props.__schema || {};\n      this.state = this.__parseData(schema.state || {});\n      this.__initDataSource(props);\n      this.__executeLifeCycleMethod('constructor', [...arguments]);\n    }\n\n    render() {\n      const { __schema, __components } = this.props;\n\n      if (this.__checkSchema(__schema, 'Div')) {\n        return '区块 schema 结构异常！';\n      }\n\n      this.__debug(`${BlockRenderer.displayName} render - ${__schema?.fileName}`);\n      this.__generateCtx({});\n      this.__render();\n\n      const { Block } = __components;\n      if (Block) {\n        return this.__renderComp(Block, {});\n      }\n\n      return this.__renderContent(this.__renderContextProvider());\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/component.tsx",
    "content": "import baseRendererFactory from './base';\nimport { IBaseRendererProps, IBaseRenderComponent } from '../types';\n\nexport default function componentRendererFactory(): IBaseRenderComponent {\n  const BaseRenderer = baseRendererFactory();\n  return class CompRenderer extends BaseRenderer {\n    static displayName = 'CompRenderer';\n\n    __namespace = 'component';\n\n    __afterInit(props: IBaseRendererProps) {\n      this.__generateCtx({\n        component: this,\n      });\n      const schema = props.__schema || {};\n      this.state = this.__parseData(schema.state || {});\n      this.__initDataSource(props);\n      this.__executeLifeCycleMethod('constructor', arguments as any);\n    }\n\n    render() {\n      const { __schema, __components } = this.props;\n      if (this.__checkSchema(__schema)) {\n        return '自定义组件 schema 结构异常！';\n      }\n      this.__debug(`${CompRenderer.displayName} render - ${__schema.fileName}`);\n\n      this.__generateCtx({\n        component: this,\n      });\n      this.__render();\n\n      const noContainer = this.__parseData(__schema.props?.noContainer);\n\n      this.__bindCustomMethods(this.props);\n\n      if (noContainer) {\n        return this.__renderContextProvider({ compContext: this });\n      }\n\n      const Component = __components?.[__schema?.componentName];\n\n      if (!Component) {\n        return this.__renderContent(this.__renderContextProvider({ compContext: this }));\n      }\n\n      return this.__renderComp(Component, this.__renderContextProvider({ compContext: this }));\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/index.ts",
    "content": "import baseRendererFactory from './base';\nimport pageRendererFactory from './page';\nimport componentRendererFactory from './component';\nimport blockRendererFactory from './block';\nimport addonRendererFactory from './addon';\nimport tempRendererFactory from './temp';\nimport rendererFactory from './renderer';\n\nexport {\n  baseRendererFactory,\n  pageRendererFactory,\n  componentRendererFactory,\n  blockRendererFactory,\n  addonRendererFactory,\n  tempRendererFactory,\n  rendererFactory,\n};\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/page.tsx",
    "content": "import { getLogger } from '@alilc/lowcode-utils';\nimport baseRendererFactory from './base';\nimport { IBaseRendererProps, IBaseRenderComponent } from '../types';\n\nconst logger = getLogger({ level: 'warn', bizName: 'renderer-core:page' });\n\nexport default function pageRendererFactory(): IBaseRenderComponent {\n  const BaseRenderer = baseRendererFactory();\n  return class PageRenderer extends BaseRenderer {\n    static displayName = 'PageRenderer';\n\n    __namespace = 'page';\n\n    __afterInit(props: IBaseRendererProps, ...rest: unknown[]) {\n      this.__generateCtx({\n        page: this,\n      });\n      const schema = props.__schema || {};\n      this.state = this.__parseData(schema.state || {});\n      this.__initDataSource(props);\n      this.__executeLifeCycleMethod('constructor', [props, ...rest]);\n    }\n\n    async componentDidUpdate(prevProps: IBaseRendererProps, _prevState: {}, snapshot: unknown) {\n      const { __ctx } = this.props;\n      // 当编排的时候修改 schema.state 值，需要将最新 schema.state 值 setState\n      if (JSON.stringify(prevProps.__schema.state) != JSON.stringify(this.props.__schema.state)) {\n        const newState = this.__parseData(this.props.__schema.state, __ctx);\n        this.setState(newState);\n      }\n\n      super.componentDidUpdate?.(prevProps, _prevState, snapshot);\n    }\n\n    setState(state: any, callback?: () => void) {\n      logger.info('page set state', state);\n      super.setState(state, callback);\n    }\n\n    render() {\n      const { __schema, __components } = this.props;\n      if (this.__checkSchema(__schema)) {\n        return '页面schema结构异常！';\n      }\n      this.__debug(`${PageRenderer.displayName} render - ${__schema.fileName}`);\n\n      this.__bindCustomMethods(this.props);\n      this.__initDataSource(this.props);\n\n      this.__generateCtx({\n        page: this,\n      });\n      this.__render();\n\n      const { Page } = __components;\n      if (Page) {\n        return this.__renderComp(Page, { pageContext: this });\n      }\n\n      return this.__renderContent(this.__renderContextProvider({ pageContext: this }));\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/renderer.tsx",
    "content": "import Debug from 'debug';\nimport adapter from '../adapter';\nimport contextFactory from '../context';\nimport { isFileSchema, isEmpty } from '../utils';\nimport baseRendererFactory from './base';\nimport divFactory from '../components/Div';\nimport { IRenderComponent, IRendererProps, IRendererState } from '../types';\nimport { IPublicTypeNodeSchema, IPublicTypeRootSchema } from '@alilc/lowcode-types';\nimport logger from '../utils/logger';\n\nexport default function rendererFactory(): IRenderComponent {\n  const { PureComponent, Component, createElement, findDOMNode } = adapter.getRuntime();\n  const RENDERER_COMPS: any = adapter.getRenderers();\n  const BaseRenderer = baseRendererFactory();\n  const AppContext = contextFactory();\n  const Div = divFactory();\n\n  const ConfigProvider = adapter.getConfigProvider() || Div;\n\n  const debug = Debug('renderer:entry');\n\n  class FaultComponent extends PureComponent<IPublicTypeNodeSchema | any> {\n    render() {\n      logger.error(`%c${this.props.componentName || ''} 组件渲染异常, 异常原因: ${this.props.error?.message || this.props.error || '未知'}`, 'color: #ff0000;');\n      return createElement(Div, {\n        style: {\n          width: '100%',\n          height: '50px',\n          lineHeight: '50px',\n          textAlign: 'center',\n          fontSize: '15px',\n          color: '#ff0000',\n          border: '2px solid #ff0000',\n        },\n      }, `${this.props.componentName || ''} 组件渲染异常，请查看控制台日志`);\n    }\n  }\n\n  class NotFoundComponent extends PureComponent<{\n    componentName: string;\n  } & IRendererProps> {\n    render() {\n      if (this.props.enableStrictNotFoundMode) {\n        return `${this.props.componentName || ''} Component Not Found`;\n      }\n      return createElement(Div, this.props, this.props.children || `${this.props.componentName || ''} Component Not Found`);\n    }\n  }\n\n  return class Renderer extends Component<IRendererProps> {\n    static displayName = 'Renderer';\n\n    state: Partial<IRendererState> = {};\n\n    __ref: any;\n\n    static defaultProps: IRendererProps = {\n      appHelper: undefined,\n      components: {},\n      designMode: '',\n      suspended: false,\n      schema: {} as IPublicTypeRootSchema,\n      onCompGetRef: () => { },\n      onCompGetCtx: () => { },\n      thisRequiredInJSE: true,\n    };\n\n    static findDOMNode = findDOMNode;\n\n    constructor(props: IRendererProps, context: any) {\n      super(props, context);\n      this.state = {};\n      debug(`entry.constructor - ${props?.schema?.componentName}`);\n    }\n\n    async componentDidMount() {\n      debug(`entry.componentDidMount - ${this.props.schema && this.props.schema.componentName}`);\n    }\n\n    async componentDidUpdate() {\n      debug(`entry.componentDidUpdate - ${this.props?.schema?.componentName}`);\n    }\n\n    async componentWillUnmount() {\n      debug(`entry.componentWillUnmount - ${this.props?.schema?.componentName}`);\n    }\n\n    componentDidCatch(error: Error) {\n      this.state.engineRenderError = true;\n      this.state.error = error;\n    }\n\n    shouldComponentUpdate(nextProps: IRendererProps) {\n      return !nextProps.suspended;\n    }\n\n    __getRef = (ref: any) => {\n      this.__ref = ref;\n      if (ref) {\n        this.props.onCompGetRef?.(this.props.schema, ref);\n      }\n    };\n\n    isValidComponent(SetComponent: any) {\n      return SetComponent;\n    }\n\n    createElement(SetComponent: any, props: any, children?: any) {\n      return (this.props.customCreateElement || createElement)(SetComponent, props, children);\n    }\n\n    getNotFoundComponent() {\n      return this.props.notFoundComponent || NotFoundComponent;\n    }\n\n    getFaultComponent() {\n      const { faultComponent, faultComponentMap, schema } = this.props;\n      if (faultComponentMap) {\n        const { componentName } = schema;\n        return faultComponentMap[componentName] || faultComponent || FaultComponent;\n      }\n      return faultComponent || FaultComponent;\n    }\n\n    getComp() {\n      const { schema, components } = this.props;\n      const { componentName } = schema;\n      const allComponents = { ...RENDERER_COMPS, ...components };\n      let Comp = allComponents[componentName] || RENDERER_COMPS[`${componentName}Renderer`];\n      if (Comp && Comp.prototype) {\n        if (!(Comp.prototype instanceof BaseRenderer)) {\n          Comp = RENDERER_COMPS[`${componentName}Renderer`];\n        }\n      }\n      return Comp;\n    }\n\n    render() {\n      const { schema, designMode, appHelper, components } = this.props;\n      if (isEmpty(schema)) {\n        return null;\n      }\n      // 兼容乐高区块模板\n      if (schema.componentName !== 'Div' && !isFileSchema(schema)) {\n        logger.error('The root component name needs to be one of Page、Block、Component, please check the schema: ', schema);\n        return '模型结构异常';\n      }\n      debug('entry.render');\n      const allComponents = { ...RENDERER_COMPS, ...components };\n      let Comp = this.getComp();\n\n      if (this.state && this.state.engineRenderError) {\n        return createElement(this.getFaultComponent(), {\n          ...this.props,\n          error: this.state.error,\n        });\n      }\n\n      if (Comp) {\n        return createElement(AppContext.Provider, {\n          value: {\n            appHelper,\n            components: allComponents,\n            engine: this,\n          },\n        }, createElement(ConfigProvider, {\n          device: this.props.device,\n          locale: this.props.locale,\n        }, createElement(Comp, {\n          key: schema.__ctx && `${schema.__ctx.lceKey}_${schema.__ctx.idx || '0'}`,\n          ref: this.__getRef,\n          __appHelper: appHelper,\n          __components: allComponents,\n          __schema: schema,\n          __designMode: designMode,\n          ...this.props,\n        })));\n      }\n      return null;\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/renderer/temp.tsx",
    "content": "import { IBaseRenderComponent } from '../types';\nimport logger from '../utils/logger';\nimport baseRendererFactory from './base';\n\nexport default function tempRendererFactory(): IBaseRenderComponent {\n  const BaseRenderer = baseRendererFactory();\n\n  return class TempRenderer extends BaseRenderer {\n    static displayName = 'TempRenderer';\n\n    __namespace = 'temp';\n\n    cacheSetState?: Record<string, any>;\n\n    __init() {\n      this.state = {};\n      this.cacheSetState = {};\n    }\n\n    async componentDidMount() {\n      const ctx = this.props.__ctx;\n      if (!ctx) return;\n      const { setState } = ctx;\n      this.cacheSetState = setState;\n      ctx.setState = (...args: any) => {\n        setState.call(ctx, ...args);\n        setTimeout(() => this.forceUpdate(), 0);\n      };\n      this.__debug(`componentDidMount - ${this.props.__schema.fileName}`);\n    }\n\n    async componentDidUpdate() {\n      this.__debug(`componentDidUpdate - ${this.props.__schema.fileName}`);\n    }\n\n    async componentWillUnmount() {\n      const ctx = this.props.__ctx;\n      if (!ctx || !this.cacheSetState) return;\n      ctx.setState = this.cacheSetState;\n      delete this.cacheSetState;\n      this.__debug(`componentWillUnmount - ${this.props.__schema.fileName}`);\n    }\n\n    async componentDidCatch(e: any) {\n      logger.warn(e);\n      this.__debug(`componentDidCatch - ${this.props.__schema.fileName}`);\n    }\n\n    render() {\n      const { __schema, __ctx } = this.props;\n      if (this.__checkSchema(__schema)) {\n        return '下钻编辑 schema 结构异常！';\n      }\n\n      this.__debug(`${TempRenderer.displayName} render - ${__schema?.fileName}`);\n\n      return this.__renderContent(this.__renderContextProvider({ __ctx }));\n    }\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/types/index.ts",
    "content": "import type { ComponentLifecycle, CSSProperties } from 'react';\nimport { BuiltinSimulatorHost, BuiltinSimulatorRenderer } from '@alilc/lowcode-designer';\nimport { RequestHandler, IPublicTypeNodeSchema, IPublicTypeRootSchema, IPublicTypeJSONObject } from '@alilc/lowcode-types';\n\nexport type ISchema = IPublicTypeNodeSchema | IPublicTypeRootSchema;\n\n/*\n ** Duck typed component type supporting both react and rax\n */\ninterface IGeneralComponent<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> {\n  readonly props: Readonly<P> & Readonly<{ children?: any | undefined }>;\n  state: Readonly<S>;\n  refs: Record<string, any>;\n  context: any;\n  setState<K extends keyof S>(\n    state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),\n    callback?: () => void\n  ): void;\n  forceUpdate(callback?: () => void): void;\n  render(): any;\n}\n\nexport type IGeneralConstructor<\n  T = {\n    [key: string]: any;\n  }, S = {\n    [key: string]: any;\n  }, D = any\n> = new <TT = T, SS = S, DD = D>(props: TT, context: any) => IGeneralComponent<TT, SS, DD>;\n\n/**\n * duck-typed History\n *\n * @see https://github.com/ReactTraining/history/tree/master/docs/api-reference.md\n */\ninterface IHistoryLike {\n  readonly action: any;\n  readonly location: ILocationLike;\n  createHref: (to: any) => string;\n  push: (to: any, state?: any) => void;\n  replace: (to: any, state?: any) => void;\n  go: (delta: any) => void;\n  back: () => void;\n  forward: () => void;\n  listen: (listener: any) => () => void;\n  block: (blocker: any) => () => void;\n}\n\n/**\n * duck-typed History.Location\n *\n * @see https://github.com/remix-run/history/blob/dev/docs/api-reference.md#location\n */\nexport interface ILocationLike {\n  pathname: any;\n  search: any;\n  state: any;\n  hash: any;\n  key?: any;\n}\n\nexport type IRendererAppHelper = Partial<{\n\n  /** 全局公共函数 */\n  utils: Record<string, any>;\n\n  /** 全局常量 */\n  constants: Record<string, any>;\n\n  /** react-router 的 location 实例 */\n  location: ILocationLike;\n\n  /** react-router 的 history 实例 */\n  history: IHistoryLike;\n\n  /** @deprecated 已无业务使用 */\n  match: any;\n\n  /** @experimental 内部使用 */\n  logParams: Record<string, any>;\n\n  /** @experimental 内部使用 */\n  addons: Record<string, any>;\n\n  /** @experimental 内部使用 */\n  requestHandlersMap: Record<string, RequestHandler<{\n    data: unknown;\n  }>>;\n}>;\n\n/**\n * 渲染模块可用配置\n *\n * @see @todo @承虎\n */\nexport interface IRendererProps {\n\n  /** 符合低代码搭建协议的数据 */\n  schema: IPublicTypeRootSchema | IPublicTypeNodeSchema;\n\n  /** 组件依赖的实例 */\n  components: Record<string, IGeneralComponent>;\n\n  /** CSS 类名 */\n  className?: string;\n\n  /** style */\n  style?: CSSProperties;\n\n  /** id */\n  id?: string | number;\n\n  /** 语言 */\n  locale?: string;\n\n  /**\n   * 多语言语料\n   * 配置规范参见《低代码搭建组件描述协议》https://lowcode-engine.cn/lowcode 中 2.6 国际化多语言支持\n   * */\n  messages?: Record<string, any>;\n\n  /** 主要用于设置渲染模块的全局上下文，里面定义的内容可以在低代码中通过 this 来访问，比如 this.utils */\n  appHelper?: IRendererAppHelper;\n\n  /**\n   * 配置规范参见《低代码搭建组件描述协议》https://lowcode-engine.cn/lowcode\n   * 主要在搭建场景中使用，用于提升用户搭建体验。\n   *\n   * > 在生产环境下不需要设置\n   */\n  componentsMap?: { [key: string]: any };\n\n  /** 设计模式，可选值：live、design */\n  designMode?: string;\n\n  /** 渲染模块是否挂起，当设置为 true 时，渲染模块最外层容器的 shouldComponentUpdate 将始终返回false，在下钻编辑或者多引擎渲染的场景会用到该参数。 */\n  suspended?: boolean;\n\n  /** 组件获取 ref 时触发的钩子 */\n  onCompGetRef?: (schema: IPublicTypeNodeSchema, ref: any) => void;\n\n  /** 组件 ctx 更新回调 */\n  onCompGetCtx?: (schema: IPublicTypeNodeSchema, ref: any) => void;\n\n  /** 传入的 schema 是否有变更 */\n  getSchemaChangedSymbol?: () => boolean;\n\n  /** 设置 schema 是否有变更 */\n  setSchemaChangedSymbol?: (symbol: boolean) => void;\n\n  /** 自定义创建 element 的钩子 */\n  customCreateElement?: (Component: any, props: any, children: any) => any;\n\n  /** 渲染类型，标识当前模块是以什么类型进行渲染的 */\n  rendererName?: 'LowCodeRenderer' | 'PageRenderer' | string;\n\n  /** 当找不到组件时，显示的组件 */\n  notFoundComponent?: IGeneralComponent;\n\n  /** 当组件渲染异常时，显示的组件 */\n  faultComponent?: IGeneralComponent;\n\n  /**  */\n  faultComponentMap?: {\n    [prop: string]: IGeneralComponent;\n  };\n\n  /** 设备信息 */\n  device?: string;\n\n  /**\n   * @default true\n   * JSExpression 是否只支持使用 this 来访问上下文变量\n   */\n  thisRequiredInJSE?: boolean;\n\n  /**\n   * @default false\n   * 当开启组件未找到严格模式时，渲染模块不会默认给一个容器组件\n   */\n  enableStrictNotFoundMode?: boolean;\n}\n\nexport interface IRendererState {\n  engineRenderError?: boolean;\n  error?: Error;\n}\n\n/**\n * 渲染内部模块可用配置\n */\nexport interface IBaseRendererProps {\n  locale?: string;\n  messages: Record<string, any>;\n  __appHelper: IRendererAppHelper;\n  __components: Record<string, any>;\n  __ctx: Record<string, any>;\n  __schema: IPublicTypeRootSchema;\n  __host?: BuiltinSimulatorHost;\n  __container?: BuiltinSimulatorRenderer;\n  config?: Record<string, any>;\n  designMode?: 'design';\n  className?: string;\n  style?: CSSProperties;\n  id?: string | number;\n  getSchemaChangedSymbol?: () => boolean;\n  setSchemaChangedSymbol?: (symbol: boolean) => void;\n  thisRequiredInJSE?: boolean;\n  documentId?: string;\n  getNode?: any;\n\n  /**\n   * 设备类型，默认值：'default'\n   */\n  device?: 'default' | 'mobile' | string;\n  componentName?: string;\n}\n\nexport interface INodeInfo {\n  schema?: IPublicTypeNodeSchema;\n  Comp: any;\n  componentInfo?: any;\n  componentChildren?: any;\n}\n\nexport interface JSExpression {\n  type: string;\n  value: string;\n}\n\nexport interface DataSourceItem {\n  id: string;\n  isInit?: boolean | JSExpression;\n  type?: string;\n  options?: {\n    uri: string | JSExpression;\n    params?: IPublicTypeJSONObject | JSExpression;\n    method?: string | JSExpression;\n    shouldFetch?: string;\n    willFetch?: string;\n    fit?: string;\n    didFetch?: string;\n  };\n  dataHandler?: JSExpression;\n}\n\nexport interface DataSource {\n  list?: DataSourceItem[];\n  dataHandler?: JSExpression;\n}\n\nexport interface IRuntime {\n  [key: string]: any;\n  Component: IGeneralConstructor;\n  PureComponent: IGeneralConstructor;\n  createElement: (...args: any) => any;\n  createContext: (...args: any) => any;\n  forwardRef: (...args: any) => any;\n  findDOMNode: (...args: any) => any;\n}\n\nexport interface IRendererModules {\n  BaseRenderer?: IBaseRenderComponent;\n  PageRenderer: IBaseRenderComponent;\n  ComponentRenderer: IBaseRenderComponent;\n  BlockRenderer?: IBaseRenderComponent;\n  AddonRenderer?: IBaseRenderComponent;\n  TempRenderer?: IBaseRenderComponent;\n  DivRenderer?: IBaseRenderComponent;\n}\n\nexport interface IBaseRendererContext {\n  appHelper: IRendererAppHelper;\n  components: Record<string, IGeneralComponent>;\n  engine: IRuntime;\n  pageContext?: IBaseRenderComponent;\n  compContext?: IBaseRenderComponent;\n}\n\nexport type IBaseRendererInstance = IGeneralComponent<\n  IBaseRendererProps,\n  Record<string, any>,\n  any\n>\n  & {\n    reloadDataSource(): Promise<any>;\n    __beforeInit(props: IBaseRendererProps): void;\n    __init(props: IBaseRendererProps): void;\n    __afterInit(props: IBaseRendererProps): void;\n    __executeLifeCycleMethod(method: string, args?: any[]): void;\n    __bindCustomMethods(props: IBaseRendererProps): void;\n    __generateCtx(ctx: Record<string, any>): void;\n    __parseData(data: any, ctx?: any): any;\n    __initDataSource(props: IBaseRendererProps): void;\n    __render(): void;\n    __getRef(ref: any): void;\n    __getSchemaChildrenVirtualDom(\n      schema: IPublicTypeNodeSchema | undefined,\n      Comp: any,\n      nodeChildrenMap?: any\n    ): any;\n    __getComponentProps(schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, componentInfo?: any): any;\n    __createDom(): any;\n    __createVirtualDom(schema: any, self: any, parentInfo: INodeInfo, idx: string | number): any;\n    __createLoopVirtualDom(schema: any, self: any, parentInfo: INodeInfo, idx: number | string): any;\n    __parseProps(props: any, self: any, path: string, info: INodeInfo): any;\n    __initDebug?(): void;\n    __debug(...args: any[]): void;\n    __renderContextProvider(customProps?: object, children?: any): any;\n    __renderContextConsumer(children: any): any;\n    __renderContent(children: any): any;\n    __checkSchema(schema: IPublicTypeNodeSchema | undefined, extraComponents?: string | string[]): any;\n    __renderComp(Comp: any, ctxProps: object): any;\n    $(filedId: string, instance?: any): any;\n  };\n\nexport interface IBaseRenderComponent {\n  new(\n    props: IBaseRendererProps,\n    context: any\n  ): IBaseRendererInstance;\n}\n\nexport interface IRenderComponent {\n  displayName: string;\n  defaultProps: IRendererProps;\n  findDOMNode: (...args: any) => any;\n\n  new(props: IRendererProps, context: any): IGeneralComponent<IRendererProps, IRendererState> & {\n    [x: string]: any;\n    __getRef: (ref: any) => void;\n    componentDidMount(): Promise<void> | void;\n    componentDidUpdate(): Promise<void> | void;\n    componentWillUnmount(): Promise<void> | void;\n    componentDidCatch(e: any): Promise<void> | void;\n    shouldComponentUpdate(nextProps: IRendererProps): boolean;\n    isValidComponent(SetComponent: any): any;\n    createElement(SetComponent: any, props: any, children?: any): any;\n    getNotFoundComponent(): any;\n    getFaultComponent(): any;\n  };\n}\n"
  },
  {
    "path": "packages/renderer-core/src/utils/common.ts",
    "content": "/* eslint-disable no-console */\n/* eslint-disable no-new-func */\nimport logger from './logger';\nimport { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot } from '@alilc/lowcode-types';\nimport { isI18nData, isJSExpression } from '@alilc/lowcode-utils';\nimport { isEmpty } from 'lodash';\nimport IntlMessageFormat from 'intl-messageformat';\nimport pkg from '../../package.json';\n\n(window as any).sdkVersion = pkg.version;\n\nexport { pick, isEqualWith as deepEqual, cloneDeep as clone, isEmpty, throttle, debounce } from 'lodash';\n\nconst EXPRESSION_TYPE = {\n  JSEXPRESSION: 'JSExpression',\n  JSFUNCTION: 'JSFunction',\n  JSSLOT: 'JSSlot',\n  JSBLOCK: 'JSBlock',\n  I18N: 'i18n',\n};\n\n/**\n * check if schema passed in is a valid schema\n * @name isSchema\n * @returns boolean\n */\nexport function isSchema(schema: any): schema is IPublicTypeNodeSchema {\n  if (isEmpty(schema)) {\n    return false;\n  }\n  // Leaf and Slot should be valid\n  if (schema.componentName === 'Leaf' || schema.componentName === 'Slot') {\n    return true;\n  }\n  if (Array.isArray(schema)) {\n    return schema.every((item) => isSchema(item));\n  }\n  // check if props is valid\n  const isValidProps = (props: any) => {\n    if (!props) {\n      return false;\n    }\n    if (isJSExpression(props)) {\n      return true;\n    }\n    return (typeof schema.props === 'object' && !Array.isArray(props));\n  };\n  return !!(schema.componentName && isValidProps(schema.props));\n}\n\n/**\n * check if schema passed in is a container type, including : Component Block Page\n * @param schema\n * @returns boolean\n */\nexport function isFileSchema(schema: IPublicTypeNodeSchema): schema is IPublicTypeRootSchema {\n  if (!isSchema(schema)) {\n    return false;\n  }\n  return ['Page', 'Block', 'Component'].includes(schema.componentName);\n}\n\n/**\n * check if current page is nested within another page with same host\n * @returns boolean\n */\nexport function inSameDomain() {\n  try {\n    return window.parent !== window && window.parent.location.host === window.location.host;\n  } catch (e) {\n    return false;\n  }\n}\n\n/**\n * get css styled name from schema`s fileName\n * FileName -> lce-file-name\n * @returns string\n */\nexport function getFileCssName(fileName: string) {\n  if (!fileName) {\n    return;\n  }\n  const name = fileName.replace(/([A-Z])/g, '-$1').toLowerCase();\n  return (`lce-${name}`)\n    .split('-')\n    .filter((p) => !!p)\n    .join('-');\n}\n\n/**\n * check if a object is type of JSSlot\n * @returns string\n */\nexport function isJSSlot(obj: any): obj is IPublicTypeJSSlot {\n  if (!obj) {\n    return false;\n  }\n  if (typeof obj !== 'object' || Array.isArray(obj)) {\n    return false;\n  }\n\n  // Compatible with the old protocol JSBlock\n  return [EXPRESSION_TYPE.JSSLOT, EXPRESSION_TYPE.JSBLOCK].includes(obj.type);\n}\n\n/**\n * get value from an object\n * @returns string\n */\nexport function getValue(obj: any, path: string, defaultValue = {}) {\n  // array is not valid type, return default value\n  if (Array.isArray(obj)) {\n    return defaultValue;\n  }\n\n  if (isEmpty(obj) || typeof obj !== 'object') {\n    return defaultValue;\n  }\n\n  const res = path.split('.').reduce((pre, cur) => {\n    return pre && pre[cur];\n  }, obj);\n  if (res === undefined) {\n    return defaultValue;\n  }\n  return res;\n}\n\n/**\n * 用于处理国际化字符串\n * @param {*} key 语料标识\n * @param {*} values 字符串模版变量\n * @param {*} locale 国际化标识，例如 zh-CN、en-US\n * @param {*} messages 国际化语言包\n */\nexport function getI18n(key: string, values = {}, locale = 'zh-CN', messages: Record<string, any> = {}) {\n  if (!messages || !messages[locale] || !messages[locale][key]) {\n    return '';\n  }\n  const formater = new IntlMessageFormat(messages[locale][key], locale);\n  return formater.format(values);\n}\n\n/**\n * 判断当前组件是否能够设置ref\n * @param {*} Comp 需要判断的组件\n */\nexport function canAcceptsRef(Comp: any) {\n  const hasSymbol = typeof Symbol === 'function' && Symbol.for;\n  const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;\n  // eslint-disable-next-line max-len\n  return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState || Comp._forwardRef;\n}\n\n/**\n * transform array to a object\n * @param arr array to be transformed\n * @param key key of array item, which`s value will be used as key in result map\n * @param overwrite overwrite existing item in result or not\n * @returns object result map\n */\nexport function transformArrayToMap(arr: any[], key: string, overwrite = true) {\n  if (isEmpty(arr) || !Array.isArray(arr)) {\n    return {};\n  }\n  const res: any = {};\n  arr.forEach((item) => {\n    const curKey = item[key];\n    if (item[key] === undefined) {\n      return;\n    }\n    if (res[curKey] && !overwrite) {\n      return;\n    }\n    res[curKey] = item;\n  });\n  return res;\n}\n\n/**\n * transform string to a function\n * @param str function in string form\n * @returns funtion\n */\nexport function transformStringToFunction(str: string) {\n  if (typeof str !== 'string') {\n    return str;\n  }\n  if (inSameDomain() && (window.parent as any).__newFunc) {\n    return (window.parent as any).__newFunc(`\"use strict\"; return ${str}`)();\n  } else {\n    return new Function(`\"use strict\"; return ${str}`)();\n  }\n}\n\n/**\n * 对象类型JSExpression，支持省略this\n * @param str expression in string form\n * @param self scope object\n * @returns funtion\n */\n\nfunction parseExpression(options: {\n  str: any; self: any; thisRequired?: boolean; logScope?: string;\n}): any;\nfunction parseExpression(str: any, self: any, thisRequired?: boolean): any;\nfunction parseExpression(a: any, b?: any, c = false) {\n  let str;\n  let self;\n  let thisRequired;\n  let logScope;\n  if (typeof a === 'object' && b === undefined) {\n    str = a.str;\n    self = a.self;\n    thisRequired = a.thisRequired;\n    logScope = a.logScope;\n  } else {\n    str = a;\n    self = b;\n    thisRequired = c;\n  }\n  try {\n    const contextArr = ['\"use strict\";', 'var __self = arguments[0];'];\n    contextArr.push('return ');\n    let tarStr: string;\n\n    tarStr = (str.value || '').trim();\n\n    // NOTE: use __self replace 'this' in the original function str\n    // may be wrong in extreme case which contains '__self' already\n    tarStr = tarStr.replace(/this(\\W|$)/g, (_a: any, b: any) => `__self${b}`);\n    tarStr = contextArr.join('\\n') + tarStr;\n\n    // 默认调用顶层窗口的parseObj, 保障new Function的window对象是顶层的window对象\n    if (inSameDomain() && (window.parent as any).__newFunc) {\n      return (window.parent as any).__newFunc(tarStr)(self);\n    }\n    const code = `with(${thisRequired ? '{}' : '$scope || {}'}) { ${tarStr} }`;\n    return new Function('$scope', code)(self);\n  } catch (err) {\n    logger.error(`${logScope || ''} parseExpression.error`, err, str, self?.__self ?? self);\n    return undefined;\n  }\n}\n\nexport {\n  parseExpression,\n};\n\nexport function parseThisRequiredExpression(str: any, self: any) {\n  return parseExpression(str, self, true);\n}\n\n/**\n * capitalize first letter\n * @param word string to be proccessed\n * @returns string capitalized string\n */\nexport function capitalizeFirstLetter(word: string) {\n  if (!word || !isString(word) || word.length === 0) {\n    return word;\n  }\n  return word[0].toUpperCase() + word.slice(1);\n}\n\n/**\n * check str passed in is a string type of not\n * @param str obj to be checked\n * @returns boolean\n */\nexport function isString(str: any): boolean {\n  return {}.toString.call(str) === '[object String]';\n}\n\n/**\n * check if obj is type of variable structure\n * @param obj object to be checked\n * @returns boolean\n */\nexport function isVariable(obj: any) {\n  if (!obj || Array.isArray(obj)) {\n    return false;\n  }\n  return typeof obj === 'object' && obj?.type === 'variable';\n}\n\n/**\n * 将 i18n 结构，降级解释为对 i18n 接口的调用\n * @param i18nInfo object\n * @param self context\n */\nexport function parseI18n(i18nInfo: any, self: any) {\n  return parseExpression({\n    type: EXPRESSION_TYPE.JSEXPRESSION,\n    value: `this.i18n('${i18nInfo.key}')`,\n  }, self);\n}\n\n/**\n * for each key in targetObj, run fn with the value of the value, and the context paased in.\n * @param targetObj object that keys will be for each\n * @param fn function that process each item\n * @param context\n */\nexport function forEach(targetObj: any, fn: any, context?: any) {\n  if (!targetObj || Array.isArray(targetObj) || isString(targetObj) || typeof targetObj !== 'object') {\n    return;\n  }\n\n  Object.keys(targetObj).forEach((key) => fn.call(context, targetObj[key], key));\n}\n\ninterface IParseOptions {\n  thisRequiredInJSE?: boolean;\n  logScope?: string;\n}\n\nexport function parseData(schema: unknown, self: any, options: IParseOptions = {}): any {\n  if (isJSExpression(schema)) {\n    return parseExpression({\n      str: schema,\n      self,\n      thisRequired: options.thisRequiredInJSE,\n      logScope: options.logScope,\n    });\n  } else if (isI18nData(schema)) {\n    return parseI18n(schema, self);\n  } else if (typeof schema === 'string') {\n    return schema.trim();\n  } else if (Array.isArray(schema)) {\n    return schema.map((item) => parseData(item, self, options));\n  } else if (typeof schema === 'function') {\n    return schema.bind(self);\n  } else if (typeof schema === 'object') {\n    // 对于undefined及null直接返回\n    if (!schema) {\n      return schema;\n    }\n    const res: any = {};\n    forEach(schema, (val: any, key: string) => {\n      if (key.startsWith('__')) {\n        return;\n      }\n      res[key] = parseData(val, self, options);\n    });\n    return res;\n  }\n  return schema;\n}\n\n/**\n * process params for using in a url query\n * @param obj params to be processed\n * @returns string\n */\nexport function serializeParams(obj: any) {\n  let result: any = [];\n  forEach(obj, (val: any, key: any) => {\n    if (val === null || val === undefined || val === '') {\n      return;\n    }\n    if (typeof val === 'object') {\n      result.push(`${key}=${encodeURIComponent(JSON.stringify(val))}`);\n    } else {\n      result.push(`${key}=${encodeURIComponent(val)}`);\n    }\n  });\n  return result.join('&');\n}\n"
  },
  {
    "path": "packages/renderer-core/src/utils/data-helper.ts",
    "content": "/* eslint-disable no-console */\n/* eslint-disable max-len */\n/* eslint-disable object-curly-newline */\nimport { isJSFunction } from '@alilc/lowcode-utils';\nimport { transformArrayToMap, transformStringToFunction } from './common';\nimport { jsonp, request, get, post } from './request';\nimport logger from './logger';\nimport { DataSource, DataSourceItem, IRendererAppHelper } from '../types';\n\nconst DS_STATUS = {\n  INIT: 'init',\n  LOADING: 'loading',\n  LOADED: 'loaded',\n  ERROR: 'error',\n};\n\ntype DataSourceType = 'fetch' | 'jsonp';\n\n/**\n * do request for standard DataSourceType\n * @param {DataSourceType} type type of DataSourceItem\n * @param {any} options\n */\nexport function doRequest(type: DataSourceType, options: any) {\n  // eslint-disable-next-line prefer-const\n  let { uri, url, method = 'GET', headers, params, ...otherProps } = options;\n  otherProps = otherProps || {};\n  if (type === 'jsonp') {\n    return jsonp(uri, params, otherProps);\n  }\n\n  if (type === 'fetch') {\n    switch (method.toUpperCase()) {\n      case 'GET':\n        return get(uri, params, headers, otherProps);\n      case 'POST':\n        return post(uri, params, headers, otherProps);\n      default:\n        return request(uri, method, params, headers, otherProps);\n    }\n  }\n\n  logger.log(`Engine default dataSource does not support type:[${type}] dataSource request!`, options);\n}\n\n// TODO: according to protocol, we should implement errorHandler/shouldFetch/willFetch/requestHandler and isSync controll.\nexport class DataHelper {\n  /**\n   * host object that will be \"this\" object when excuting dataHandler\n   *\n   * @type {*}\n   * @memberof DataHelper\n   */\n  host: any;\n\n  /**\n   * data source config\n   *\n   * @type {DataSource}\n   * @memberof DataHelper\n   */\n  config: DataSource;\n\n  /**\n   * a parser function which will be called to process config data\n   * which eventually will call common/utils.processData() to process data\n   * (originalConfig) => parsedConfig\n   * @type {*}\n   * @memberof DataHelper\n   */\n  parser: any;\n\n  /**\n   * config.list\n   *\n   * @type {any[]}\n   * @memberof DataHelper\n   */\n  ajaxList: any[];\n\n  ajaxMap: any;\n\n  dataSourceMap: any;\n\n  appHelper: IRendererAppHelper;\n\n  constructor(comp: any, config: DataSource, appHelper: IRendererAppHelper, parser: any) {\n    this.host = comp;\n    this.config = config || {};\n    this.parser = parser;\n    this.ajaxList = config?.list || [];\n    this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');\n    this.dataSourceMap = this.generateDataSourceMap();\n    this.appHelper = appHelper;\n  }\n\n  // 更新config，只会更新配置，状态保存；\n  updateConfig(config = {}) {\n    this.config = config as DataSource;\n    this.ajaxList = (config as DataSource)?.list || [];\n    const ajaxMap: any = transformArrayToMap(this.ajaxList, 'id');\n    // 删除已经移除的接口\n    Object.keys(this.ajaxMap).forEach((key) => {\n      if (!ajaxMap[key]) {\n        delete this.dataSourceMap[key];\n      }\n    });\n    this.ajaxMap = ajaxMap;\n    // 添加未加入到dataSourceMap中的接口\n    this.ajaxList.forEach((item) => {\n      if (!this.dataSourceMap[item.id]) {\n        this.dataSourceMap[item.id] = {\n          status: DS_STATUS.INIT,\n          load: (...args: any) => {\n            // @ts-ignore\n            return this.getDataSource(item.id, ...args);\n          },\n        };\n      }\n    });\n    return this.dataSourceMap;\n  }\n\n  generateDataSourceMap() {\n    const res: any = {};\n    this.ajaxList.forEach((item) => {\n      res[item.id] = {\n        status: DS_STATUS.INIT,\n        load: (...args: any) => {\n          // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n          // @ts-ignore\n          return this.getDataSource(item.id, ...args);\n        },\n      };\n    });\n    return res;\n  }\n\n  updateDataSourceMap(id: string, data: any, error: any) {\n    this.dataSourceMap[id].error = error || undefined;\n    this.dataSourceMap[id].data = data;\n    this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED;\n  }\n\n  /**\n   * get all dataSourceItems which marked as isInit === true\n   * @private\n   * @returns\n   * @memberof DataHelper\n   */\n  getInitDataSourseConfigs() {\n    const initConfigs = this.parser(this.ajaxList).filter((item: DataSourceItem) => {\n      // according to [spec](https://lowcode-engine.cn/lowcode), isInit should be boolean true to be working\n      if (item.isInit === true) {\n        this.dataSourceMap[item.id].status = DS_STATUS.LOADING;\n        return true;\n      }\n      return false;\n    });\n    return initConfigs;\n  }\n\n  /**\n   * process all dataSourceItems which marked as isInit === true, and get dataSource request results.\n   * @public\n   * @returns\n   * @memberof DataHelper\n   */\n  getInitData() {\n    const initSyncData = this.getInitDataSourseConfigs();\n    // 所有 datasource 的 datahandler\n    return this.asyncDataHandler(initSyncData).then((res) => {\n      const { dataHandler } = this.config;\n      return this.handleData(null, dataHandler, res, null);\n    });\n  }\n\n  getDataSource(id: string, params: any, otherOptions: any, callback: any) {\n    const req = this.parser(this.ajaxMap[id]);\n    const options = req.options || {};\n    let callbackFn = callback;\n    let otherOptionsObj = otherOptions;\n    if (typeof otherOptions === 'function') {\n      callbackFn = otherOptions;\n      otherOptionsObj = {};\n    }\n    const { headers, ...otherProps } = otherOptionsObj || {};\n    if (!req) {\n      logger.warn(`getDataSource API named ${id} not exist`);\n      return;\n    }\n\n    return this.asyncDataHandler([\n      {\n        ...req,\n        options: {\n          ...options,\n          // 支持参数为array的情况，当参数为array时，不做参数合并\n          params:\n            Array.isArray(options.params) || Array.isArray(params)\n              ? params || options.params\n              : {\n                ...options.params,\n                ...params,\n              },\n          headers: {\n            ...options.headers,\n            ...headers,\n          },\n          ...otherProps,\n        },\n      },\n    ])\n    .then((res: any) => {\n      try {\n        callbackFn && callbackFn(res && res[id]);\n      } catch (e) {\n        logger.error('load请求回调函数报错', e);\n      }\n      return res && res[id];\n    })\n    .catch((err) => {\n      try {\n        callbackFn && callbackFn(null, err);\n      } catch (e) {\n        logger.error('load请求回调函数报错', e);\n      }\n      return err;\n    });\n  }\n\n  asyncDataHandler(asyncDataList: any[]) {\n    return new Promise((resolve, reject) => {\n      const allReq: any[] = [];\n      asyncDataList.forEach((req) => {\n        const { id, type } = req;\n        // TODO: need refactoring to remove 'legao' related logic\n        if (!id || !type || type === 'legao') {\n          return;\n        }\n        allReq.push(req);\n      });\n\n      if (allReq.length === 0) {\n        resolve({});\n      }\n      const res: any = {};\n      Promise.all(\n        allReq.map((item: any) => {\n          return new Promise((innerResolve) => {\n            const { type, id, dataHandler, options } = item;\n\n            const fetchHandler = (data: any, error: any) => {\n              res[id] = this.handleData(id, dataHandler, data, error);\n              this.updateDataSourceMap(id, res[id], error);\n              innerResolve({});\n            };\n\n            const doFetch = (innerType: string, innerOptions: any) => {\n              doRequest(innerType as any, innerOptions)\n                ?.then((data: any) => {\n                  fetchHandler(data, undefined);\n                })\n                .catch((err: Error) => {\n                  fetchHandler(undefined, err);\n                });\n            };\n\n            this.dataSourceMap[id].status = DS_STATUS.LOADING;\n            doFetch(type, options);\n          });\n        }),\n      ).then(() => {\n        resolve(res);\n      }).catch((e) => {\n        reject(e);\n      });\n    });\n  }\n\n  /**\n   * process data using dataHandler\n   *\n   * @param {(string | null)} id request id, will be used in error message, can be null\n   * @param {*} dataHandler\n   * @param {*} data\n   * @param {*} error\n   * @returns\n   * @memberof DataHelper\n   */\n  handleData(id: string | null, dataHandler: any, data: any, error: any) {\n    let dataHandlerFun = dataHandler;\n    if (isJSFunction(dataHandler)) {\n      dataHandlerFun = transformStringToFunction(dataHandler.value);\n    }\n    if (!dataHandlerFun || typeof dataHandlerFun !== 'function') {\n      return data;\n    }\n    try {\n      return dataHandlerFun.call(this.host, data, error);\n    } catch (e) {\n      if (id) {\n        logger.error(`[${id}]单个请求数据处理函数运行出错`, e);\n      } else {\n        logger.error('请求数据处理函数运行出错', e);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/renderer-core/src/utils/index.ts",
    "content": "export * from './common';\nexport * from './data-helper';\nexport * from './request';\n"
  },
  {
    "path": "packages/renderer-core/src/utils/is-use-loop.ts",
    "content": "import { IPublicTypeJSExpression } from '@alilc/lowcode-types';\nimport { isJSExpression } from '@alilc/lowcode-utils';\n\n// 1.渲染模式下，loop 是数组，则按照数组长度渲染组件\n// 2.设计模式下，loop 需要长度大于 0，按照循环模式渲染，防止无法设计的情况\nexport default function isUseLoop(loop: null | any[] | IPublicTypeJSExpression, isDesignMode: boolean): boolean {\n  if (isJSExpression(loop)) {\n    return true;\n  }\n\n  if (!isDesignMode) {\n    return true;\n  }\n\n  if (!Array.isArray(loop)) {\n    return false;\n  }\n\n  return loop.length > 0;\n}\n"
  },
  {
    "path": "packages/renderer-core/src/utils/logger.ts",
    "content": "import { Logger } from '@alilc/lowcode-utils';\n\nexport default new Logger({ level: 'warn', bizName: 'renderer' });"
  },
  {
    "path": "packages/renderer-core/src/utils/request.ts",
    "content": "import 'whatwg-fetch';\nimport fetchJsonp from 'fetch-jsonp';\nimport { serializeParams } from '.';\n\n/**\n * this is a private method, export for testing purposes only.\n *\n * @export\n * @param {*} dataAPI\n * @param {*} params\n * @returns\n */\nexport function buildUrl(dataAPI: any, params: any) {\n  const paramStr = serializeParams(params);\n  if (paramStr) {\n    return dataAPI.indexOf('?') > 0 ? `${dataAPI}&${paramStr}` : `${dataAPI}?${paramStr}`;\n  }\n  return dataAPI;\n}\n\n/**\n * do Get request\n *\n * @export\n * @param {*} dataAPI\n * @param {*} [params={}]\n * @param {*} [headers={}]\n * @param {*} [otherProps={}]\n * @returns\n */\n export function get(dataAPI: any, params = {}, headers = {}, otherProps = {}) {\n  const processedHeaders = {\n    Accept: 'application/json',\n    ...headers,\n  };\n  const url = buildUrl(dataAPI, params);\n  return request(url, 'GET', null, processedHeaders, otherProps);\n}\n\n/**\n * do Post request\n *\n * @export\n * @param {*} dataAPI\n * @param {*} [params={}]\n * @param {*} [headers={}]\n * @param {*} [otherProps={}]\n * @returns\n */\nexport function post(dataAPI: any, params = {}, headers: any = {}, otherProps = {}) {\n  const processedHeaders = {\n    Accept: 'application/json',\n    'Content-Type': 'application/x-www-form-urlencoded',\n    ...headers,\n  };\n  const body = processedHeaders['Content-Type'].indexOf('application/json') > -1 || Array.isArray(params)\n  ? JSON.stringify(params)\n  : serializeParams(params);\n\n  return request(\n    dataAPI,\n    'POST',\n    body,\n    processedHeaders,\n    otherProps,\n  );\n}\n\n/**\n * do request\n *\n * @export\n * @param {*} dataAPI\n * @param {string} [method='GET']\n * @param {*} data\n * @param {*} [headers={}]\n * @param {*} [otherProps={}]\n * @returns\n */\nexport function request(dataAPI: any, method = 'GET', data: any, headers = {}, otherProps: any = {}) {\n  let processedHeaders = headers || {};\n  let payload = data;\n  if (method === 'PUT' || method === 'DELETE') {\n    processedHeaders = {\n      Accept: 'application/json',\n      'Content-Type': 'application/json',\n      ...processedHeaders,\n    };\n    payload = JSON.stringify(payload || {});\n  }\n  return new Promise((resolve, reject) => {\n    if (otherProps.timeout) {\n      setTimeout(() => {\n        reject(new Error('timeout'));\n      }, otherProps.timeout);\n    }\n    fetch(dataAPI, {\n      method,\n      credentials: 'include',\n      headers: processedHeaders,\n      body: payload,\n      ...otherProps,\n    })\n      .then((response) => {\n        switch (response.status) {\n          case 200:\n          case 201:\n          case 202:\n            return response.json();\n          case 204:\n            if (method === 'DELETE') {\n              return {\n                success: true,\n              };\n            } else {\n              return {\n                __success: false,\n                code: response.status,\n              };\n            }\n          case 400:\n          case 401:\n          case 403:\n          case 404:\n          case 406:\n          case 410:\n          case 422:\n          case 500:\n            return response\n              .json()\n              .then((res) => {\n                return {\n                  __success: false,\n                  code: response.status,\n                  data: res,\n                };\n              })\n              .catch(() => {\n                return {\n                  __success: false,\n                  code: response.status,\n                };\n              });\n          default:\n        }\n        return null;\n      })\n      .then((json) => {\n        if (!json) {\n          reject(json);\n          return;\n        }\n        if (json.__success !== false) {\n          resolve(json);\n        } else {\n          // eslint-disable-next-line no-param-reassign\n          delete json.__success;\n          reject(json);\n        }\n      })\n      .catch((err) => {\n        reject(err);\n      });\n  });\n}\n\n/**\n * do jsonp request\n *\n * @export\n * @param {*} dataAPI\n * @param {*} [params={}]\n * @param {*} [otherProps={}]\n * @returns\n */\nexport function jsonp(dataAPI: any, params = {}, otherProps = {}) {\n  return new Promise((resolve, reject) => {\n    const processedOtherProps = {\n      timeout: 5000,\n      ...otherProps,\n    };\n    const url = buildUrl(dataAPI, params);\n    fetchJsonp(url, processedOtherProps)\n      .then((response) => {\n        response.json();\n      })\n      .then((json) => {\n        if (json) {\n          resolve(json);\n        } else {\n          reject();\n        }\n      })\n      .catch((err) => {\n        reject(err);\n      });\n  });\n}\n"
  },
  {
    "path": "packages/renderer-core/tests/adapter/adapter.test.ts",
    "content": "// @ts-nocheck\nimport adapter, { Env } from '../../src/adapter';\n\n\n\ndescribe('test src/adapter ', () => {\n  \n  it('adapter basic use works', () => {\n    expect(adapter).toBeTruthy();\n\n  });\n  \n  it('isValidRuntime works', () => {\n    expect(adapter.isValidRuntime([] as any)).toBeFalsy();\n\n    expect(adapter.isValidRuntime('' as any)).toBeFalsy();\n\n    let invalidRuntime = {};\n    expect(() => adapter.isValidRuntime(invalidRuntime as any)).toThrowError(/Component/);\n    invalidRuntime = {\n      Component: {},\n    };\n    expect(() => adapter.isValidRuntime(invalidRuntime as any)).toThrowError(/PureComponent/);\n    invalidRuntime = {\n      Component: {},\n      PureComponent: {},\n    };\n    expect(() => adapter.isValidRuntime(invalidRuntime as any)).toThrowError(/createElement/);\n    invalidRuntime = {\n      Component: {},\n      PureComponent: {},\n      createElement: {},\n    };\n    expect(() => adapter.isValidRuntime(invalidRuntime as any)).toThrowError(/createContext/);\n    invalidRuntime = {\n      Component: {},\n      PureComponent: {},\n      createElement: {},\n      createContext: {},\n    };\n    expect(() => adapter.isValidRuntime(invalidRuntime as any)).toThrowError(/forwardRef/);\n    invalidRuntime = {\n      Component: {},\n      PureComponent: {},\n      createElement: {},\n      createContext: {},\n      forwardRef: {},\n    };\n    expect(() => adapter.isValidRuntime(invalidRuntime as any)).toThrowError(/findDOMNode/);\n    const validRuntime = {\n      Component: {},\n      PureComponent: {},\n      createElement: {},\n      createContext: {},\n      forwardRef: {},\n      findDOMNode: {},\n    };\n\n    expect(adapter.isValidRuntime(validRuntime as any)).toBeTruthy();\n  });\n\n  it('setRuntime/getRuntime works', () => {\n    const validRuntime = {\n      Component: {},\n      PureComponent: {},\n      createElement: {},\n      createContext: {},\n      forwardRef: {},\n      findDOMNode: {},\n    };\n\n    adapter.setRuntime(validRuntime as any);\n    expect(adapter.getRuntime()).toBe(validRuntime);\n\n    // won`t work when invalid runtime paased in. \n    adapter.setRuntime([] as any);\n    expect(adapter.getRuntime()).toBe(validRuntime);\n\n\n  });\n\n  it('setEnv/.env/isReact works', () => {\n    adapter.setEnv(Env.React);\n    expect(adapter.env).toBe(Env.React);\n    expect(adapter.isReact()).toBeTruthy();\n  });\n\n  it('setRenderers/getRenderers works', () => {\n    const mockRenderers = { BaseRenderer: {} as IBaseRenderComponent};\n    adapter.setRenderers(mockRenderers);\n    expect(adapter.getRenderers()).toBe(mockRenderers);\n    adapter.setRenderers(undefined);\n    expect(adapter.getRenderers()).toStrictEqual({});\n  });\n\n  it('setConfigProvider/getConfigProvider works', () => {\n    const mockConfigProvider = { a: 111 };\n    adapter.setConfigProvider(mockConfigProvider);\n    expect(adapter.getConfigProvider()).toBe(mockConfigProvider);\n  });\n});"
  },
  {
    "path": "packages/renderer-core/tests/fixtures/schema/basic.ts",
    "content": "export default {\n  componentName: 'Page',\n  id: 'node_dockcviv8fo1',\n  props: {\n    ref: 'outterView',\n    autoLoading: true,\n    style: {\n      padding: '0 5px 0 5px',\n    },\n  },\n  fileName: 'test',\n  dataSource: {\n    list: [],\n  },\n  state: {\n    text: 'outter',\n    isShowDialog: false,\n  },\n  css: 'body {font-size: 12px;} .botton{width:100px;color:#ff00ff}',\n  lifeCycles: {\n    componentDidMount: {\n      type: 'JSFunction',\n      value: \"function() {\\n    console.log('did mount');\\n  }\",\n    },\n    componentWillUnmount: {\n      type: 'JSFunction',\n      value: \"function() {\\n    console.log('will umount');\\n  }\",\n    },\n  },\n  methods: {\n    testFunc: {\n      type: 'JSFunction',\n      value: \"function() {\\n    console.log('test func');\\n  }\",\n    },\n    onClick: {\n      type: 'JSFunction',\n      value: 'function() {\\n    this.setState({\\n      isShowDialog: true\\n    })\\n  }',\n    },\n    closeDialog: {\n      type: 'JSFunction',\n      value: 'function() {\\n    this.setState({\\n      isShowDialog: false\\n    })\\n  }',\n    },\n  },\n  children: [\n    {\n      componentName: 'Box',\n      id: 'node_dockcy8n9xed',\n      props: {\n        style: {\n          backgroundColor: 'rgba(31,56,88,0.1)',\n          padding: '12px 12px 12px 12px',\n        },\n      },\n      children: [\n        {\n          componentName: 'Box',\n          id: 'node_dockcy8n9xee',\n          props: {\n            style: {\n              padding: '12px 12px 12px 12px',\n              backgroundColor: '#ffffff',\n            },\n          },\n          children: [\n            {\n              componentName: 'Breadcrumb',\n              id: 'node_dockcy8n9xef',\n              props: {\n                prefix: 'next-',\n                maxNode: 100,\n                component: 'nav',\n              },\n              children: [\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xeg',\n                  props: {\n                    prefix: 'next-',\n                    children: '首页',\n                  },\n                },\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xei',\n                  props: {\n                    prefix: 'next-',\n                    children: '品质中台',\n                  },\n                },\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xek',\n                  props: {\n                    prefix: 'next-',\n                    children: '商家品质页面管理',\n                  },\n                },\n                {\n                  componentName: 'Breadcrumb.Item',\n                  id: 'node_dockcy8n9xem',\n                  props: {\n                    prefix: 'next-',\n                    children: '质检知识条配置',\n                  },\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'Box',\n          id: 'node_dockcy8n9xeo',\n          props: {\n            style: {\n              marginTop: '12px',\n              backgroundColor: '#ffffff',\n            },\n          },\n          children: [\n            {\n              componentName: 'Form',\n              id: 'node_dockcy8n9xep',\n              props: {\n                inline: true,\n                style: {\n                  marginTop: '12px',\n                  marginRight: '12px',\n                  marginLeft: '12px',\n                },\n                __events: [],\n              },\n              children: [\n                {\n                  componentName: 'Form.Item',\n                  id: 'node_dockcy8n9xeq',\n                  props: {\n                    style: {\n                      marginBottom: '0',\n                    },\n                    label: '类目名：',\n                  },\n                  children: [\n                    {\n                      componentName: 'Select',\n                      id: 'node_dockcy8n9xer',\n                      props: {\n                        mode: 'single',\n                        hasArrow: true,\n                        cacheValue: true,\n                        style: {\n                          width: '150px',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Form.Item',\n                  id: 'node_dockcy8n9xes',\n                  props: {\n                    style: {\n                      marginBottom: '0',\n                    },\n                    label: '项目类型：',\n                  },\n                  children: [\n                    {\n                      componentName: 'Select',\n                      id: 'node_dockcy8n9xet',\n                      props: {\n                        mode: 'single',\n                        hasArrow: true,\n                        cacheValue: true,\n                        style: {\n                          width: '200px',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Form.Item',\n                  id: 'node_dockcy8n9xeu',\n                  props: {\n                    style: {\n                      marginBottom: '0',\n                    },\n                    label: '项目 ID：',\n                  },\n                  children: [\n                    {\n                      componentName: 'Input',\n                      id: 'node_dockcy8n9xev',\n                      props: {\n                        hasBorder: true,\n                        size: 'medium',\n                        autoComplete: 'off',\n                        style: {\n                          width: '200px',\n                        },\n                      },\n                    },\n                  ],\n                },\n                {\n                  componentName: 'Button.Group',\n                  id: 'node_dockcy8n9xew',\n                  props: {},\n                  children: [\n                    {\n                      componentName: 'Button',\n                      id: 'node_dockcy8n9xex',\n                      props: {\n                        type: 'primary',\n                        style: {\n                          margin: '0 5px 0 5px',\n                        },\n                        htmlType: 'submit',\n                        children: '搜索',\n                      },\n                    },\n                    {\n                      componentName: 'Button',\n                      id: 'node_dockcy8n9xe10',\n                      props: {\n                        type: 'normal',\n                        style: {\n                          margin: '0 5px 0 5px',\n                        },\n                        htmlType: 'reset',\n                        children: '清空',\n                      },\n                    },\n                  ],\n                },\n              ],\n            },\n          ],\n        },\n        {\n          componentName: 'Box',\n          id: 'node_dockcy8n9xe1f',\n          props: {\n            style: {\n              backgroundColor: '#ffffff',\n              paddingBottom: '24px',\n              display: 'flex',\n              flexDirection: 'row',\n              justifyContent: 'flex-end',\n            },\n          },\n          children: [\n            {\n              componentName: 'Button',\n              id: 'node_dockd5nrh9p4',\n              props: {\n                type: 'primary',\n                size: 'medium',\n                htmlType: 'button',\n                component: 'button',\n                children: '新建配置',\n                style: {},\n                __events: [\n                  {\n                    type: 'componentEvent',\n                    name: 'onClick',\n                    relatedEventName: 'onClick',\n                  },\n                ],\n                onClick: {\n                  type: 'JSFunction',\n                  value: 'function(){ this.onClick() }',\n                },\n              },\n            },\n          ],\n        },\n        {\n          componentName: 'Box',\n          id: 'node_dockd5nrh9p5',\n          props: {},\n          children: [\n            {\n              componentName: 'Table',\n              id: 'node_dockjielosj1',\n              props: {\n                showMiniPager: true,\n                showActionBar: true,\n                actionBar: [\n                  {\n                    title: '新增',\n                    type: 'primary',\n                  },\n                  {\n                    title: '编辑',\n                  },\n                ],\n                columns: [\n                  {\n                    dataKey: 'name',\n                    width: 200,\n                    align: 'center',\n                    title: '姓名',\n                    editType: 'text',\n                  },\n                  {\n                    dataKey: 'age',\n                    width: 200,\n                    align: 'center',\n                    title: '年龄',\n                  },\n                  {\n                    dataKey: 'email',\n                    width: 200,\n                    align: 'center',\n                    title: '邮箱',\n                  },\n                ],\n                data: [\n                  {\n                    name: '王小',\n                    id: '1',\n                    age: 15000,\n                    email: 'aaa@abc.com',\n                  },\n                  {\n                    name: '王中',\n                    id: '2',\n                    age: 25000,\n                    email: 'bbb@abc.com',\n                  },\n                  {\n                    name: '王大',\n                    id: '3',\n                    age: 35000,\n                    email: 'ccc@abc.com',\n                  },\n                ],\n                actionTitle: '操作',\n                actionWidth: 180,\n                actionType: 'link',\n                actionFixed: 'right',\n                actionHidden: false,\n                maxWebShownActionCount: 2,\n                actionColumn: [\n                  {\n                    title: '编辑',\n                    callback: {\n                      type: 'JSFunction',\n                      value: '(rowData, action, table) => {\\n return table.editRow(rowData).then((row) => {\\n console.log(row);\\n });\\n }',\n                    },\n                    device: [\n                      'desktop',\n                    ],\n                  },\n                  {\n                    title: '保存',\n                    callback: {\n                      type: 'JSFunction',\n                      value: '(rowData, action, table) => { \\nreturn table.saveRow(rowData).then((row) => { \\nconsole.log(row); \\n}); \\n}',\n                    },\n                    mode: 'EDIT',\n                  },\n                ],\n              },\n            },\n            {\n              componentName: 'Box',\n              id: 'node_dockd5nrh9pg',\n              props: {\n                style: {\n                  display: 'flex',\n                  flexDirection: 'row',\n                  justifyContent: 'flex-end',\n                },\n              },\n              children: [\n                {\n                  componentName: 'Pagination',\n                  id: 'node_dockd5nrh9pf',\n                  props: {\n                    prefix: 'next-',\n                    type: 'normal',\n                    shape: 'normal',\n                    size: 'medium',\n                    defaultCurrent: 1,\n                    total: 100,\n                    pageShowCount: 5,\n                    pageSize: 10,\n                    pageSizePosition: 'start',\n                    showJump: true,\n                    style: {},\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'Dialog',\n      id: 'node_dockcy8n9xe1h',\n      props: {\n        prefix: 'next-',\n        footerAlign: 'right',\n        footerActions: [\n          'ok',\n          'cancel',\n        ],\n        closeable: 'esc,close',\n        hasMask: true,\n        align: 'cc cc',\n        minMargin: 40,\n        visible: {\n          type: 'JSExpression',\n          value: 'this.state.isShowDialog',\n        },\n        title: '标题',\n        events: [],\n        __events: [\n          {\n            type: 'componentEvent',\n            name: 'onCancel',\n            relatedEventName: 'closeDialog',\n          },\n          {\n            type: 'componentEvent',\n            name: 'onClose',\n            relatedEventName: 'closeDialog',\n          },\n          {\n            type: 'componentEvent',\n            name: 'onOk',\n            relatedEventName: 'testFunc',\n          },\n        ],\n        onCancel: {\n          type: 'JSFunction',\n          value: 'function(){ this.closeDialog() }',\n        },\n        onClose: {\n          type: 'JSFunction',\n          value: 'function(){ this.closeDialog() }',\n        },\n        onOk: {\n          type: 'JSFunction',\n          value: 'function(){ this.testFunc() }',\n        },\n      },\n      children: [\n        {\n          componentName: 'Form',\n          id: 'node_dockd5nrh9pi',\n          props: {\n            inline: false,\n            labelAlign: 'top',\n            labelTextAlign: 'right',\n            size: 'medium',\n          },\n          children: [\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pj',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node_dockd5nrh9pk',\n                  props: {\n                    mode: 'single',\n                    hasArrow: true,\n                    cacheValue: true,\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pl',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node_dockd5nrh9pm',\n                  props: {\n                    mode: 'single',\n                    hasArrow: true,\n                    cacheValue: true,\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pn',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n                asterisk: true,\n              },\n              children: [\n                {\n                  componentName: 'Select',\n                  id: 'node_dockd5nrh9po',\n                  props: {\n                    mode: 'single',\n                    hasArrow: true,\n                    cacheValue: true,\n                  },\n                },\n              ],\n            },\n            {\n              componentName: 'Form.Item',\n              id: 'node_dockd5nrh9pp',\n              props: {\n                style: {\n                  marginBottom: '0',\n                  minWidth: '200px',\n                  minHeight: '28px',\n                },\n                label: '商品类目',\n              },\n              children: [\n                {\n                  componentName: 'Input',\n                  id: 'node_dockd5nrh9pr',\n                  props: {\n                    hasBorder: true,\n                    size: 'medium',\n                    autoComplete: 'off',\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      ],\n    },\n    {\n      componentName: 'ErrorComponent',\n      id: 'node_dockd5nrh9pr',\n      props: {\n        name: 'error',\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/renderer-core/tests/fixtures/unhandled-rejection.ts",
    "content": "if (!process.env.LISTENING_TO_UNHANDLED_REJECTION) {\n  process.on('unhandledRejection', reason => {\n    throw reason;\n  });\n  // Avoid memory leak by adding too many listeners\n  process.env.LISTENING_TO_UNHANDLED_REJECTION = 'true';\n}\n"
  },
  {
    "path": "packages/renderer-core/tests/hoc/__snapshots__/leaf.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`children this.props.children is array 1`] = `\n<div>\n  <div\n    content=\"content\"\n  >\n    content\n  </div>\n  <div\n    content=\"content\"\n  >\n    content\n  </div>\n</div>\n`;\n\nexports[`lifecycle leaf change and make componentWillReceiveProps 1`] = `\n<div>\n  <div\n    __id=\"text6\"\n    __tag=\"222\"\n    componentId=\"text6\"\n    content=\"content new leaf\"\n  >\n    content new leaf\n  </div>\n</div>\n`;\n\nexports[`lifecycle props change and make componentWillReceiveProps 1`] = `\n<div>\n  <div\n    content=\"content\"\n  >\n    content\n  </div>\n</div>\n`;\n\nexports[`lifecycle props change and make componentWillReceiveProps 2`] = `\n<div>\n  <div\n    content=\"content 123\"\n  >\n    content 123\n  </div>\n</div>\n`;\n\nexports[`lifecycle props change and make componentWillReceiveProps 3`] = `\n<div>\n  <div\n    __tag=\"111\"\n    content=\"content 123\"\n  >\n    content 123\n  </div>\n</div>\n`;\n\nexports[`mini unit render leaf has a loop, render from parent 1`] = `\n<div>\n  this is a new children\n</div>\n`;\n\nexports[`mini unit render make text props change 1`] = `\n<div>\n  <div\n    content=\"content\"\n  >\n    content\n  </div>\n</div>\n`;\n\nexports[`mini unit render make text props change 2`] = `\n<div\n  newPropKey=\"newPropValue\"\n/>\n`;\n\nexports[`mini unit render parent is a mock leaf 1`] = `\n<div>\n  <div\n    content=\"new content to mock\"\n  >\n    new content to mock\n  </div>\n</div>\n`;\n\nexports[`mini unit render props has new children 1`] = `\n<div>\n  children 01\n  children 02\n</div>\n`;\n\nexports[`onChildrenChange children is array string 1`] = `\n<div>\n  onChildrenChange content 01\n  onChildrenChange content 02\n</div>\n`;\n\nexports[`onPropChange change textNode [key:___condition___] props, but not hidden component 1`] = `\n<div>\n  <div\n    content=\"content\"\n  >\n    content\n  </div>\n</div>\n`;\n\nexports[`onPropChange change textNode [key:___condition___] props, hide textNode component 1`] = `<div />`;\n\nexports[`onPropChange change textNode [key:content], content in this.props but not in leaf.export result 1`] = `\n<div>\n  <div\n    content=\"content\"\n  >\n    content\n  </div>\n</div>\n`;\n\nexports[`onPropChange change textNode [key:content], content in this.props but not in leaf.export result 2`] = `\n<div>\n  <div\n    content={null}\n  />\n</div>\n`;\n\nexports[`onVisibleChange visible is false 1`] = `<div />`;\n\nexports[`onVisibleChange visible is true 1`] = `\n<div>\n  <div\n    content=\"content\"\n  >\n    content\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/renderer-core/tests/hoc/leaf.test.tsx",
    "content": "import renderer from 'react-test-renderer';\nimport React from 'react';\nimport { createElement } from 'react';\nimport '../utils/react-env-init';\nimport { leafWrapper } from '../../src/hoc/leaf';\nimport components from '../utils/components';\nimport Node from '../utils/node';\nimport { parseData } from '../../src/utils';\n\nlet rerenderCount = 0;\n\nconst nodeMap = new Map();\n\nconst makeSnapshot = (component) => {\n  let tree = component.toJSON();\n  expect(tree).toMatchSnapshot();\n}\n\nconst baseRenderer: any = {\n  __debug () {},\n  __getComponentProps (schema: any) {\n    return schema.props;\n  },\n  __getSchemaChildrenVirtualDom (schema: any) {\n    return schema.children;\n  },\n  context: {\n    engine: {\n      createElement,\n    }\n  },\n  props: {\n    __host: {},\n    getNode: (id) => nodeMap.get(id),\n    __container: {\n      rerender: () => {\n        rerenderCount = 1 + rerenderCount;\n      },\n      autoRepaintNode: true,\n    },\n    documentId: '01'\n  },\n  __parseData (data, scope) {\n    return parseData(data, scope, {});\n  }\n}\n\nlet Div, DivNode, Text, TextNode, component, textSchema, divSchema;\nlet id = 0;\n\nbeforeEach(() => {\n  textSchema = {\n    id: 'text' + id,\n    props: {\n      content: 'content'\n    },\n  };\n\n  divSchema = {\n    id: 'div' + id,\n  };\n\n  id++;\n\n  Div = leafWrapper(components.Div as any, {\n    schema: divSchema,\n    baseRenderer,\n    componentInfo: {},\n    scope: {},\n  });\n\n  DivNode = new Node(divSchema);\n  TextNode = new Node(textSchema);\n\n  nodeMap.set(divSchema.id, DivNode);\n  nodeMap.set(textSchema.id, TextNode);\n\n  Text = leafWrapper(components.Text as any, {\n    schema: textSchema,\n    baseRenderer,\n    componentInfo: {},\n    scope: {},\n  });\n\n  component = renderer.create(\n    <Div _leaf={DivNode}>\n      <Text _leaf={TextNode} content=\"content\"></Text>\n    </Div>\n  );\n});\n\nafterEach(() => {\n  component.unmount(component);\n});\n\ndescribe('onPropChange', () => {\n  it('change textNode [key:content] props', () => {\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'new content',\n    } as any);\n\n    const root = component.root;\n    expect(root.findByType(components.Text).props.content).toEqual('new content')\n  });\n\n  it('change textNode [key:___condition___] props, hide textNode component', () => {\n    // mock leaf?.export result\n    TextNode.schema.condition = false;\n    TextNode.emitPropChange({\n      key: '___condition___',\n      newValue: false,\n    } as any);\n\n    makeSnapshot(component);\n  });\n\n  it('change textNode [key:___condition___] props, but not hidden component', () => {\n    TextNode.schema.condition = true;\n    TextNode.emitPropChange({\n      key: '___condition___',\n      newValue: false,\n    } as any);\n\n    makeSnapshot(component);\n  });\n\n  it('change textNode [key:content], content in this.props but not in leaf.export result', () => {\n    makeSnapshot(component);\n\n    delete TextNode.schema.props.content;\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: null,\n    } as any, true);\n\n    makeSnapshot(component);\n\n    const root = component.root;\n\n    const TextInst = root.findByType(components.Text);\n\n    expect(TextInst.props.content).toBeNull();\n  });\n\n  it('change textNode [key:___loop___], make rerender', () => {\n    expect(leafWrapper(components.Text as any, {\n      schema: textSchema,\n      baseRenderer,\n      componentInfo: {},\n      scope: {},\n    })).toEqual(Text);\n\n    const nextRerenderCount = rerenderCount + 1;\n\n    TextNode.emitPropChange({\n      key: '___loop___',\n      newValue: 'new content',\n    } as any);\n\n    expect(rerenderCount).toBe(nextRerenderCount);\n    expect(leafWrapper(components.Text as any, {\n      schema: textSchema,\n      baseRenderer,\n      componentInfo: {},\n      scope: {},\n    })).not.toEqual(Text);\n  });\n});\n\ndescribe('lifecycle', () => {\n  it('props change and make componentWillReceiveProps', () => {\n    makeSnapshot(component);\n\n    // 没有 __tag 标识\n    component.update((\n      <Div _leaf={DivNode}>\n        <Text _leaf={TextNode} content=\"content 123\"></Text>\n      </Div>\n    ));\n\n    makeSnapshot(component);\n\n    // 有 __tag 标识\n    component.update((\n      <Div _leaf={DivNode}>\n        <Text _leaf={TextNode} __tag=\"111\" content=\"content 123\"></Text>\n      </Div>\n    ));\n\n    makeSnapshot(component);\n  });\n\n  it('leaf change and make componentWillReceiveProps', () => {\n    const newTextNodeLeaf = new Node(textSchema);\n    nodeMap.set(textSchema.id, newTextNodeLeaf);\n    component.update((\n      <Div _leaf={DivNode}>\n        <Text componentId={textSchema.id} __tag=\"222\" content=\"content 123\"></Text>\n      </Div>\n    ));\n\n    newTextNodeLeaf.emitPropChange({\n      key: 'content',\n      newValue: 'content new leaf',\n    });\n\n    makeSnapshot(component);\n  });\n});\n\ndescribe('mini unit render', () => {\n  let miniRenderSchema, MiniRenderDiv, MiniRenderDivNode;\n  beforeEach(() => {\n    miniRenderSchema = {\n      id: 'miniDiv' + id,\n    };\n\n    MiniRenderDiv = leafWrapper(components.MiniRenderDiv as any, {\n      schema: miniRenderSchema,\n      baseRenderer,\n      componentInfo: {},\n      scope: {},\n    });\n\n    MiniRenderDivNode = new Node(miniRenderSchema, {\n      componentMeta: {\n        isMinimalRenderUnit: true,\n      },\n    });\n\n    TextNode = new Node(textSchema, {\n      parent: MiniRenderDivNode,\n    });\n\n    nodeMap.set(miniRenderSchema.id, MiniRenderDivNode);\n    nodeMap.set(textSchema.id, TextNode);\n\n    component = renderer.create(\n      <MiniRenderDiv _leaf={MiniRenderDivNode}>\n        <Text _leaf={TextNode} content=\"content\"></Text>\n      </MiniRenderDiv>\n    );\n  })\n\n  it('make text props change', () => {\n    if (!MiniRenderDivNode.schema.props) {\n      MiniRenderDivNode.schema.props = {};\n    }\n    MiniRenderDivNode.schema.props['newPropKey'] = 'newPropValue';\n\n    makeSnapshot(component);\n\n    const inst = component.root;\n\n    const TextInst = inst.findByType(Text).children[0];\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'new content',\n    } as any);\n\n    expect((TextInst as any)?._fiber.stateNode.renderUnitInfo).toEqual({\n      singleRender: false,\n      minimalUnitId: 'miniDiv' + id,\n      minimalUnitName: undefined,\n    });\n\n    makeSnapshot(component);\n  });\n\n  it('dont render mini render component', () => {\n    const TextNode = new Node(textSchema, {\n      parent: new Node({\n        id: 'random',\n      }, {\n        componentMeta: {\n          isMinimalRenderUnit: true,\n        },\n      }),\n    });\n\n    nodeMap.set(textSchema.id, TextNode);\n\n    renderer.create(\n      <div>\n        <Text _leaf={TextNode} content=\"content\"></Text>\n      </div>\n    );\n\n    const nextCount = rerenderCount + 1;\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'new content',\n    } as any);\n\n    expect(rerenderCount).toBe(nextCount);\n  });\n\n  it('leaf is a mock function', () => {\n    const TextNode = new Node(textSchema, {\n      parent: {\n        isEmpty: () => false,\n      }\n    });\n\n    renderer.create(\n      <div>\n        <Text _leaf={TextNode} content=\"content\"></Text>\n      </div>\n    );\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'new content',\n    } as any);\n  });\n\n  it('change component leaf isRoot is true', () => {\n    const TextNode = new Node(textSchema, {\n      isRoot: true,\n      isRootNode: true,\n    });\n\n    nodeMap.set(textSchema.id, TextNode);\n\n    const component = renderer.create(\n      <Text _leaf={TextNode} content=\"content\"></Text>\n    );\n\n    const inst = component.root;\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'new content',\n    } as any);\n\n    expect((inst.children[0] as any)?._fiber.stateNode.renderUnitInfo).toEqual({\n      singleRender: true,\n    });\n  });\n\n  it('change component leaf parent isRoot is true', () => {\n    const TextNode = new Node(textSchema, {\n      parent: new Node({\n        id: 'first-parent',\n      }, {\n        componentMeta: {\n          isMinimalRenderUnit: true,\n        },\n        parent: new Node({\n          id: 'rootId',\n        }, {\n          isRoot: true,\n          isRootNode: true\n        }),\n      })\n    });\n\n    nodeMap.set(textSchema.id, TextNode);\n\n    const component = renderer.create(\n      <Text _leaf={TextNode} content=\"content\"></Text>\n    );\n\n    const inst = component.root;\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'new content',\n    } as any);\n\n    expect((inst.children[0] as any)?._fiber.stateNode.renderUnitInfo).toEqual({\n      singleRender: false,\n      minimalUnitId: 'first-parent',\n      minimalUnitName: undefined,\n    });\n  });\n\n  it('parent is a mock leaf', () => {\n    const MiniRenderDivNode = {\n      isMock: true,\n    };\n\n    const component = renderer.create(\n      <MiniRenderDiv _leaf={MiniRenderDivNode}>\n        <Text _leaf={TextNode} content=\"content\"></Text>\n      </MiniRenderDiv>\n    );\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'new content to mock',\n    } as any);\n\n    makeSnapshot(component);\n  });\n\n  it('props has new children', () => {\n    MiniRenderDivNode.schema.props.children = [\n      'children 01',\n      'children 02',\n    ];\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: 'props'\n    });\n\n    makeSnapshot(component);\n  });\n\n  it('leaf has a loop, render from parent', () => {\n    MiniRenderDivNode = new Node(miniRenderSchema, {});\n\n    TextNode = new Node(textSchema, {\n      parent: MiniRenderDivNode,\n      hasLoop: true,\n    });\n\n    nodeMap.set(textSchema.id, TextNode);\n    nodeMap.set(miniRenderSchema.id, MiniRenderDivNode);\n\n    component = renderer.create(\n      <MiniRenderDiv _leaf={MiniRenderDivNode}>\n        <Text _leaf={TextNode} content=\"content\"></Text>\n      </MiniRenderDiv>\n    );\n\n    MiniRenderDivNode.schema.children = ['this is a new children'];\n\n    TextNode.emitPropChange({\n      key: 'content',\n      newValue: '1',\n    });\n\n    makeSnapshot(component);\n  });\n});\n\ndescribe('component cache', () => {\n  it('get different component with same is and different doc id', () => {\n    const baseRenderer02 = {\n      ...baseRenderer,\n      props: {\n        ...baseRenderer.props,\n        documentId: '02',\n      }\n    }\n    const Div3 = leafWrapper(components.Div as any, {\n      schema: divSchema,\n      baseRenderer: baseRenderer02,\n      componentInfo: {},\n      scope: {},\n    });\n\n    expect(Div).not.toEqual(Div3);\n  });\n\n  it('get component again and get ths cache component', () => {\n    const Div2 = leafWrapper(components.Div as any, {\n      schema: divSchema,\n      baseRenderer,\n      componentInfo: {},\n      scope: {},\n    });\n\n    expect(Div).toEqual(Div2);\n  });\n});\n\ndescribe('onVisibleChange', () => {\n  it('visible is false', () => {\n    TextNode.emitVisibleChange(false);\n    makeSnapshot(component);\n  });\n\n  it('visible is true', () => {\n    TextNode.emitVisibleChange(true);\n    makeSnapshot(component);\n  });\n});\n\ndescribe('children', () => {\n  it('this.props.children is array', () => {\n    const component = renderer.create(\n      <Div _leaf={DivNode}>\n        <Text _leaf={TextNode} content=\"content\"></Text>\n        <Text _leaf={TextNode} content=\"content\"></Text>\n      </Div>\n    );\n\n    makeSnapshot(component);\n  });\n});\n\ndescribe('onChildrenChange', () => {\n  it('children is array string', () => {\n    DivNode.schema.children = [\n      'onChildrenChange content 01',\n      'onChildrenChange content 02'\n    ]\n    DivNode.emitChildrenChange();\n    makeSnapshot(component);\n  });\n\n  it('children is 0', () => {\n    DivNode.schema.children = 0\n    DivNode.emitChildrenChange();\n    const componentInstance = component.root;\n    expect(componentInstance.findByType(components.Div).props.children).toEqual(0);\n  });\n\n  it('children is false', () => {\n    DivNode.schema.children = false\n    DivNode.emitChildrenChange();\n    const componentInstance = component.root;\n    expect(componentInstance.findByType(components.Div).props.children).toEqual(false);\n  });\n\n  it('children is []', () => {\n    DivNode.schema.children = []\n    DivNode.emitChildrenChange();\n    const componentInstance = component.root;\n    expect(componentInstance.findByType(components.Div).props.children).toEqual([]);\n  });\n\n  it('children is null', () => {\n    DivNode.schema.children = null\n    DivNode.emitChildrenChange();\n    const componentInstance = component.root;\n    expect(componentInstance.findByType(components.Div).props.children).toEqual(null);\n  });\n\n  it('children is undefined', () => {\n    DivNode.schema.children = undefined;\n    DivNode.emitChildrenChange();\n    const componentInstance = component.root;\n    expect(componentInstance.findByType(components.Div).props.children).toEqual(undefined);\n  });\n});\n\ndescribe('not render leaf', () => {\n  let miniRenderSchema, MiniRenderDiv, MiniRenderDivNode;\n  beforeEach(() => {\n    miniRenderSchema = {\n      id: 'miniDiv' + id,\n    };\n\n    MiniRenderDivNode = new Node(miniRenderSchema, {\n      componentMeta: {\n        isMinimalRenderUnit: true,\n      },\n    });\n\n    nodeMap.set(miniRenderSchema.id, MiniRenderDivNode);\n\n    MiniRenderDiv = leafWrapper(components.MiniRenderDiv as any, {\n      schema: miniRenderSchema,\n      baseRenderer,\n      componentInfo: {},\n      scope: {},\n    });\n\n    TextNode = new Node(textSchema, {\n      parent: MiniRenderDivNode,\n    });\n\n    component = renderer.create(\n      <Text _leaf={TextNode} content=\"content\"></Text>\n    );\n  });\n\n  it('onPropsChange', () => {\n    const nextCount = rerenderCount + 1;\n\n    MiniRenderDivNode.emitPropChange({\n      key: 'any',\n      newValue: 'any',\n    });\n\n    expect(rerenderCount).toBe(nextCount);\n  });\n\n  it('onChildrenChange', () => {\n    const nextCount = rerenderCount + 1;\n\n    MiniRenderDivNode.emitChildrenChange({\n      key: 'any',\n      newValue: 'any',\n    });\n\n    expect(rerenderCount).toBe(nextCount);\n  });\n\n  it('onVisibleChange', () => {\n    const nextCount = rerenderCount + 1;\n\n    MiniRenderDivNode.emitVisibleChange(true);\n\n    expect(rerenderCount).toBe(nextCount);\n  });\n});\n"
  },
  {
    "path": "packages/renderer-core/tests/mock/loop.ts",
    "content": "const schema = {\n    \"componentName\": \"Page\",\n    \"id\": \"node_ocl1djd9o41\",\n    \"docId\": \"docl1djd9o4\",\n    \"props\": {\n        \"templateVersion\": \"1.0.0\",\n        \"containerStyle\": {},\n        \"pageStyle\": {\n            \"backgroundColor\": \"#f2f3f5\"\n        },\n        \"className\": \"_css_pseudo_node_ocl1djd9o41\"\n    },\n    \"dataSource\": {\n        \"offline\": [],\n        \"globalConfig\": {},\n        \"online\": [\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n                \"formUuid\": \"FORM-3KYJN7RV-J47BPFK63W2PHAGPO1VC3-B4H1WE5K-131\",\n                \"name\": \"locale\",\n                \"description\": \"当前语种（在 window.g_config 中设置）\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            },\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n                \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n                \"name\": \"appType\",\n                \"description\": \"应用的唯一 code\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            },\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n                \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n                \"name\": \"version\",\n                \"description\": \"应该版本，默认 0.1.0\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            },\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n                \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n                \"name\": \"apiPrefix\",\n                \"description\": \"\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            }\n        ],\n        \"sync\": true,\n        \"list\": [\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n                \"formUuid\": \"FORM-3KYJN7RV-J47BPFK63W2PHAGPO1VC3-B4H1WE5K-131\",\n                \"name\": \"locale\",\n                \"description\": \"当前语种（在 window.g_config 中设置）\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            },\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n                \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n                \"name\": \"appType\",\n                \"description\": \"应用的唯一 code\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            },\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n                \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n                \"name\": \"version\",\n                \"description\": \"应该版本，默认 0.1.0\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            },\n            {\n                \"gmtModified\": 1639385418000,\n                \"initialData\": \"\",\n                \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n                \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n                \"name\": \"apiPrefix\",\n                \"description\": \"\",\n                \"id\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n                \"protocal\": \"VALUE\",\n                \"shareType\": \"APP\"\n            }\n        ]\n    },\n    \"methods\": {},\n    \"hidden\": false,\n    \"title\": \"\",\n    \"isLocked\": false,\n    \"condition\": true,\n    \"conditionGroup\": \"\",\n    \"children\": [\n        {\n            \"componentName\": \"RootHeader\",\n            \"id\": \"node_ocl1djd9o42\",\n            \"docId\": \"docl1djd9o4\",\n            \"props\": {},\n            \"hidden\": false,\n            \"title\": \"\",\n            \"isLocked\": false,\n            \"condition\": true,\n            \"conditionGroup\": \"\"\n        },\n        {\n            \"componentName\": \"RootContent\",\n            \"id\": \"node_ocl1djd9o43\",\n            \"docId\": \"docl1djd9o4\",\n            \"props\": {\n                \"contentMargin\": \"20\",\n                \"contentPadding\": \"20\",\n                \"contentBgColor\": \"white\"\n            },\n            \"hidden\": false,\n            \"title\": \"\",\n            \"isLocked\": false,\n            \"condition\": true,\n            \"conditionGroup\": \"\",\n            \"children\": [\n                {\n                    \"componentName\": \"Div\",\n                    \"id\": \"node_ocl1djd9o45\",\n                    \"docId\": \"docl1djd9o4\",\n                    \"props\": {\n                        \"behavior\": \"NORMAL\",\n                        \"__style__\": {},\n                        \"fieldId\": \"div_l1djdj1n\",\n                        \"events\": {\n                            \"ignored\": true\n                        },\n                        \"useFieldIdAsDomId\": false,\n                        \"customClassName\": \"\",\n                        \"className\": \"_css_pseudo_node_ocl1djd9o45\"\n                    },\n                    \"hidden\": false,\n                    \"title\": \"\",\n                    \"isLocked\": false,\n                    \"condition\": true,\n                    \"conditionGroup\": \"\",\n                    \"loop\": [\n                        1,\n                        2,\n                        3\n                    ],\n                    \"loopArgs\": [\n                        null,\n                        null\n                    ],\n                    \"children\": [\n                        {\n                            \"componentName\": \"Div\",\n                            \"id\": \"node_ocl1djd9o46\",\n                            \"docId\": \"docl1djd9o4\",\n                            \"props\": {\n                                \"behavior\": \"NORMAL\",\n                                \"__style__\": {},\n                                \"fieldId\": \"div_l1djdj1o\",\n                                \"events\": {\n                                    \"ignored\": true\n                                },\n                                \"useFieldIdAsDomId\": false,\n                                \"customClassName\": \"\",\n                                \"className\": \"_css_pseudo_node_ocl1djd9o46\"\n                            },\n                            \"hidden\": false,\n                            \"title\": \"\",\n                            \"isLocked\": false,\n                            \"condition\": true,\n                            \"conditionGroup\": \"\",\n                            \"loop\": [\n                                1,\n                                2,\n                                3\n                            ],\n                            \"loopArgs\": [\n                                null,\n                                null\n                            ]\n                        }\n                    ]\n                }\n            ]\n        },\n        {\n            \"componentName\": \"RootFooter\",\n            \"id\": \"node_ocl1djd9o44\",\n            \"docId\": \"docl1djd9o4\",\n            \"props\": {},\n            \"hidden\": false,\n            \"title\": \"\",\n            \"isLocked\": false,\n            \"condition\": true,\n            \"conditionGroup\": \"\"\n        }\n    ]\n};\n\nexport default schema;\n"
  },
  {
    "path": "packages/renderer-core/tests/mock/sample.ts",
    "content": "export const sampleSchema = {\n  \"componentName\": \"Page\",\n  \"id\": \"node_ockyigdqxl1\",\n  \"docId\": \"dockyigdqxl\",\n  \"props\": {\n      \"templateVersion\": \"1.0.0\",\n      \"containerStyle\": {},\n      \"pageStyle\": {\n          \"backgroundColor\": \"#f2f3f5\"\n      },\n      \"className\": \"_css_pseudo_node_ockyigdqxl1\"\n  },\n  \"dataSource\": {\n      \"offline\": [],\n      \"globalConfig\": {},\n      \"online\": [\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n              \"formUuid\": \"FORM-3KYJN7RV-J47BPFK63W2PHAGPO1VC3-B4H1WE5K-131\",\n              \"name\": \"locale\",\n              \"description\": \"当前语种（在 window.g_config 中设置）\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          },\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n              \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n              \"name\": \"appType\",\n              \"description\": \"应用的唯一 code\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          },\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n              \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n              \"name\": \"version\",\n              \"description\": \"应该版本，默认 0.1.0\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          },\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n              \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n              \"name\": \"apiPrefix\",\n              \"description\": \"\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          }\n      ],\n      \"sync\": true,\n      \"list\": [\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n              \"formUuid\": \"FORM-3KYJN7RV-J47BPFK63W2PHAGPO1VC3-B4H1WE5K-131\",\n              \"name\": \"locale\",\n              \"description\": \"当前语种（在 window.g_config 中设置）\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH3NM0RF4XK61\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          },\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n              \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n              \"name\": \"appType\",\n              \"description\": \"应用的唯一 code\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH3SM0RF4XK71\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          },\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n              \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n              \"name\": \"version\",\n              \"description\": \"应该版本，默认 0.1.0\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH3XM0RF4XK81\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          },\n          {\n              \"gmtModified\": 1639385418000,\n              \"initialData\": \"\",\n              \"globalUid\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n              \"formUuid\": \"FORM-RFYJTWKV-D47BWO6R0QHA74R062FN2-R5IPXK4K-0H\",\n              \"name\": \"apiPrefix\",\n              \"description\": \"\",\n              \"id\": \"AY866BC1ERSVK0BE55NU364515LH33N0RF4XK91\",\n              \"protocal\": \"VALUE\",\n              \"shareType\": \"APP\"\n          }\n      ]\n  },\n  \"methods\": {},\n  \"lifeCycles\": {},\n  \"hidden\": false,\n  \"title\": \"\",\n  \"isLocked\": false,\n  \"condition\": true,\n  \"conditionGroup\": \"\",\n  \"children\": [\n      {\n          \"componentName\": \"RootHeader\",\n          \"id\": \"node_ockyigdqxl2\",\n          \"docId\": \"dockyigdqxl\",\n          \"props\": {},\n          \"hidden\": false,\n          \"title\": \"\",\n          \"isLocked\": false,\n          \"condition\": true,\n          \"conditionGroup\": \"\"\n      },\n      {\n          \"componentName\": \"RootContent\",\n          \"id\": \"node_ockyigdqxl3\",\n          \"docId\": \"dockyigdqxl\",\n          \"props\": {\n              \"contentMargin\": \"20\",\n              \"contentPadding\": \"20\",\n              \"contentBgColor\": \"white\"\n          },\n          \"hidden\": false,\n          \"title\": \"\",\n          \"isLocked\": false,\n          \"condition\": true,\n          \"conditionGroup\": \"\",\n          \"children\": [\n              {\n                  \"componentName\": \"Button\",\n                  \"id\": \"node_ockyigdqxl5\",\n                  \"docId\": \"dockyigdqxl\",\n                  \"props\": {\n                      \"content\": \"按 钮\",\n                      \"type\": \"primary\",\n                      \"size\": \"medium\",\n                      \"behavior\": \"NORMAL\",\n                      \"__style__\": {},\n                      \"fieldId\": \"button_kyige3yf\",\n                      \"events\": {\n                          \"ignored\": true\n                      },\n                      \"baseIcon\": \"\",\n                      \"otherIcon\": \"\",\n                      \"loading\": false,\n                      \"triggerEventsWhenLoading\": false,\n                      \"className\": \"_css_pseudo_node_ockyigdqxl5\"\n                  },\n                  \"hidden\": false,\n                  \"title\": \"\",\n                  \"isLocked\": false,\n                  \"condition\": true,\n                  \"conditionGroup\": \"\"\n              }\n          ]\n      },\n      {\n          \"componentName\": \"RootFooter\",\n          \"id\": \"node_ockyigdqxl4\",\n          \"docId\": \"dockyigdqxl\",\n          \"props\": {},\n          \"hidden\": false,\n          \"title\": \"\",\n          \"isLocked\": false,\n          \"condition\": true,\n          \"conditionGroup\": \"\"\n      }\n  ]\n};"
  },
  {
    "path": "packages/renderer-core/tests/mock/styleMock.js",
    "content": "module.exports = {\n  process() {\n    return '';\n  },\n};"
  },
  {
    "path": "packages/renderer-core/tests/renderer/__snapshots__/renderer.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Base Render renderComp 1`] = `\n<div\n  className=\"lce-page lce-test\"\n  style={\n    Object {\n      \"padding\": \"0 5px 0 5px\",\n    }\n  }\n>\n  <div\n    __id=\"node_dockcy8n9xed\"\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"next-box\"\n    style={\n      Object {\n        \"backgroundColor\": \"rgba(31,56,88,0.1)\",\n        \"flexDirection\": \"column\",\n        \"flexWrap\": \"nowrap\",\n        \"msFlexDirection\": \"column\",\n        \"msFlexWrap\": \"none\",\n        \"padding\": \"12px 12px 12px 12px\",\n      }\n    }\n  >\n    <div\n      __id=\"node_dockcy8n9xee\"\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": undefined,\n        }\n      }\n      className=\"next-box\"\n      style={\n        Object {\n          \"backgroundColor\": \"#ffffff\",\n          \"flexDirection\": \"column\",\n          \"flexWrap\": \"nowrap\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n          \"padding\": \"12px 12px 12px 12px\",\n        }\n      }\n    >\n      <nav\n        __id=\"node_dockcy8n9xef\"\n        __inner__={\n          Object {\n            \"condition\": true,\n            \"hidden\": undefined,\n          }\n        }\n        aria-label=\"Breadcrumb\"\n        style={\n          Object {\n            \"position\": \"relative\",\n          }\n        }\n      >\n        <ul\n          className=\"next-breadcrumb\"\n        >\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xeg\"\n              __inner__={\n                Object {\n                  \"condition\": true,\n                  \"hidden\": undefined,\n                }\n              }\n              className=\"next-breadcrumb-text\"\n            >\n              首页\n            </span>\n            <span\n              className=\"next-breadcrumb-separator\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep\"\n                style={Object {}}\n              />\n            </span>\n          </li>\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xei\"\n              __inner__={\n                Object {\n                  \"condition\": true,\n                  \"hidden\": undefined,\n                }\n              }\n              className=\"next-breadcrumb-text\"\n            >\n              品质中台\n            </span>\n            <span\n              className=\"next-breadcrumb-separator\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep\"\n                style={Object {}}\n              />\n            </span>\n          </li>\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xek\"\n              __inner__={\n                Object {\n                  \"condition\": true,\n                  \"hidden\": undefined,\n                }\n              }\n              className=\"next-breadcrumb-text\"\n            >\n              商家品质页面管理\n            </span>\n            <span\n              className=\"next-breadcrumb-separator\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep\"\n                style={Object {}}\n              />\n            </span>\n          </li>\n          <li\n            className=\"next-breadcrumb-item\"\n            dir={null}\n          >\n            <span\n              __id=\"node_dockcy8n9xem\"\n              __inner__={\n                Object {\n                  \"condition\": true,\n                  \"hidden\": undefined,\n                }\n              }\n              aria-current=\"page\"\n              className=\"next-breadcrumb-text activated\"\n            >\n              质检知识条配置\n            </span>\n          </li>\n        </ul>\n      </nav>\n    </div>\n    <div\n      __id=\"node_dockcy8n9xeo\"\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": undefined,\n        }\n      }\n      className=\"next-box\"\n      style={\n        Object {\n          \"backgroundColor\": \"#ffffff\",\n          \"flexDirection\": \"column\",\n          \"flexWrap\": \"nowrap\",\n          \"marginTop\": \"12px\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n        }\n      }\n    >\n      <form\n        __events={Array []}\n        __id=\"node_dockcy8n9xep\"\n        __inner__={\n          Object {\n            \"condition\": true,\n            \"hidden\": undefined,\n          }\n        }\n        className=\"next-form next-inline next-medium\"\n        onSubmit={[Function]}\n        role=\"grid\"\n        style={\n          Object {\n            \"marginLeft\": \"12px\",\n            \"marginRight\": \"12px\",\n            \"marginTop\": \"12px\",\n          }\n        }\n      >\n        <div\n          __id=\"node_dockcy8n9xeq\"\n          __inner__={\n            Object {\n              \"condition\": true,\n              \"hidden\": undefined,\n            }\n          }\n          className=\"next-form-item next-left next-medium\"\n          style={\n            Object {\n              \"marginBottom\": \"0\",\n            }\n          }\n        >\n          <div\n            className=\"next-form-item-label\"\n          >\n            <label>\n              类目名：\n            </label>\n          </div>\n          <div\n            className=\"next-form-item-control\"\n          >\n            <span\n              aria-haspopup={true}\n              className=\"next-select next-select-trigger next-select-single next-medium next-inactive next-no-search\"\n              onClick={[Function]}\n              onKeyDown={[Function]}\n              onMouseDown={[Function]}\n              onMouseEnter={[Function]}\n              onMouseLeave={[Function]}\n              style={\n                Object {\n                  \"width\": \"150px\",\n                }\n              }\n            >\n              <span\n                className=\"next-input next-medium next-select-inner\"\n              >\n                <span\n                  className=\"next-select-values next-input-text-field\"\n                >\n                  <span\n                    className=\"next-select-trigger-search\"\n                  >\n                    <input\n                      __id=\"node_dockcy8n9xer\"\n                      __inner__={\n                        Object {\n                          \"condition\": true,\n                          \"hidden\": undefined,\n                        }\n                      }\n                      autoComplete=\"off\"\n                      disabled={false}\n                      height=\"100%\"\n                      maxLength={null}\n                      onBlur={[Function]}\n                      onChange={[Function]}\n                      onCompositionEnd={[Function]}\n                      onCompositionStart={[Function]}\n                      onFocus={[Function]}\n                      onKeyDown={[Function]}\n                      placeholder=\"请选择\"\n                      readOnly={true}\n                      role=\"combobox\"\n                      size=\"1\"\n                      tabIndex={0}\n                      value=\"\"\n                    />\n                    <span\n                      aria-hidden={true}\n                    >\n                      <span>\n                        请选择\n                      </span>\n                      <span\n                        style={\n                          Object {\n                            \"display\": \"inline-block\",\n                            \"width\": 1,\n                          }\n                        }\n                      >\n                         \n                      </span>\n                    </span>\n                  </span>\n                </span>\n                <span\n                  className=\"next-input-control\"\n                  onClick={[Function]}\n                >\n                  <span\n                    aria-hidden={true}\n                    className=\"next-select-arrow\"\n                    onClick={[Function]}\n                  >\n                    <i\n                      className=\"next-icon next-icon-arrow-down next-medium next-select-symbol-fold\"\n                      style={Object {}}\n                    />\n                  </span>\n                </span>\n              </span>\n              <span\n                aria-live=\"polite\"\n                className=\"next-sr-only\"\n              >\n                \n              </span>\n            </span>\n             \n             \n          </div>\n        </div>\n        <div\n          __id=\"node_dockcy8n9xes\"\n          __inner__={\n            Object {\n              \"condition\": true,\n              \"hidden\": undefined,\n            }\n          }\n          className=\"next-form-item next-left next-medium\"\n          style={\n            Object {\n              \"marginBottom\": \"0\",\n            }\n          }\n        >\n          <div\n            className=\"next-form-item-label\"\n          >\n            <label>\n              项目类型：\n            </label>\n          </div>\n          <div\n            className=\"next-form-item-control\"\n          >\n            <span\n              aria-haspopup={true}\n              className=\"next-select next-select-trigger next-select-single next-medium next-inactive next-no-search\"\n              onClick={[Function]}\n              onKeyDown={[Function]}\n              onMouseDown={[Function]}\n              onMouseEnter={[Function]}\n              onMouseLeave={[Function]}\n              style={\n                Object {\n                  \"width\": \"200px\",\n                }\n              }\n            >\n              <span\n                className=\"next-input next-medium next-select-inner\"\n              >\n                <span\n                  className=\"next-select-values next-input-text-field\"\n                >\n                  <span\n                    className=\"next-select-trigger-search\"\n                  >\n                    <input\n                      __id=\"node_dockcy8n9xet\"\n                      __inner__={\n                        Object {\n                          \"condition\": true,\n                          \"hidden\": undefined,\n                        }\n                      }\n                      autoComplete=\"off\"\n                      disabled={false}\n                      height=\"100%\"\n                      maxLength={null}\n                      onBlur={[Function]}\n                      onChange={[Function]}\n                      onCompositionEnd={[Function]}\n                      onCompositionStart={[Function]}\n                      onFocus={[Function]}\n                      onKeyDown={[Function]}\n                      placeholder=\"请选择\"\n                      readOnly={true}\n                      role=\"combobox\"\n                      size=\"1\"\n                      tabIndex={0}\n                      value=\"\"\n                    />\n                    <span\n                      aria-hidden={true}\n                    >\n                      <span>\n                        请选择\n                      </span>\n                      <span\n                        style={\n                          Object {\n                            \"display\": \"inline-block\",\n                            \"width\": 1,\n                          }\n                        }\n                      >\n                         \n                      </span>\n                    </span>\n                  </span>\n                </span>\n                <span\n                  className=\"next-input-control\"\n                  onClick={[Function]}\n                >\n                  <span\n                    aria-hidden={true}\n                    className=\"next-select-arrow\"\n                    onClick={[Function]}\n                  >\n                    <i\n                      className=\"next-icon next-icon-arrow-down next-medium next-select-symbol-fold\"\n                      style={Object {}}\n                    />\n                  </span>\n                </span>\n              </span>\n              <span\n                aria-live=\"polite\"\n                className=\"next-sr-only\"\n              >\n                \n              </span>\n            </span>\n             \n             \n          </div>\n        </div>\n        <div\n          __id=\"node_dockcy8n9xeu\"\n          __inner__={\n            Object {\n              \"condition\": true,\n              \"hidden\": undefined,\n            }\n          }\n          className=\"next-form-item next-left next-medium\"\n          style={\n            Object {\n              \"marginBottom\": \"0\",\n            }\n          }\n        >\n          <div\n            className=\"next-form-item-label\"\n          >\n            <label>\n              项目 ID：\n            </label>\n          </div>\n          <div\n            className=\"next-form-item-control\"\n          >\n            <span\n              className=\"next-input next-medium\"\n              style={\n                Object {\n                  \"width\": \"200px\",\n                }\n              }\n            >\n              <input\n                __id=\"node_dockcy8n9xev\"\n                __inner__={\n                  Object {\n                    \"condition\": true,\n                    \"hidden\": undefined,\n                  }\n                }\n                autoComplete=\"off\"\n                disabled={false}\n                height=\"100%\"\n                maxLength={null}\n                onBlur={[Function]}\n                onChange={[Function]}\n                onCompositionEnd={[Function]}\n                onCompositionStart={[Function]}\n                onFocus={[Function]}\n                onKeyDown={[Function]}\n                readOnly={false}\n                value=\"\"\n              />\n            </span>\n             \n             \n          </div>\n        </div>\n        <div\n          __id=\"node_dockcy8n9xew\"\n          __inner__={\n            Object {\n              \"condition\": true,\n              \"hidden\": undefined,\n            }\n          }\n          className=\"next-btn-group\"\n        >\n          <button\n            __id=\"node_dockcy8n9xex\"\n            __inner__={\n              Object {\n                \"condition\": true,\n                \"hidden\": undefined,\n              }\n            }\n            className=\"next-btn next-medium next-btn-primary\"\n            disabled={false}\n            onClick={[Function]}\n            onMouseUp={[Function]}\n            style={\n              Object {\n                \"margin\": \"0 5px 0 5px\",\n              }\n            }\n            type=\"submit\"\n          >\n            <span\n              className=\"next-btn-helper\"\n            >\n              搜索\n            </span>\n          </button>\n          <button\n            __id=\"node_dockcy8n9xe10\"\n            __inner__={\n              Object {\n                \"condition\": true,\n                \"hidden\": undefined,\n              }\n            }\n            className=\"next-btn next-medium next-btn-normal\"\n            disabled={false}\n            onClick={[Function]}\n            onMouseUp={[Function]}\n            style={\n              Object {\n                \"margin\": \"0 5px 0 5px\",\n              }\n            }\n            type=\"reset\"\n          >\n            <span\n              className=\"next-btn-helper\"\n            >\n              清空\n            </span>\n          </button>\n        </div>\n      </form>\n    </div>\n    <div\n      __id=\"node_dockcy8n9xe1f\"\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": undefined,\n        }\n      }\n      className=\"next-box\"\n      style={\n        Object {\n          \"backgroundColor\": \"#ffffff\",\n          \"display\": \"flex\",\n          \"flexDirection\": \"row\",\n          \"flexWrap\": \"nowrap\",\n          \"justifyContent\": \"flex-end\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n          \"paddingBottom\": \"24px\",\n        }\n      }\n    >\n      <button\n        __events={\n          Array [\n            Object {\n              \"name\": \"onClick\",\n              \"relatedEventName\": \"onClick\",\n              \"type\": \"componentEvent\",\n            },\n          ]\n        }\n        __id=\"node_dockd5nrh9p4\"\n        __inner__={\n          Object {\n            \"condition\": true,\n            \"hidden\": undefined,\n          }\n        }\n        className=\"next-btn next-medium next-btn-primary\"\n        disabled={false}\n        onClick={[Function]}\n        onMouseUp={[Function]}\n        style={Object {}}\n        type=\"button\"\n      >\n        <span\n          className=\"next-btn-helper\"\n        >\n          新建配置\n        </span>\n      </button>\n    </div>\n    <div\n      __id=\"node_dockd5nrh9p5\"\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": undefined,\n        }\n      }\n      className=\"next-box\"\n      style={\n        Object {\n          \"flexDirection\": \"column\",\n          \"flexWrap\": \"nowrap\",\n          \"msFlexDirection\": \"column\",\n          \"msFlexWrap\": \"none\",\n        }\n      }\n    >\n      <div\n        __id=\"node_dockjielosj1\"\n        __inner__={\n          Object {\n            \"condition\": true,\n            \"hidden\": undefined,\n          }\n        }\n        actionBar={\n          Array [\n            Object {\n              \"title\": \"新增\",\n              \"type\": \"primary\",\n            },\n            Object {\n              \"title\": \"编辑\",\n            },\n          ]\n        }\n        actionColumn={\n          Array [\n            Object {\n              \"callback\": [Function],\n              \"device\": Array [\n                \"desktop\",\n              ],\n              \"title\": \"编辑\",\n            },\n            Object {\n              \"callback\": [Function],\n              \"mode\": \"EDIT\",\n              \"title\": \"保存\",\n            },\n          ]\n        }\n        actionFixed=\"right\"\n        actionHidden={false}\n        actionTitle=\"操作\"\n        actionType=\"link\"\n        actionWidth={180}\n        className=\"next-table next-table-medium\"\n        data={\n          Array [\n            Object {\n              \"age\": 15000,\n              \"email\": \"aaa@abc.com\",\n              \"id\": \"1\",\n              \"name\": \"王小\",\n            },\n            Object {\n              \"age\": 25000,\n              \"email\": \"bbb@abc.com\",\n              \"id\": \"2\",\n              \"name\": \"王中\",\n            },\n            Object {\n              \"age\": 35000,\n              \"email\": \"ccc@abc.com\",\n              \"id\": \"3\",\n              \"name\": \"王大\",\n            },\n          ]\n        }\n        maxWebShownActionCount={2}\n        showActionBar={true}\n        showMiniPager={true}\n        style={Object {}}\n      >\n        <div\n          className=\"next-table-column-resize-proxy\"\n        />\n        <table\n          role=\"table\"\n          style={\n            Object {\n              \"width\": undefined,\n            }\n          }\n        >\n          <colgroup>\n            <col\n              style={\n                Object {\n                  \"width\": 200,\n                }\n              }\n            />\n            <col\n              style={\n                Object {\n                  \"width\": 200,\n                }\n              }\n            />\n            <col\n              style={\n                Object {\n                  \"width\": 200,\n                }\n              }\n            />\n          </colgroup>\n          <thead\n            className=\"next-table-header\"\n          >\n            <tr>\n              <th\n                className=\"next-table-cell next-table-header-node\"\n                role=\"gridcell\"\n                rowSpan={1}\n                style={\n                  Object {\n                    \"textAlign\": \"center\",\n                  }\n                }\n              >\n                <div\n                  className=\"next-table-cell-wrapper\"\n                  data-next-table-col={0}\n                >\n                  姓名\n                </div>\n              </th>\n              <th\n                className=\"next-table-cell next-table-header-node\"\n                role=\"gridcell\"\n                rowSpan={1}\n                style={\n                  Object {\n                    \"textAlign\": \"center\",\n                  }\n                }\n              >\n                <div\n                  className=\"next-table-cell-wrapper\"\n                  data-next-table-col={1}\n                >\n                  年龄\n                </div>\n              </th>\n              <th\n                className=\"next-table-cell next-table-header-node\"\n                role=\"gridcell\"\n                rowSpan={1}\n                style={\n                  Object {\n                    \"textAlign\": \"center\",\n                  }\n                }\n              >\n                <div\n                  className=\"next-table-cell-wrapper\"\n                  data-next-table-col={2}\n                >\n                  邮箱\n                </div>\n              </th>\n            </tr>\n          </thead>\n          <tbody\n            className=\"next-table-body\"\n          >\n            <tr>\n              <td\n                colSpan={3}\n              >\n                <div\n                  className=\"next-table-empty\"\n                  style={\n                    Object {\n                      \"left\": 0,\n                      \"overflow\": \"hidden\",\n                      \"position\": \"sticky\",\n                      \"width\": -1,\n                    }\n                  }\n                >\n                  没有数据\n                </div>\n              </td>\n            </tr>\n          </tbody>\n        </table>\n      </div>\n      <div\n        __id=\"node_dockd5nrh9pg\"\n        __inner__={\n          Object {\n            \"condition\": true,\n            \"hidden\": undefined,\n          }\n        }\n        className=\"next-box\"\n        style={\n          Object {\n            \"display\": \"flex\",\n            \"flexDirection\": \"row\",\n            \"flexWrap\": \"nowrap\",\n            \"justifyContent\": \"flex-end\",\n            \"msFlexDirection\": \"column\",\n            \"msFlexWrap\": \"none\",\n          }\n        }\n      >\n        <div\n          __id=\"node_dockd5nrh9pf\"\n          __inner__={\n            Object {\n              \"condition\": true,\n              \"hidden\": undefined,\n            }\n          }\n          className=\"next-pagination next-medium next-normal\"\n          style={Object {}}\n        >\n          <div\n            className=\"next-pagination-pages\"\n          >\n            <button\n              aria-label=\"上一页，当前第1页\"\n              className=\"next-btn next-medium next-btn-normal next-pagination-item next-prev\"\n              disabled={true}\n              onClick={[Function]}\n              onMouseUp={[Function]}\n              type=\"button\"\n            >\n              <i\n                className=\"next-icon next-icon-arrow-left next-xs next-btn-icon next-icon-first next-pagination-icon-prev\"\n                style={Object {}}\n              />\n              <span\n                className=\"next-btn-helper\"\n              >\n                上一页\n              </span>\n            </button>\n            <div\n              className=\"next-pagination-list\"\n            >\n              <button\n                aria-label=\"第1页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item next-current\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  1\n                </span>\n              </button>\n              <button\n                aria-label=\"第2页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  2\n                </span>\n              </button>\n              <button\n                aria-label=\"第3页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  3\n                </span>\n              </button>\n              <button\n                aria-label=\"第4页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  4\n                </span>\n              </button>\n              <i\n                className=\"next-icon next-icon-ellipsis next-medium next-pagination-ellipsis next-pagination-icon-ellipsis\"\n                style={Object {}}\n              />\n              <button\n                aria-label=\"第10页，共10页\"\n                className=\"next-btn next-medium next-btn-normal next-pagination-item\"\n                disabled={false}\n                onClick={[Function]}\n                onMouseUp={[Function]}\n                type=\"button\"\n              >\n                <span\n                  className=\"next-btn-helper\"\n                >\n                  10\n                </span>\n              </button>\n            </div>\n            <button\n              aria-label=\"下一页，当前第1页\"\n              className=\"next-btn next-medium next-btn-normal next-pagination-item next-next\"\n              disabled={false}\n              onClick={[Function]}\n              onMouseUp={[Function]}\n              type=\"button\"\n            >\n              <span\n                className=\"next-btn-helper\"\n              >\n                下一页\n              </span>\n              <i\n                className=\"next-icon next-icon-arrow-right next-xs next-btn-icon next-icon-last next-pagination-icon-next\"\n                style={Object {}}\n              />\n            </button>\n            <span\n              className=\"next-pagination-display\"\n            >\n              <em>\n                1\n              </em>\n              /\n              10\n            </span>\n            <span\n              className=\"next-pagination-jump-text\"\n            >\n              到第\n            </span>\n            <span\n              className=\"next-input next-medium next-pagination-jump-input\"\n            >\n              <input\n                aria-label=\"请输入跳转到第几页\"\n                autoComplete=\"off\"\n                disabled={false}\n                height=\"100%\"\n                maxLength={null}\n                onBlur={[Function]}\n                onChange={[Function]}\n                onCompositionEnd={[Function]}\n                onCompositionStart={[Function]}\n                onFocus={[Function]}\n                onKeyDown={[Function]}\n                readOnly={false}\n                value=\"\"\n              />\n            </span>\n            <span\n              className=\"next-pagination-jump-text\"\n            >\n              页\n            </span>\n            <button\n              className=\"next-btn next-medium next-btn-normal next-pagination-jump-go\"\n              disabled={false}\n              onClick={[Function]}\n              onMouseUp={[Function]}\n              type=\"button\"\n            >\n              <span\n                className=\"next-btn-helper\"\n              >\n                确定\n              </span>\n            </button>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n  <span\n    aria-haspopup={true}\n    className=\"next-select next-select-trigger next-select-single next-medium next-inactive next-no-search\"\n    onClick={[Function]}\n    onKeyDown={[Function]}\n    onMouseDown={[Function]}\n    onMouseEnter={[Function]}\n    onMouseLeave={[Function]}\n  >\n    <span\n      className=\"next-input next-medium next-select-inner\"\n    >\n      <span\n        className=\"next-select-values next-input-text-field\"\n      >\n        <span\n          className=\"next-select-trigger-search\"\n        >\n          <input\n            __id=\"node_dockd5nrh9pr\"\n            __inner__={\n              Object {\n                \"condition\": true,\n                \"hidden\": undefined,\n              }\n            }\n            autoComplete=\"off\"\n            disabled={false}\n            height=\"100%\"\n            maxLength={null}\n            name=\"error\"\n            onBlur={[Function]}\n            onChange={[Function]}\n            onCompositionEnd={[Function]}\n            onCompositionStart={[Function]}\n            onFocus={[Function]}\n            onKeyDown={[Function]}\n            placeholder=\"请选择\"\n            readOnly={true}\n            role=\"combobox\"\n            size=\"1\"\n            tabIndex={0}\n            value=\"\"\n          />\n          <span\n            aria-hidden={true}\n          >\n            <span>\n              请选择\n            </span>\n            <span\n              style={\n                Object {\n                  \"display\": \"inline-block\",\n                  \"width\": 1,\n                }\n              }\n            >\n               \n            </span>\n          </span>\n        </span>\n      </span>\n      <span\n        className=\"next-input-control\"\n        onClick={[Function]}\n      >\n        <span\n          aria-hidden={true}\n          className=\"next-select-arrow\"\n          onClick={[Function]}\n        >\n          <i\n            className=\"next-icon next-icon-arrow-down next-medium next-select-symbol-fold\"\n            style={Object {}}\n          />\n        </span>\n      </span>\n    </span>\n    <span\n      aria-live=\"polite\"\n      className=\"next-sr-only\"\n    >\n      \n    </span>\n  </span>\n</div>\n`;\n\nexports[`JSExpression JSExpression props 1`] = `\n<div\n  className=\"lce-page\"\n  style={Object {}}\n>\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n    visible={true}\n  />\n</div>\n`;\n\nexports[`JSExpression JSExpression props with loop 1`] = `\n<div\n  className=\"lce-page\"\n  style={Object {}}\n>\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n    name1=\"1\"\n    name2=\"1\"\n  />\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n    name1=\"2\"\n    name2=\"2\"\n  />\n</div>\n`;\n\nexports[`JSExpression JSExpression props with loop, and thisRequiredInJSE is true 1`] = `\n<div\n  className=\"lce-page\"\n  style={Object {}}\n>\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n    name1=\"1\"\n  />\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n    name1=\"2\"\n  />\n</div>\n`;\n\nexports[`JSExpression JSFunction props 1`] = `\n<div\n  className=\"lce-page\"\n  style={Object {}}\n>\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n    onClick={[Function]}\n  />\n</div>\n`;\n\nexports[`JSExpression JSSlot has loop 1`] = `\n<div\n  className=\"lce-page\"\n  style={Object {}}\n>\n  <div\n    __id=\"node_ocl1ao1o7w3\"\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": false,\n      }\n    }\n    __style__=\":root {\n padding: 12px;\n background: #f2f2f2;\n border: 1px solid #ddd;\n}\"\n    behavior=\"NORMAL\"\n    className=\"div_l1ao7pfc\"\n    customClassName=\"\"\n    fieldId=\"div_l1ao7lvq\"\n    forwardRef={[Function]}\n    useFieldIdAsDomId={false}\n  >\n    <div\n      __id=\"node_ocl1ao1o7w4\"\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": false,\n        }\n      }\n      __style__=\":root {\n font-size: 14px;\n color: #666;\n}\"\n      behavior=\"NORMAL\"\n      className=\"text_l1ao7pfb\"\n      content=\"这是一个低代码业务组件~\"\n      fieldId=\"text_l1ao7lvp\"\n      forwardRef={[Function]}\n      maxLine={0}\n      showTitle={false}\n    >\n      这是一个低代码业务组件~\n    </div>\n  </div>\n  <div\n    __id=\"node_ocl1ao1o7w3\"\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": false,\n      }\n    }\n    __style__=\":root {\n padding: 12px;\n background: #f2f2f2;\n border: 1px solid #ddd;\n}\"\n    behavior=\"NORMAL\"\n    className=\"div_l1ao7pfc\"\n    customClassName=\"\"\n    fieldId=\"div_l1ao7lvq\"\n    forwardRef={[Function]}\n    useFieldIdAsDomId={false}\n  >\n    <div\n      __id=\"node_ocl1ao1o7w4\"\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": false,\n        }\n      }\n      __style__=\":root {\n font-size: 14px;\n color: #666;\n}\"\n      behavior=\"NORMAL\"\n      className=\"text_l1ao7pfb\"\n      content=\"这是一个低代码业务组件~\"\n      fieldId=\"text_l1ao7lvp\"\n      forwardRef={[Function]}\n      maxLine={0}\n      showTitle={false}\n    >\n      这是一个低代码业务组件~\n    </div>\n  </div>\n  <div\n    __id=\"node_ocl1ao1o7w3\"\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": false,\n      }\n    }\n    __style__=\":root {\n padding: 12px;\n background: #f2f2f2;\n border: 1px solid #ddd;\n}\"\n    behavior=\"NORMAL\"\n    className=\"div_l1ao7pfc\"\n    customClassName=\"\"\n    fieldId=\"div_l1ao7lvq\"\n    forwardRef={[Function]}\n    useFieldIdAsDomId={false}\n  >\n    <div\n      __id=\"node_ocl1ao1o7w4\"\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": false,\n        }\n      }\n      __style__=\":root {\n font-size: 14px;\n color: #666;\n}\"\n      behavior=\"NORMAL\"\n      className=\"text_l1ao7pfb\"\n      content=\"这是一个低代码业务组件~\"\n      fieldId=\"text_l1ao7lvp\"\n      forwardRef={[Function]}\n      maxLine={0}\n      showTitle={false}\n    >\n      这是一个低代码业务组件~\n    </div>\n  </div>\n</div>\n`;\n\nexports[`JSExpression base props 1`] = `\n<div\n  className=\"lce-page\"\n  style={Object {}}\n>\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n    text=\"123\"\n    visible={true}\n  />\n</div>\n`;\n\nexports[`designMode designMode:default 1`] = `\n<div\n  className=\"lce-page\"\n  style={Object {}}\n>\n  <div\n    __inner__={\n      Object {\n        \"condition\": true,\n        \"hidden\": undefined,\n      }\n    }\n    className=\"div-ut\"\n    forwardRef={[Function]}\n  >\n    <div\n      __inner__={\n        Object {\n          \"condition\": true,\n          \"hidden\": undefined,\n        }\n      }\n      className=\"div-ut-children\"\n      forwardRef={[Function]}\n    />\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/renderer-core/tests/renderer/base.test.tsx",
    "content": "\nimport React, { Component, createElement, forwardRef, PureComponent, createContext } from 'react';\nconst mockGetRenderers = jest.fn();\nconst mockGetRuntime = jest.fn();\nconst mockParseExpression = jest.fn();\njest.mock('../../src/adapter', () => {\n  return {\n    getRenderers: () => { return mockGetRenderers();},\n    getRuntime: () => { return mockGetRuntime();},\n   };\n});\njest.mock('../../src/utils', () => {\n  const originalUtils = jest.requireActual('../../src/utils');\n  return {\n    ...originalUtils,\n    parseExpression: (...args) => { mockParseExpression(args);},\n   };\n});\n\n\nimport baseRendererFactory from '../../src/renderer/base';\nimport { IBaseRendererProps } from '../../src/types';\nimport TestRenderer from 'react-test-renderer';\nimport components from '../utils/components';\nimport schema from '../fixtures/schema/basic';\n\n\ndescribe('Base Render factory', () => {\n  it('customBaseRenderer logic works', () => {\n    mockGetRenderers.mockReturnValue({BaseRenderer: {}});\n    const baseRenderer = baseRendererFactory();\n    expect(mockGetRenderers).toBeCalledTimes(1);\n    expect(baseRenderer).toStrictEqual({});\n    mockGetRenderers.mockClear();\n  });\n});\n\ndescribe('Base Render methods', () => {\n  let RendererClass;\n  const mockRendererFactory = () => {\n    return class extends Component {\n      constructor(props: IBaseRendererProps, context: any) {\n        super(props, context);\n      }\n    }\n  }\n  beforeEach(() => {\n    const mockRnederers = {\n      PageRenderer: mockRendererFactory(),\n      ComponentRenderer: mockRendererFactory(),\n      BlockRenderer: mockRendererFactory(),\n      AddonRenderer: mockRendererFactory(),\n      TempRenderer: mockRendererFactory(),\n      DivRenderer: mockRendererFactory(),\n    };\n    mockGetRenderers.mockReturnValue(mockRnederers);\n    mockGetRuntime.mockReturnValue({\n      Component,\n      createElement,\n      PureComponent,\n      createContext,\n      forwardRef,\n    });\n    RendererClass = baseRendererFactory();\n  })\n\n  afterEach(() => {\n    mockGetRenderers.mockClear();\n  })\n\n  it('should excute lifecycle.getDerivedStateFromProps when defined', () => {\n    const mockGetDerivedStateFromProps = {\n      type: 'JSFunction',\n      value: 'function() {\\n    console.log(\\'did mount\\');\\n  }',\n    };\n    const mockSchema = schema;\n    (mockSchema.lifeCycles as any).getDerivedStateFromProps = mockGetDerivedStateFromProps;\n\n    // const originalUtils = jest.requireActual('../../src/utils');\n    // mockParseExpression.mockImplementation(originalUtils.parseExpression);\n    const component = TestRenderer.create(\n      <RendererClass\n        __schema={mockSchema}\n        components={components as any}\n        thisRequiredInJSE={false}\n        a='1'\n      />);\n    // console.log(component.root.props.a);\n    // component.update(<RendererClasssnippets\n    //   schema={mockSchema}\n    //   components={components as any}\n    //   thisRequiredInJSE={false}\n    //   a='2'\n    // />);\n    // console.log(component.root.props.a);\n    // expect(mockParseExpression).toHaveBeenCalledWith(mockGetDerivedStateFromProps, expect.anything())\n    // test lifecycle.getDerivedStateFromProps is null\n\n    // test lifecycle.getDerivedStateFromProps is JSExpression\n\n    // test lifecycle.getDerivedStateFromProps is JSFunction\n\n    // test lifecycle.getDerivedStateFromProps is function\n\n  });\n\n\n  // it('should excute lifecycle.getSnapshotBeforeUpdate when defined', () => {\n  // });\n\n  // it('should excute lifecycle.componentDidMount when defined', () => {\n  // });\n\n  // it('should excute lifecycle.componentDidUpdate when defined', () => {\n  // });\n\n  // it('should excute lifecycle.componentWillUnmount when defined', () => {\n  // });\n\n  // it('should excute lifecycle.componentDidCatch when defined', () => {\n  // });\n\n  // it('__executeLifeCycleMethod should work', () => {\n  // });\n\n  // it('reloadDataSource should work', () => {\n  // });\n\n  // it('shouldComponentUpdate should work', () => {\n  // });\n\n\n  // it('_getComponentView should work', () => {\n  // });\n\n  // it('__bindCustomMethods should work', () => {\n  // });\n\n  // it('__generateCtx should work', () => {\n  // });\n\n  // it('__parseData should work', () => {\n  // });\n\n  // it('__initDataSource should work', () => {\n  // });\n\n  // it('__initI18nAPIs should work', () => {\n  // });\n\n  // it('__writeCss should work', () => {\n  // });\n\n  // it('__render should work', () => {\n  // });\n\n  // it('getSchemaChildren should work', () => {\n  // });\n\n  // it('__createDom should work', () => {\n  // });\n\n  // it('__createVirtualDom should work', () => {\n  // });\n\n  // it('__componentHOCs should work', () => {\n  // });\n\n  // it('__getSchemaChildrenVirtualDom should work', () => {\n  // });\n\n  // it('__getComponentProps should work', () => {\n  // });\n\n  // it('__createLoopVirtualDom should work', () => {\n  // });\n\n  // it('__designModeIsDesign should work', () => {\n  // });\n\n  // it('__parseProps should work', () => {\n  // });\n\n  // it('$ should work', () => {\n  // });\n\n  // it('__renderContextProvider should work', () => {\n  // });\n\n  // it('__renderContextConsumer should work', () => {\n  // });\n\n  // it('__getHOCWrappedComponent should work', () => {\n  // });\n\n  // it('__renderComp should work', () => {\n  // });\n\n  // it('__renderContent should work', () => {\n  // });\n\n  // it('__checkSchema should work', () => {\n  // });\n\n  // it('requestHandlersMap should work', () => {\n  // });\n\n  // it('utils should work', () => {\n  // });\n\n  // it('constants should work', () => {\n  // });\n\n  // it('history should work', () => {\n  // });\n\n  // it('location should work', () => {\n  // });\n\n  // it('match should work', () => {\n  // });\n});"
  },
  {
    "path": "packages/renderer-core/tests/renderer/renderer.test.tsx",
    "content": "import React from 'react';\nimport renderer from 'react-test-renderer';\nimport schema from '../fixtures/schema/basic';\nimport '../utils/react-env-init';\nimport rendererFactory from '../../src/renderer/renderer';\nimport components from '../utils/components';\n\nconst Renderer = rendererFactory();\n\nfunction getComp(schema, comp = null, others = {}): Promise<{\n  component,\n  inst,\n}> {\n  return new Promise((resolve, reject) => {\n    const component = renderer.create(\n      <Renderer\n        schema={schema}\n        components={components as any}\n        {...others}\n      />);\n\n    const componentInstance = component.root;\n\n    setTimeout(() => {\n      resolve({\n        inst: comp ? componentInstance.findAllByType(comp) : null,\n        component,\n      });\n    }, 20);\n  })\n}\n\nbeforeEach(() => {\n\n});\n\nlet componentSnapshot;\n\nafterEach(() => {\n  if (componentSnapshot) {\n    let tree = componentSnapshot.toJSON();\n    expect(tree).toMatchSnapshot();\n    componentSnapshot = null;\n  }\n});\n\ndescribe('Base Render', () => {\n  it('renderComp', () => {\n    const content = (\n      <Renderer\n        schema={schema as any}\n        components={components as any}\n      />);\n    const tree = renderer.create(content).toJSON();\n    expect(tree).toMatchSnapshot();\n  });\n});\n\ndescribe('JSExpression', () => {\n  it('base props', (done) => {\n    const schema = {\n      componentName: 'Page',\n      props: {},\n      children: [\n        {\n          componentName: \"Div\",\n          props: {\n            className: 'div-ut',\n            text: \"123\",\n            visible: true,\n          }\n        }\n      ]\n    };\n\n    getComp(schema, components.Div).then(({ component, inst }) => {\n      expect(inst[0].props.text).toBe('123');\n      expect(inst[0].props.visible).toBeTruthy();\n\n      componentSnapshot = component;\n      done();\n    });\n  });\n\n  it('JSExpression props', (done) => {\n    const schema = {\n      componentName: 'Page',\n      props: {},\n      state: {\n        isShowDialog: true,\n      },\n      children: [\n        {\n          componentName: \"Div\",\n          props: {\n            className: \"div-ut\",\n            visible: {\n              type: 'JSExpression',\n              value: 'this.state.isShowDialog',\n            },\n          }\n        }\n      ]\n    };\n\n    getComp(schema, components.Div).then(({ component, inst }) => {\n      expect(inst[0].props.visible).toBeTruthy();\n      componentSnapshot = component;\n      done();\n    });\n  });\n\n  it('JSExpression props with loop', (done) => {\n    const schema = {\n      componentName: 'Page',\n      props: {},\n      state: {\n        isShowDialog: true,\n      },\n      children: [\n        {\n          componentName: \"Div\",\n          loop: [\n            {\n              name: '1',\n            },\n            {\n              name: '2'\n            }\n          ],\n          props: {\n            className: \"div-ut\",\n            name1: {\n              type: 'JSExpression',\n              value: 'this.item.name',\n            },\n            name2: {\n              type: 'JSExpression',\n              value: 'item.name',\n            },\n          }\n        }\n      ]\n    };\n\n    getComp(schema, components.Div, {\n      thisRequiredInJSE: false,\n    }).then(({ component, inst }) => {\n      // expect(inst[0].props.visible).toBeTruthy();\n      expect(inst.length).toEqual(2);\n      [1, 2].forEach((i) => {\n        expect(inst[0].props[`name${i}`]).toBe('1');\n        expect(inst[1].props[`name${i}`]).toBe('2');\n      })\n      componentSnapshot = component;\n      done();\n    });\n  });\n\n  it('JSExpression props with loop, and thisRequiredInJSE is true', (done) => {\n    const schema = {\n      componentName: 'Page',\n      props: {},\n      state: {\n        isShowDialog: true,\n      },\n      children: [\n        {\n          componentName: \"Div\",\n          loop: [\n            {\n              name: '1',\n            },\n            {\n              name: '2'\n            }\n          ],\n          props: {\n            className: \"div-ut\",\n            name1: {\n              type: 'JSExpression',\n              value: 'this.item.name',\n            },\n            name2: {\n              type: 'JSExpression',\n              value: 'item.name',\n            },\n          }\n        }\n      ]\n    };\n\n    getComp(schema, components.Div).then(({ component, inst }) => {\n      expect(inst.length).toEqual(2);\n      [0, 1].forEach((i) => {\n        expect(inst[i].props[`name1`]).toBe(i + 1 + '');\n        expect(inst[i].props[`name2`]).toBe(undefined);\n      })\n      componentSnapshot = component;\n      done();\n    });\n  });\n\n  // it('JSFunction props with loop', (done) => {\n  //   const schema = {\n  //     componentName: 'Page',\n  //     props: {},\n  //     state: {\n  //       isShowDialog: true,\n  //     },\n  //     children: [\n  //       {\n  //         componentName: \"Div\",\n  //         loop: [\n  //           {\n  //             name: '1',\n  //           },\n  //           {\n  //             name: '2'\n  //           }\n  //         ],\n  //         props: {\n  //           className: \"div-ut\",\n  //           onClick1: {\n  //             type: 'JSFunction',\n  //             value: '() => this.item.name',\n  //           },\n  //           onClick2: {\n  //             type: 'JSFunction',\n  //             value: 'function(){ return this.item.name }',\n  //           },\n  //           onClick3: {\n  //             type: 'JSFunction',\n  //             value: 'function(){ return item.name }',\n  //           },\n  //           onClick4: {\n  //             type: 'JSFunction',\n  //             value: '() => item.name',\n  //           }\n  //         }\n  //       }\n  //     ]\n  //   };\n\n  //   getComp(schema, components.Div).then(({ component, inst }) => {\n  //     // expect(inst[0].props.visible).toBeTruthy();\n  //     expect(inst.length).toEqual(2);\n  //     [1, 2, 3, 4].forEach((i) => {\n  //       expect(inst[0].props[`onClick${i}`]()).toBe('1');\n  //       expect(inst[1].props[`onClick${i}`]()).toBe('2');\n  //     })\n  //     componentSnapshot = component;\n  //     done();\n  //   });\n  // });\n\n  it('JSFunction props', (done) => {\n    const schema = {\n      componentName: 'Page',\n      props: {},\n      state: {\n        isShowDialog: true,\n      },\n      children: [\n        {\n          componentName: \"Div\",\n          props: {\n            className: \"div-ut\",\n            onClick: {\n              type: 'JSFunction',\n              value: 'function() {return this.state.isShowDialog}',\n            },\n          }\n        }\n      ]\n    };\n\n    getComp(schema, components.Div).then(({ component, inst }) => {\n      expect(!!inst[0].props.onClick).toBeTruthy();\n      expect(inst[0].props.onClick()).toBeTruthy();\n\n      componentSnapshot = component;\n      done();\n    });\n  });\n\n  it('JSSlot has loop', (done) => {\n    const schema = {\n      componentName: \"Page\",\n      props: {},\n      children: [\n        {\n          componentName: \"SlotComponent\",\n          id: \"node_k8bnubvz\",\n          props: {\n            mobileSlot: {\n              type: \"JSSlot\",\n              title: \"mobile容器\",\n              name: \"mobileSlot\",\n              value: [\n                {\n                  condition: true,\n                  hidden: false,\n                  children: [\n                    {\n                      condition: true,\n                      hidden: false,\n                      loopArgs: [\n                        \"item\",\n                        \"index\"\n                        ],\n                        isLocked: false,\n                        conditionGroup: \"\",\n                        componentName: \"Text\",\n                        id: \"node_ocl1ao1o7w4\",\n                        title: \"\",\n                        props: {\n                          maxLine: 0,\n                          showTitle: false,\n                          className: \"text_l1ao7pfb\",\n                          behavior: \"NORMAL\",\n                          content: \"这是一个低代码业务组件~\",\n                          __style__: \":root {\\n font-size: 14px;\\n color: #666;\\n}\",\n                          fieldId: \"text_l1ao7lvp\"\n                        }\n                    }\n                  ],\n                  loop: {\n                    type: \"JSExpression\",\n                    value: \"this.state.content\"\n                  },\n                  loopArgs: [\n                      \"item\",\n                      \"index\"\n                  ],\n                  isLocked: false,\n                  conditionGroup: \"\",\n                  componentName: \"Div\",\n                  id: \"node_ocl1ao1o7w3\",\n                  title: \"\",\n                  props: {\n                    useFieldIdAsDomId: false,\n                    customClassName: \"\",\n                    className: \"div_l1ao7pfc\",\n                    behavior: \"NORMAL\",\n                    __style__: \":root {\\n padding: 12px;\\n background: #f2f2f2;\\n border: 1px solid #ddd;\\n}\",\n                    fieldId: \"div_l1ao7lvq\"\n                  }\n                }\n              ]\n            },\n          },\n        }\n      ],\n      state: {\n        content: {\n          type: \"JSExpression\",\n          value: \"[{}, {}, {}]\",\n        },\n      },\n    };\n\n    getComp(schema, components.Div).then(({ component, inst }) => {\n      expect(inst.length).toBe(3);\n      componentSnapshot = component;\n      done();\n    });\n  })\n});\n\ndescribe(\"designMode\", () => {\n  it('designMode:default', (done) => {\n    const schema = {\n      componentName: 'Page',\n      props: {},\n      children: [\n        {\n          componentName: \"Div\",\n          props: {\n            className: 'div-ut',\n            children: [\n              {\n                componentName: \"Div\",\n                visible: true,\n                props: {\n                  className: 'div-ut-children',\n                }\n              }\n            ]\n          }\n        }\n      ]\n    };\n\n    getComp(schema, components.Div).then(({ component, inst }) => {\n      expect(inst.length).toBe(2);\n      expect(inst[0].props.className).toBe('div-ut');\n      expect(inst[1].props.className).toBe('div-ut-children');\n      componentSnapshot = component;\n      done();\n    });\n  });\n  it('designMode:design', (done) => {\n    const schema = {\n      componentName: 'Page',\n      props: {},\n      children: [\n        {\n          componentName: \"Div\",\n          id: '0',\n          props: {\n            className: 'div-ut',\n            children: [\n              {\n                componentName: \"Div\",\n                id: 'hiddenId',\n                hidden: true,\n                props: {\n                  className: 'div-ut-children',\n                }\n              }\n            ]\n          }\n        }\n      ]\n    };\n\n    getComp(schema, components.Div, {\n      designMode: 'design',\n      getNode: (id) => {\n        if (id === 'hiddenId') {\n          return {\n            export() {\n              return {\n                hidden: true,\n              };\n            }\n          }\n        }\n      }\n    }).then(({ component, inst }) => {\n      expect(inst.length).toBe(1);\n      expect(inst[0].props.className).toBe('div-ut');\n      done();\n    });\n  });\n})"
  },
  {
    "path": "packages/renderer-core/tests/setup.ts",
    "content": "jest.mock('lodash', () => {\n  const original = jest.requireActual('lodash');\n\n  return {\n    ...original,\n    debounce: (fn) => (...args: any[]) => fn.apply(this, args),\n    throttle: (fn) => (...args: any[]) => fn.apply(this, args),\n  }\n})\n\nexport const mockConsoleWarn = jest.fn();\nconsole.warn = mockConsoleWarn;\n\nprocess.env.NODE_ENV = 'production';"
  },
  {
    "path": "packages/renderer-core/tests/utils/common.test.ts",
    "content": "import {\n  isSchema,\n  isFileSchema,\n  inSameDomain,\n  getFileCssName,\n  isJSSlot,\n  getValue,\n  getI18n,\n  transformArrayToMap,\n  transformStringToFunction,\n  isVariable,\n  capitalizeFirstLetter,\n  forEach,\n  isString,\n  serializeParams,\n  parseExpression,\n  parseThisRequiredExpression,\n  parseI18n,\n  parseData,\n} from '../../src/utils/common';\nimport logger from '../../src/utils/logger';\n\ndescribe('test isSchema', () => {\n  it('should be false when empty value is passed', () => {\n    expect(isSchema(null)).toBeFalsy();\n    expect(isSchema(undefined)).toBeFalsy();\n    expect(isSchema('')).toBeFalsy();\n    expect(isSchema({})).toBeFalsy();\n  });\n\n  it('should be true when componentName is Leaf or Slot ', () => {\n    expect(isSchema({ componentName: 'Leaf' })).toBeTruthy();\n    expect(isSchema({ componentName: 'Slot' })).toBeTruthy();\n  });\n\n  it('should check each item of an array', () => {\n    const validArraySchema = [\n      { componentName: 'Button', props: {}},\n      { componentName: 'Button', props: { type: 'JSExpression' }},\n      { componentName: 'Leaf' },\n      { componentName: 'Slot'},\n    ];\n    const invalidArraySchema = [\n      ...validArraySchema,\n      { componentName: 'ComponentWithoutProps'},\n    ];\n    expect(isSchema(validArraySchema)).toBeTruthy();\n    expect(isSchema(invalidArraySchema)).toBeFalsy();\n  });\n\n  it('normal valid schema should contains componentName, and props of type object or JSExpression', () => {\n    expect(isSchema({ componentName: 'Button', props: {}})).toBeTruthy();\n    expect(isSchema({ componentName: 'Button', props: { type: 'JSExpression' }})).toBeTruthy();\n    expect(isSchema({ xxxName: 'Button'})).toBeFalsy();\n    expect(isSchema({ componentName: 'Button', props: null})).toBeFalsy();\n    expect(isSchema({ componentName: 'Button', props: []})).toBeFalsy();\n    expect(isSchema({ componentName: 'Button', props: 'props string'})).toBeFalsy();\n  });\n});\n\ndescribe('test isFileSchema ', () => {\n  it('should be false when invalid schema is passed', () => {\n    expect(isFileSchema({ xxxName: 'Button'})).toBeFalsy();\n    expect(isFileSchema({ componentName: 'Button', props: null})).toBeFalsy();\n    expect(isFileSchema({ componentName: 'Button', props: []})).toBeFalsy();\n    expect(isFileSchema({ componentName: 'Button', props: 'props string'})).toBeFalsy();\n  });\n  it('should be true only when schema with root named Page || Block || Component is passed', () => {\n    expect(isFileSchema({ componentName: 'Page', props: {}})).toBeTruthy();\n    expect(isFileSchema({ componentName: 'Block', props: {}})).toBeTruthy();\n    expect(isFileSchema({ componentName: 'Component', props: {}})).toBeTruthy();\n    expect(isFileSchema({ componentName: 'Button', props: {}})).toBeFalsy();\n  });\n});\n\ndescribe('test inSameDomain ', () => {\n  let windowSpy;\n\n  beforeEach(() => {\n    windowSpy = jest.spyOn(window, \"window\", \"get\");\n  });\n\n  afterEach(() => {\n    windowSpy.mockRestore();\n  });\n  it('should work', () => {\n\n    windowSpy.mockImplementation(() => ({\n      parent: {\n        location: {\n          host: \"example.com\"\n        },\n      },\n      location: {\n        host: \"example.com\"\n      }\n    }));\n    expect(inSameDomain()).toBeTruthy();\n\n    windowSpy.mockImplementation(() => ({\n      parent: {\n        location: {\n          host: \"example.com\"\n        },\n      },\n      location: {\n        host: \"another.com\"\n      }\n    }));\n    expect(inSameDomain()).toBeFalsy();\n\n    windowSpy.mockImplementation(() => ({\n      parent: null,\n      location: {\n        host: \"example.com\"\n      }\n    }));\n\n    expect(inSameDomain()).toBeFalsy();\n  });\n});\n\n\ndescribe('test getFileCssName ', () => {\n  it('should work', () => {\n    expect(getFileCssName(null)).toBe(undefined);\n    expect(getFileCssName(undefined)).toBe(undefined);\n    expect(getFileCssName('')).toBe(undefined);\n    expect(getFileCssName('FileName')).toBe('lce-file-name');\n    expect(getFileCssName('Page1_abc')).toBe('lce-page1_abc');\n  });\n});\n\n\ndescribe('test isJSSlot ', () => {\n  it('should work', () => {\n    expect(isJSSlot(null)).toBeFalsy();\n    expect(isJSSlot(undefined)).toBeFalsy();\n    expect(isJSSlot('stringValue')).toBeFalsy();\n    expect(isJSSlot([1, 2, 3])).toBeFalsy();\n    expect(isJSSlot({ type: 'JSSlot' })).toBeTruthy();\n    expect(isJSSlot({ type: 'JSBlock' })).toBeTruthy();\n    expect(isJSSlot({ type: 'anyOtherType' })).toBeFalsy();\n  });\n});\n\ndescribe('test getValue ', () => {\n  it('should check params', () => {\n    expect(getValue(null, 'somePath')).toStrictEqual({});\n    expect(getValue(undefined, 'somePath')).toStrictEqual({});\n    // array is not valid input, return default\n    expect(getValue([], 'somePath')).toStrictEqual({});\n    expect(getValue([], 'somePath', 'aaa')).toStrictEqual('aaa');\n    expect(getValue([1, 2, 3], 'somePath', 'aaa')).toStrictEqual('aaa');\n\n    expect(getValue({}, 'somePath')).toStrictEqual({});\n    expect(getValue({}, 'somePath', 'default')).toStrictEqual('default');\n  });\n  it('should work normally', () => {\n    // single segment path\n    expect(getValue({ a: 'aValue' }, 'a')).toStrictEqual('aValue');\n    expect(getValue({ a: 'aValue', f:null }, 'f')).toBeNull();\n    expect(getValue({ a: { b: 'bValue' } }, 'a.b')).toStrictEqual('bValue');\n    expect(getValue({ a: { b: 'bValue', c: { d: 'dValue' } } }, 'a.c.d')).toStrictEqual('dValue');\n    expect(getValue({ a: { b: 'bValue', c: { d: 'dValue' } } }, 'e')).toStrictEqual({});\n  });\n});\n\ndescribe('test getI18n ', () => {\n  it('should work', () => {\n    const messages = {\n      'zh-CN': {\n        'key1': '啊啊啊',\n        'key2': '哈哈哈',\n      },\n    };\n    expect(getI18n('keyString', {}, 'zh-CN')).toStrictEqual('');\n    expect(getI18n('keyString', {}, 'zh-CN', null)).toStrictEqual('');\n    expect(getI18n('keyString', {}, 'en-US', messages)).toStrictEqual('');\n    expect(getI18n('key3', {}, 'zh-CN', messages)).toStrictEqual('');\n  });\n});\n\n\ndescribe('test transformArrayToMap ', () => {\n  it('should work', () => {\n    expect(transformArrayToMap([])).toStrictEqual({});\n    expect(transformArrayToMap('not a array')).toStrictEqual({});\n    expect(transformArrayToMap({'not Array': 1})).toStrictEqual({});\n\n    let mockArray = [\n      {\n        name: 'jack', \n        age: 2,\n      },\n      {\n        name: 'jack', \n        age: 20,\n      }\n    ];\n    // test override\n    expect(transformArrayToMap(mockArray, 'name', true).jack.age).toBe(20);\n    expect(transformArrayToMap(mockArray, 'name').jack.age).toBe(20);\n    expect(transformArrayToMap(mockArray, 'name', false).jack.age).toBe(2);\n\n    mockArray = [\n      {\n        name: 'jack', \n        age: 2,\n      },\n      {\n        name: 'rose', \n        age: 20,\n      }\n    ];\n    // normal case\n    expect(transformArrayToMap(mockArray, 'name').jack.age).toBe(2);\n    expect(transformArrayToMap(mockArray, 'name').jack.name).toBe('jack');\n    expect(transformArrayToMap(mockArray, 'name').rose.age).toBe(20);\n    // key not exists\n    expect(transformArrayToMap(mockArray, 'nameEn')).toStrictEqual({});\n  });\n});\n\n\n\ndescribe('test transformStringToFunction ', () => {\n  it('should work', () => {\n    const mockFun = jest.fn();\n    expect(transformStringToFunction(mockFun)).toBe(mockFun);\n    expect(transformStringToFunction(111)).toBe(111);\n\n    let mockFnStr = 'function(){return 111;}';\n    let fn = transformStringToFunction(mockFnStr);\n    expect(fn()).toBe(111);\n\n    mockFnStr = '() => { return 222; }';\n    fn = transformStringToFunction(mockFnStr);\n    expect(fn()).toBe(222);\n\n    mockFnStr = 'function getValue() { return 333; }';\n    fn = transformStringToFunction(mockFnStr);\n    expect(fn()).toBe(333);\n\n    mockFnStr = 'function getValue(aaa) {\\\n       return aaa; \\\n    }';\n    fn = transformStringToFunction(mockFnStr);\n    expect(fn(123)).toBe(123);\n  });\n});\n\n\ndescribe('test isVariable ', () => {\n  it('should work', () => {\n    expect(isVariable(null)).toBeFalsy();\n    expect(isVariable(undefined)).toBeFalsy();\n    expect(isVariable([1, 2, 3])).toBeFalsy();\n    expect(isVariable({})).toBeFalsy();\n    expect(isVariable({ type: 'any other type' })).toBeFalsy();\n    expect(isVariable({ type: 'variable' })).toBeTruthy();\n  });\n});\n\ndescribe('test capitalizeFirstLetter ', () => {\n  it('should work', () => {\n    expect(capitalizeFirstLetter(null)).toBeNull();\n    expect(capitalizeFirstLetter()).toBeUndefined();\n    expect(capitalizeFirstLetter([1, 2, 3])).toStrictEqual([1, 2, 3]);\n    expect(capitalizeFirstLetter({ a: 1 })).toStrictEqual({ a: 1 });\n    expect(capitalizeFirstLetter('')).toStrictEqual('');\n    expect(capitalizeFirstLetter('a')).toStrictEqual('A');\n    expect(capitalizeFirstLetter('abcd')).toStrictEqual('Abcd');\n  });\n});\n\ndescribe('test forEach ', () => {\n  it('should work', () => {\n    const mockFn = jest.fn();\n\n    forEach(null, mockFn);\n    expect(mockFn).toBeCalledTimes(0);\n\n    forEach(undefined, mockFn);\n    expect(mockFn).toBeCalledTimes(0);\n\n    forEach([1, 2, 3], mockFn);\n    expect(mockFn).toBeCalledTimes(0);\n\n    forEach('stringValue', mockFn);\n    expect(mockFn).toBeCalledTimes(0);\n\n    forEach({ a: 1, b: 2, c: 3 }, mockFn);\n    expect(mockFn).toBeCalledTimes(3);\n\n    const mockFn2 = jest.fn();\n    forEach({ a: 1 }, mockFn2, { b: 'bbb' });\n    expect(mockFn2).toHaveBeenCalledWith(1, 'a');\n\n    let sum = 0;\n    const mockFn3 = function(value, key) { sum = value + this.b;  };\n    forEach({ a: 1 }, mockFn3, { b: 10 });\n    expect(sum).toEqual(11);\n  });\n});\n\ndescribe('test isString ', () => {\n  it('should work', () => {\n    expect(isString(123)).toBeFalsy();\n    expect(isString([])).toBeFalsy();\n    expect(isString({})).toBeFalsy();\n    expect(isString(null)).toBeFalsy();\n    expect(isString(undefined)).toBeFalsy();\n    expect(isString(true)).toBeFalsy();\n    expect(isString('111')).toBeTruthy();\n    expect(isString(new String('111'))).toBeTruthy();\n  });\n});\n\ndescribe('test serializeParams ', () => {\n  it('should work', () => {\n    const mockParams = { a: 1, b: 2, c: 'cvalue', d:[1, 'a', {}], e: {e1: 'value1', e2: 'value2'}};\n    const result = serializeParams(mockParams);\n    const decodedParams = decodeURIComponent(result);\n    expect(result).toBe('a=1&b=2&c=cvalue&d=%5B1%2C%22a%22%2C%7B%7D%5D&e=%7B%22e1%22%3A%22value1%22%2C%22e2%22%3A%22value2%22%7D');\n    expect(decodedParams).toBe('a=1&b=2&c=cvalue&d=[1,\"a\",{}]&e={\"e1\":\"value1\",\"e2\":\"value2\"}');\n  });\n});\n\ndescribe('test parseExpression ', () => {\n  it('can handle JSExpression', () => {\n    const mockExpression = {\n      \"type\": \"JSExpression\",\n      \"value\": \"function (params) { return this.scopeValue + params.param1 + 5;}\"\n    };\n    const result = parseExpression(mockExpression, { scopeValue: 1 });\n    expect(result({ param1: 2 })).toBe((1 + 2 + 5));\n  });\n\n  it('[success] JSExpression handle without this use scopeValue', () => {\n    const mockExpression = {\n      \"type\": \"JSExpression\",\n      \"value\": \"state\"\n    };\n    const result = parseExpression(mockExpression, { state: 1 });\n    expect(result).toBe((1));\n  });\n\n  it('[success] JSExpression handle without this use scopeValue', () => {\n    const mockExpression = {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.state\"\n    };\n    const result = parseExpression(mockExpression, { state: 1 });\n    expect(result).toBe((1));\n  });\n});\n\ndescribe('test parseThisRequiredExpression', () => {\n  it('can handle JSExpression', () => {\n    const mockExpression = {\n      \"type\": \"JSExpression\",\n      \"value\": \"function (params) { return this.scopeValue + params.param1 + 5;}\"\n    };\n    const result = parseThisRequiredExpression(mockExpression, { scopeValue: 1 });\n    expect(result({ param1: 2 })).toBe((1 + 2 + 5));\n  });\n\n  it('[error] JSExpression handle without this use scopeValue', () => {\n    const mockExpression = {\n      \"type\": \"JSExpression\",\n      \"value\": \"state.text\"\n    };\n    const fn = logger.error = jest.fn();\n    parseThisRequiredExpression(mockExpression, { state: { text: 'text' } });\n    expect(fn).toBeCalledWith(' parseExpression.error', new ReferenceError('state is not defined'), {\"type\": \"JSExpression\", \"value\": \"state.text\"}, {\"state\": {\"text\": \"text\"}});\n  });\n\n  it('[success] JSExpression handle without this use scopeValue', () => {\n    const mockExpression = {\n      \"type\": \"JSExpression\",\n      \"value\": \"this.state\"\n    };\n    const result = parseThisRequiredExpression(mockExpression, { state: 1 });\n    expect(result).toBe((1));\n  });\n})\n\ndescribe('test parseI18n ', () => {\n  it('can handle normal parseI18n', () => {\n    const mockI18n = {\n      \"type\": \"i18n\",\n      \"key\": \"keyA\"\n    };\n    const mockI18nFun = (key) => { return 'hahaha' + key;};\n    const result = parseI18n(mockI18n, { i18n: mockI18nFun });\n    expect(result).toBe('hahahakeyA');\n  });\n});\n\ndescribe('test parseData ', () => {\n  it('should work when isJSExpression === true', () => {\n    const mockExpression = {\n      \"type\": \"JSExpression\",\n      \"value\": \"function (params) { return this.scopeValue + params.param1 + 5;}\"\n    };\n    const result = parseData(mockExpression, { scopeValue: 1 });\n    expect(result({ param1: 2 })).toBe((1 + 2 + 5));\n  });\n  it('should work when isI18nData === true', () => {\n    const mockI18n = {\n      \"type\": \"i18n\",\n      \"key\": \"keyA\"\n    };\n    const mockI18nFun = (key) => { return 'hahaha' + key;};\n    const result = parseData(mockI18n, { i18n: mockI18nFun });\n    expect(result).toBe('hahahakeyA');\n  });\n  it('should work when schema is string', () => {\n    expect(parseData(' this is a normal string, will be trimmed only ')).toStrictEqual('this is a normal string, will be trimmed only');\n  });\n\n  it('should work when schema is array', () => {\n    const mockData = [\n      {\n        \"type\": \"i18n\",\n        \"key\": \"keyA\"\n      },\n      ' this is a normal string, will be trimmed only ',\n    ];\n\n    const mockI18nFun = (key) => { return 'hahaha' + key;};\n    const result = parseData(mockData, { i18n: mockI18nFun });\n\n    expect(result[0]).toStrictEqual('hahahakeyA');\n    expect(result[1]).toStrictEqual('this is a normal string, will be trimmed only');\n  });\n  it('should work when schema is function', () => {\n    const mockFn = function() { return this.a; };\n    const result = parseData(mockFn, { a: 111 });\n    expect(result()).toBe(111);\n  });\n  it('should work when schema is null or undefined', () => {\n    expect(parseData(null)).toBe(null);\n    expect(parseData(undefined)).toBe(undefined);\n  });\n  it('should work when schema is normal object', () => {\n    expect(parseData({})).toStrictEqual({});\n    const mockI18nFun = (key) => { return 'hahaha' + key;};\n    const result = parseData({\n      key1: {\n        \"type\": \"i18n\",\n        \"key\": \"keyA\"\n      },\n      key2: ' this is a normal string, will be trimmed only ',\n      __privateKey: 'any value',\n    }, { i18n: mockI18nFun });\n    expect(result.key1).toStrictEqual('hahahakeyA');\n    expect(result.key2).toStrictEqual('this is a normal string, will be trimmed only');\n    expect(result.__privateKey).toBeUndefined();\n\n  });\n});\n"
  },
  {
    "path": "packages/renderer-core/tests/utils/components.tsx",
    "content": "import React from 'react';\nimport { Box, Breadcrumb, Form, Select, Input, Button, Table, Pagination, Dialog } from '@alifd/next';\n\nconst Div = ({_leaf, ...rest}: any) => (<div {...rest}>{rest.children}</div>);\n\nconst MiniRenderDiv = ({_leaf, ...rest}: any) => {\n  return (\n    <div {...rest}>\n      {rest.children}\n    </div>\n  );\n};\n\nconst Text = ({_leaf, ...rest}: any) => (<div {...rest}>{rest.content}</div>);\n\nconst SlotComponent = (props: any) => props.mobileSlot;\n\nconst components = {\n  Box,\n  Breadcrumb,\n  'Breadcrumb.Item': Breadcrumb.Item,\n  Form,\n  'Form.Item': Form.Item,\n  Select,\n  Input,\n  Button,\n  'Button.Group': Button.Group,\n  Table,\n  Pagination,\n  Dialog,\n  ErrorComponent: Select,\n  Div,\n  SlotComponent,\n  Text,\n  MiniRenderDiv,\n};\n\nexport default components;\n"
  },
  {
    "path": "packages/renderer-core/tests/utils/data-helper.test.ts",
    "content": "// @ts-nocheck\nconst mockJsonp = jest.fn();\nconst mockRequest = jest.fn();\nconst mockGet = jest.fn();\nconst mockPost = jest.fn();\njest.mock('../../src/utils/request', () => {\n    return {\n      jsonp: (uri, params, headers, otherProps) => { \n        return new Promise((resolve, reject) => {\n          resolve(mockJsonp(uri, params, headers, otherProps));\n        });\n      },\n      request: (uri, params, headers, otherProps) => { \n        return new Promise((resolve, reject) => {\n          resolve(mockRequest(uri, params, headers, otherProps));\n        });\n      },\n      get: (uri, params, headers, otherProps) => { \n        return new Promise((resolve, reject) => {\n          resolve(mockGet(uri, params, headers, otherProps));\n        });\n      },\n      post: (uri, params, headers, otherProps) => { \n        return new Promise((resolve, reject) => {\n          resolve(mockPost(uri, params, headers, otherProps));\n        });\n      },\n    };\n  });\n\nimport { DataHelper, doRequest } from '../../src/utils/data-helper';\nimport { parseData } from '../../src/utils/common';\n\ndescribe('test DataHelper ', () => {\n  beforeEach(() => {\n    jest.resetModules();\n  })\n  it('can be inited', () => {\n    const mockHost = {};\n    let mockDataSourceConfig = {};\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n    let dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n\n    expect(dataHelper).toBeTruthy();\n    expect(dataHelper.host).toBe(mockHost);\n    expect(dataHelper.config).toBe(mockDataSourceConfig);\n    expect(dataHelper.appHelper).toBe(mockAppHelper);\n    expect(dataHelper.parser).toBe(mockParser);\n\n\n    dataHelper = new DataHelper(mockHost, undefined, mockAppHelper, mockParser);\n    expect(dataHelper.config).toStrictEqual({});\n    expect(dataHelper.ajaxList).toStrictEqual([]);\n\n    mockDataSourceConfig = { \n      list: [ \n        {\n          id: 'ds1',\n        }, {\n          id: 'ds2',\n        },\n      ]\n    };\n    dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n    expect(dataHelper.config).toBe(mockDataSourceConfig);\n    expect(dataHelper.ajaxList.length).toBe(2);\n    expect(dataHelper.ajaxMap.ds1).toStrictEqual({\n      id: 'ds1',\n    });\n  });\n  it('should handle generateDataSourceMap properly in constructor', () => {\n    const mockHost = {};\n    let mockDataSourceConfig = {};\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n    let dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n\n    // test generateDataSourceMap logic\n    mockDataSourceConfig = { \n      list: [ \n        {\n          id: 'getInfo',\n          isInit: true,\n          type: 'fetch',  // fetch/mtop/jsonp/custom\n          options: {\n            uri: 'mock/info.json',\n            method: 'GET',\n            params: { a: 1 },\n            timeout: 5000,\n          },\n        }, {\n          id: 'postInfo',\n          isInit: true,\n          type: 'fetch',\n          options: {\n            uri: 'mock/info.json',\n            method: 'POST',\n            params: { a: 1 },\n            timeout: 5000,\n          },\n        },\n      ]\n    };\n    dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n    expect(Object.keys(dataHelper.dataSourceMap).length).toBe(2);\n    expect(dataHelper.dataSourceMap.getInfo.status).toBe('init');\n    expect(typeof dataHelper.dataSourceMap.getInfo.load).toBe('function');\n  });\n\n  it('getInitDataSourseConfigs should work', () => {\n    const mockHost = {};\n    let mockDataSourceConfig = {};\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n\n    // test generateDataSourceMap logic\n    mockDataSourceConfig = { \n      list: [ \n        {\n          id: 'getInfo',\n          isInit: true,\n          type: 'fetch',  // fetch/mtop/jsonp/custom\n          options: {\n            uri: 'mock/info.json',\n            method: 'GET',\n            params: { a: 1 },\n            timeout: 5000,\n          },\n        }, \n        {\n          id: 'postInfo',\n          isInit: false,\n          type: 'fetch',\n          options: {\n            uri: 'mock/info.json',\n            method: 'POST',\n            params: { a: 1 },\n            timeout: 5000,\n          },\n        }, \n        {\n          id: 'getInfoLater',\n          isInit: false,\n          type: 'fetch',\n          options: {\n            uri: 'mock/info.json',\n            method: 'POST',\n            params: { a: 1 },\n            timeout: 5000,\n          },\n        },\n        {\n          id: 'getInfoLater2',\n          isInit: 'not a valid boolean',\n          type: 'fetch',\n          options: {\n            uri: 'mock/info.json',\n            method: 'POST',\n            params: { a: 1 },\n            timeout: 5000,\n          },\n        },\n      ],\n    };\n\n    const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n    expect(dataHelper.getInitDataSourseConfigs().length).toBe(1);\n    expect(dataHelper.getInitDataSourseConfigs()[0].id).toBe('getInfo');\n  });\n  it('util function doRequest should work', () => {\n    doRequest('jsonp', {\n      uri: 'https://www.baidu.com',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockJsonp).toBeCalled();\n\n    // test GET\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      method: 'get',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockGet).toBeCalled();\n\n    mockGet.mockClear();\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      method: 'Get',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockGet).toBeCalled();\n\n    mockGet.mockClear();\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      method: 'GET',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockGet).toBeCalled();\n\n    mockGet.mockClear();\n\n    // test POST\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      method: 'post',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockPost).toBeCalled();\n    mockPost.mockClear();\n\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      method: 'POST',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockPost).toBeCalled();\n    mockPost.mockClear();\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      method: 'Post',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockPost).toBeCalled();\n    mockPost.mockClear();\n\n    // test default\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      method: 'whatever',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockRequest).toBeCalled();\n    mockRequest.mockClear();\n    mockGet.mockClear();\n    \n    // method will be GET when not provided\n    doRequest('fetch', {\n      uri: 'https://www.baidu.com',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockRequest).toBeCalledTimes(0);\n    expect(mockGet).toBeCalledTimes(1);\n\n    mockRequest.mockClear();\n    mockGet.mockClear();\n    mockPost.mockClear();\n    mockJsonp.mockClear();\n\n    doRequest('someOtherType', {\n      uri: 'https://www.baidu.com',\n      params: { a: 1 },\n      otherStuff1: 'aaa',\n    });\n    expect(mockRequest).toBeCalledTimes(0);\n    expect(mockGet).toBeCalledTimes(0);\n    expect(mockPost).toBeCalledTimes(0);\n    expect(mockJsonp).toBeCalledTimes(0);\n  });\n  it('updateDataSourceMap should work', () => {\n    const mockHost = {};\n    const mockDataSourceConfig = { \n      list: [ \n        {\n          id: 'ds1',\n        }, {\n          id: 'ds2',\n        },\n      ]\n    };\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n    const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n    dataHelper.updateDataSourceMap('ds1', { a: 1 }, null);\n    expect(dataHelper.dataSourceMap['ds1']).toBeTruthy();\n    expect(dataHelper.dataSourceMap['ds1'].data).toStrictEqual({ a: 1 });\n    expect(dataHelper.dataSourceMap['ds1'].error).toBeUndefined();\n    expect(dataHelper.dataSourceMap['ds1'].status).toBe('loaded');\n    dataHelper.updateDataSourceMap('ds2', { b: 2 }, new Error());\n    expect(dataHelper.dataSourceMap['ds2']).toBeTruthy();\n    expect(dataHelper.dataSourceMap['ds2'].data).toStrictEqual({ b: 2 });\n    expect(dataHelper.dataSourceMap['ds2'].status).toBe('error');\n    expect(dataHelper.dataSourceMap['ds2'].error).toBeTruthy();\n  });\n\n  it('handleData should work', () => {\n    const mockHost = { stateA: 'aValue'};\n    const mockDataSourceConfig = { \n      list: [\n        {\n          id: 'fullConfigGet',\n          isInit: true,\n          options: {\n            params: {},\n            method: 'GET',\n            isCors: true,\n            timeout: 5000,\n            headers: {},\n            uri: 'mock/info.json',\n          },\n          shouldFetch: {\n            type: 'JSFunction',\n            value: 'function() { return true; }',\n          },\n          dataHandler: {\n            type: 'JSFunction',\n            value: 'function(res) { return res.data; }',\n          },\n          errorHandler: {\n            type: 'JSFunction',\n            value: 'function(error) {}',\n          },\n          willFetch: {\n            type: 'JSFunction',\n            value: 'function(options) { return options; }',\n          },\n        },\n      ]\n    };\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n    const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n    // test valid case\n    let mockDataHandler = {\n      type: 'JSFunction',\n      value: 'function(res) { return res.data + \\'+\\' + this.stateA; }',\n    };\n    let result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);\n    expect(result).toBe('mockDataValue+aValue');\n\n    // test invalid datahandler\n    mockDataHandler = {\n      type: 'not a JSFunction',\n      value: 'function(res) { return res.data + \\'+\\' + this.stateA; }',\n    };\n    result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);\n    expect(result).toStrictEqual({ data: 'mockDataValue' });\n\n    // exception with id\n    mockDataHandler = {\n      type: 'JSFunction',\n      value: 'function(res) { return res.data + \\'+\\' + JSON.parse({a:1}); }',\n    };\n    result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);\n    expect(result).toBeUndefined();\n\n    // exception without id\n    mockDataHandler = {\n      type: 'JSFunction',\n      value: 'function(res) { return res.data + \\'+\\' + JSON.parse({a:1}); }',\n    };\n    result = dataHelper.handleData(null, mockDataHandler, { data: 'mockDataValue' }, null);\n    expect(result).toBeUndefined();\n  });\n\n  it('updateConfig should work', () => {\n    const mockHost = { stateA: 'aValue'};\n    const mockDataSourceConfig = { \n      list: [\n        {\n          id: 'ds1',\n        }, {\n          id: 'ds2',\n        },\n        {\n          id: 'fullConfigGet',\n          isInit: true,\n          options: {\n            params: {},\n            method: 'GET',\n            isCors: true,\n            timeout: 5000,\n            headers: {},\n            uri: 'mock/info.json',\n          },\n          shouldFetch: {\n            type: 'JSFunction',\n            value: 'function() { return true; }',\n          },\n          dataHandler: {\n            type: 'JSFunction',\n            value: 'function(res) { return res.data; }',\n          },\n          errorHandler: {\n            type: 'JSFunction',\n            value: 'function(error) {}',\n          },\n          willFetch: {\n            type: 'JSFunction',\n            value: 'function(options) { return options; }',\n          },\n        },\n      ]\n    };\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n    const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n\n    expect(dataHelper.ajaxList.length).toBe(3);\n\n    let updatedConfig = { \n      list: [\n        {\n          id: 'ds2',\n        },\n        {\n          id: 'fullConfigGet',\n        },\n      ]\n    };\n    dataHelper.updateConfig(updatedConfig);\n\n    expect(dataHelper.ajaxList.length).toBe(2);\n    expect(dataHelper.dataSourceMap.ds1).toBeUndefined();\n\n    updatedConfig = { \n      list: [\n        {\n          id: 'ds2',\n        },\n        {\n          id: 'fullConfigGet',\n        },\n        {\n          id: 'ds3',\n        },\n      ]\n    };\n    dataHelper.updateConfig(updatedConfig);\n    expect(dataHelper.ajaxList.length).toBe(3);\n    expect(dataHelper.dataSourceMap.ds3).toBeTruthy();\n  });\n\n  it('getInitData should work', () => {\n    const mockHost = { stateA: 'aValue'};\n    const mockDataSourceConfig = { \n      list: [\n        {\n          id: 'ds1',\n        }, {\n          id: 'ds2',\n        },\n        {\n          id: 'fullConfigGet',\n          isInit: true,\n          type: 'fetch',\n          options: {\n            params: {},\n            method: 'GET',\n            isCors: true,\n            timeout: 5000,\n            headers: {\n              headerA: 1,\n            },\n            uri: 'mock/info.json',\n          },\n          shouldFetch: {\n            type: 'JSFunction',\n            value: 'function() { return true; }',\n          },\n          dataHandler: {\n            type: 'JSFunction',\n            value: 'function(res) { return 123; }',\n          },\n          errorHandler: {\n            type: 'JSFunction',\n            value: 'function(error) {}',\n          },\n          willFetch: {\n            type: 'JSFunction',\n            value: 'function(options) { return options; }',\n          },\n        },\n      ]\n    };\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n    const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n\n    expect(dataHelper.ajaxList.length).toBe(3);\n    expect(mockGet).toBeCalledTimes(0);\n    dataHelper.getInitData().then(res => {\n      expect(mockGet).toBeCalledTimes(1);\n      expect(mockGet).toBeCalledWith('mock/info.json', {}, {\n        headerA: 1,\n      }, expect.anything());\n      mockGet.mockClear();\n    });\n  });\n\n  it('getDataSource should work', () => {\n    const mockHost = { stateA: 'aValue'};\n    const mockDataSourceConfig = { \n      list: [\n        {\n          id: 'ds1',\n        }, {\n          id: 'ds2',\n        },\n        {\n          id: 'fullConfigGet',\n          isInit: true,\n          type: 'fetch',\n          options: {\n            params: {},\n            method: 'GET',\n            isCors: true,\n            timeout: 5000,\n            headers: {\n              headerA: 1,\n            },\n            uri: 'mock/info.json',\n          },\n          shouldFetch: {\n            type: 'JSFunction',\n            value: 'function() { return true; }',\n          },\n          dataHandler: {\n            type: 'JSFunction',\n            value: 'function(res) { return 123; }',\n          },\n          errorHandler: {\n            type: 'JSFunction',\n            value: 'function(error) {}',\n          },\n          willFetch: {\n            type: 'JSFunction',\n            value: 'function(options) { return options; }',\n          },\n        },\n      ]\n    };\n    const mockAppHelper = {};\n    const mockParser = (config: any) => parseData(config);\n    const dataHelper = new DataHelper(mockHost, mockDataSourceConfig, mockAppHelper, mockParser);\n\n    expect(dataHelper.ajaxList.length).toBe(3);\n    expect(mockGet).toBeCalledTimes(0);\n    const callbackFn = jest.fn();\n    dataHelper.getDataSource('fullConfigGet', { param1: 'value1' }, {}, callbackFn).then(res => {\n      expect(mockGet).toBeCalledTimes(1);\n      expect(mockGet).toBeCalledWith('mock/info.json', { param1: 'value1' }, {\n        headerA: 1,\n      }, expect.anything());\n      mockGet.mockClear();\n      expect(callbackFn).toBeCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/renderer-core/tests/utils/is-use-loop.test.ts",
    "content": "// @ts-nocheck\nimport isUseLoop from '../../src/utils/is-use-loop';\n\ndescribe('base test', () => {\n  it('designMode is true', () => {\n    expect(isUseLoop([], true)).toBeFalsy();\n    expect(isUseLoop([{}], true)).toBeTruthy();\n    expect(isUseLoop(null, true)).toBeFalsy();\n    expect(isUseLoop(undefined, true)).toBeFalsy();\n    expect(isUseLoop(0, true)).toBeFalsy();\n  });\n\n  it('loop is expression', () => {\n    expect(isUseLoop({\n      \"type\": \"JSExpression\",\n      \"value\": \"function() { console.log('componentDidMount'); }\"\n    }, true)).toBeTruthy();\n    expect(isUseLoop({\n      \"type\": \"JSExpression\",\n      \"value\": \"function() { console.log('componentDidMount'); }\"\n    }, false)).toBeTruthy();\n  });\n\n  it('designMode is false', () => {\n    expect(isUseLoop([], false)).toBeTruthy();\n    expect(isUseLoop([{}], false)).toBeTruthy();\n    expect(isUseLoop(null, false)).toBeTruthy();\n    expect(isUseLoop(undefined, false)).toBeTruthy();\n    expect(isUseLoop(0, false)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "packages/renderer-core/tests/utils/node.ts",
    "content": "import { IPublicTypePropChangeOptions } from \"@ali/lowcode-designer\";\nimport EventEmitter from \"events\";\n\nexport default class Node {\n  private emitter: EventEmitter;\n  schema: any = {\n    props: {},\n  };\n\n  componentMeta = {};\n\n  parent;\n\n  hasLoop = () => this._hasLoop;\n\n  id;\n\n  _isRoot: false;\n\n  _hasLoop: false;\n\n  constructor(schema: any, info: any = {}) {\n    this.emitter = new EventEmitter();\n    const {\n      componentMeta,\n      parent,\n      isRoot,\n      hasLoop,\n    } = info;\n    this.schema = {\n      props: {},\n      ...schema,\n    };\n    this.componentMeta = componentMeta || {};\n    this.parent = parent;\n    this.id = schema.id;\n    this._isRoot = isRoot;\n    this._hasLoop = hasLoop;\n  }\n\n  isRoot = () => this._isRoot;\n\n  get isRootNode () {\n    return this._isRoot;\n  };\n\n  // componentMeta() {\n  //   return this.componentMeta;\n  // }\n\n  // mockLoop() {\n  //   // this.hasLoop = true;\n  // }\n\n  onChildrenChange(fn: any) {\n    this.emitter.on('onChildrenChange', fn);\n    return () => {\n      this.emitter.off('onChildrenChange', fn);\n    }\n  }\n\n  emitChildrenChange() {\n    this.emitter?.emit('onChildrenChange', {});\n  }\n\n  onPropChange(fn: any) {\n    this.emitter.on('onPropChange', fn);\n    return () => {\n      this.emitter.off('onPropChange', fn);\n    }\n  }\n\n  emitPropChange(val: IPublicTypePropChangeOptions, skip?: boolean) {\n    if (!skip) {\n      this.schema.props = {\n        ...this.schema.props,\n        [val.key + '']: val.newValue,\n      }\n    }\n\n    this.emitter?.emit('onPropChange', val);\n  }\n\n  onVisibleChange(fn: any) {\n    this.emitter.on('onVisibleChange', fn);\n    return () => {\n      this.emitter.off('onVisibleChange', fn);\n    }\n  }\n\n  emitVisibleChange(val: boolean) {\n    this.emitter?.emit('onVisibleChange', val);\n  }\n  export() {\n    return this.schema;\n  }\n}"
  },
  {
    "path": "packages/renderer-core/tests/utils/react-env-init.ts",
    "content": "import React, { Component, PureComponent, createElement, createContext, forwardRef, ReactInstance, ContextType } from 'react';\nimport ReactDOM from 'react-dom';\nimport {\n  adapter,\n  pageRendererFactory,\n  componentRendererFactory,\n  blockRendererFactory,\n  addonRendererFactory,\n  tempRendererFactory,\n  // rendererFactory,\n  // types,\n} from '../../src';\nimport ConfigProvider from '@alifd/next/lib/config-provider';\n\n(window as any).React = React;\n(window as any).ReactDom = ReactDOM;\n\nadapter.setRuntime({\n  Component,\n  PureComponent,\n  createContext,\n  createElement,\n  forwardRef,\n  findDOMNode: ReactDOM.findDOMNode,\n});\n\nadapter.setRenderers({\n  PageRenderer: pageRendererFactory(),\n  ComponentRenderer: componentRendererFactory(),\n  BlockRenderer: blockRendererFactory(),\n  AddonRenderer: addonRendererFactory(),\n  TempRenderer: tempRendererFactory(),\n  DivRenderer: blockRendererFactory(),\n});\n\nadapter.setConfigProvider(ConfigProvider);\n\n// function factory(): types.IRenderComponent {\n//   const Renderer = rendererFactory();\n//   return class ReactRenderer extends Renderer implements Component {\n//     readonly props: types.IRendererProps;\n\n//     context: ContextType<any>;\n\n//     setState: (\n//       state: types.IRendererState,\n//       callback?: () => void,\n//     ) => void;\n\n//     forceUpdate: (callback?: () => void) => void;\n\n//     refs: {\n//       [key: string]: ReactInstance;\n//     };\n\n//     constructor(props: types.IRendererProps, context: ContextType<any>) {\n//       super(props, context);\n//     }\n\n//     isValidComponent(obj: any) {\n//       return obj?.prototype?.isReactComponent || obj?.prototype instanceof Component;\n//     }\n//   };\n// }\n\n// export default factory();\n"
  },
  {
    "path": "packages/renderer-core/tests/utils/request.test.ts",
    "content": "// @ts-nocheck\nconst mockSerializeParams = jest.fn();\njest.mock('../../src/utils/common', () => {\n    return {\n      serializeParams: (params) => { \n        return mockSerializeParams(params);\n      },\n    };\n  });\nconst mockFetchJsonp = jest.fn();\njest.mock('fetch-jsonp', () => {\n  return (uri, otherProps) => { \n    mockFetchJsonp(uri, otherProps);\n    return Promise.resolve({ \n      json: () => { \n        return Promise.resolve({ data: [1, 2, 3]});\n      } ,\n      ok: true,\n    });\n  }\n});\n\nimport { get, post, buildUrl, request, jsonp  } from '../../src/utils/request';\n\n\ndescribe('test utils/request.ts ', () => {\n\n  it('buildUrl should be working properly', () => {\n    mockSerializeParams.mockImplementation((params) => {\n      return 'serializedParams=serializedParams';\n    });\n    expect(buildUrl('mockDataApi', { a: 1, b: 'a', c: []})).toBe('mockDataApi?serializedParams=serializedParams');\n    expect(buildUrl('mockDataApi?existingParamA=valueA', { a: 1, b: 'a', c: []})).toBe('mockDataApi?existingParamA=valueA&serializedParams=serializedParams');\n    mockSerializeParams.mockClear();\n\n    mockSerializeParams.mockImplementation((params) => {\n      return undefined;\n    });\n    expect(buildUrl('mockDataApi', { a: 1, b: 'a', c: []})).toBe('mockDataApi');\n    mockSerializeParams.mockClear();\n  });\n \n  it('request should be working properly', () => {\n    const fetchMock = jest\n      .spyOn(global, 'fetch')\n      .mockImplementation(() =>\n        Promise.resolve({ \n          json: () => Promise.resolve([]) ,\n          status: 200,\n        })\n      );\n\n    request('https://someradomurl/api/list', 'GET', {}, {}, {}).then((response) => {\n      expect(fetchMock).toBeCalledWith('https://someradomurl/api/list', { body: {}, credentials: 'include', headers: {}, method: 'GET'});\n    }).catch((error) => {\n      console.error(error);\n    });\n\n  });\n\n  it('get should be working properly', () => {\n    const fetchMock = jest\n      .spyOn(global, 'fetch')\n      .mockImplementation(() =>\n        Promise.resolve({ \n          json: () => Promise.resolve([]) ,\n          status: 200,\n        })\n      );\n\n    get('https://someradomurl/api/list', {}, {}, {}).then((response) => {\n      expect(fetchMock).toBeCalledWith(\n        'https://someradomurl/api/list', \n        { \n          body: null, \n          headers: { Accept: 'application/json' }, \n          method: 'GET', \n          credentials: 'include',\n        });\n    }).catch((error) => {\n      console.error(error);\n    });\n\n  });\n\n  it('post should be working properly', () => {\n    const fetchMock = jest\n      .spyOn(global, 'fetch')\n      .mockImplementation(() =>\n        Promise.resolve({ \n          json: () => Promise.resolve([]) ,\n          status: 200,\n        })\n      );\n    \n    post('https://someradomurl/api/list', { a: 1, b: 'a', c: [] }, { 'Content-Type': 'application/json' }, {}).then((response) => {\n      expect(fetchMock).toBeCalledWith(\n        'https://someradomurl/api/list', \n        {\n          body: '{\"a\":1,\"b\":\"a\",\"c\":[]}', \n          headers: { \n            Accept: 'application/json',\n            'Content-Type': 'application/json',\n          }, \n          method: 'POST', \n          credentials: 'include',\n        });\n    }).catch((error) => {\n      console.error(error);\n    });\n\n\n    post('https://someradomurl/api/list', [ 1, 2, 3, 4 ], {}, {}).then((response) => {\n      expect(fetchMock).toBeCalledWith(\n        'https://someradomurl/api/list', \n        {\n          body: '[1,2,3,4]', \n          headers: { \n            Accept: 'application/json',\n            'Content-Type': 'application/x-www-form-urlencoded',\n          }, \n          method: 'POST', \n          credentials: 'include',\n        });\n    }).catch((error) => {\n      console.error(error);\n    });\n\n    mockSerializeParams.mockImplementation((params) => {\n      return 'serializedParams=serializedParams';\n    });\n    post('https://someradomurl/api/list', { a: 1, b: 'a', c: [] }, {}, {}).then((response) => {\n      expect(fetchMock).toBeCalledWith(\n        'https://someradomurl/api/list', \n        {\n          body: 'serializedParams=serializedParams', \n          headers: { \n            Accept: 'application/json',\n            'Content-Type': 'application/x-www-form-urlencoded',\n          }, \n          method: 'POST', \n          credentials: 'include',\n        });\n      mockSerializeParams.mockClear();\n    }).catch((error) => {\n      console.error(error);\n    });\n\n  });\n  it('jsonp should be working properly', () => {\n    mockSerializeParams.mockImplementation((params) => {\n      return 'params';\n    });\n    jsonp('https://someradomurl/api/list', {}, { otherParam1: '123'}).catch(() => {\n      expect(mockFetchJsonp).toBeCalledWith('https://someradomurl/api/list?params', { timeout: 5000,  otherParam1: '123' });\n      mockSerializeParams.mockClear();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/renderer-core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"jsx\": \"react\"\n  },\n  \"include\": [\"./src/\"],\n}\n"
  },
  {
    "path": "packages/shell/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\"\n  ]\n}\n"
  },
  {
    "path": "packages/shell/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/shell/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-shell\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Shell Layer for AliLowCodeEngine\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"scripts\": {\n    \"build\": \"build-scripts build\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@alilc/lowcode-designer\": \"1.3.2\",\n    \"@alilc/lowcode-editor-core\": \"1.3.2\",\n    \"@alilc/lowcode-editor-skeleton\": \"1.3.2\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"@alilc/lowcode-workspace\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"enzyme\": \"^3.11.0\",\n    \"enzyme-adapter-react-16\": \"^1.15.5\",\n    \"react\": \"^16\",\n    \"react-dom\": \"^16.7.0\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.29\",\n    \"@testing-library/react\": \"^11.2.2\",\n    \"@types/classnames\": \"^2.2.7\",\n    \"@types/jest\": \"^26.0.16\",\n    \"@types/lodash\": \"^4.14.165\",\n    \"@types/medium-editor\": \"^5.0.3\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\",\n    \"@types/react-dom\": \"^16\",\n    \"jest\": \"^26.6.3\",\n    \"lodash\": \"^4.17.20\",\n    \"moment\": \"^2.29.1\",\n    \"typescript\": \"^4.0.3\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/shell\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/shell/src/api/canvas.ts",
    "content": "import {\n  IPublicApiCanvas,\n  IPublicModelDropLocation,\n  IPublicModelScrollTarget,\n  IPublicTypeScrollable,\n  IPublicModelScroller,\n  IPublicTypeLocationData,\n  IPublicModelEditor,\n  IPublicModelDragon,\n  IPublicModelActiveTracker,\n  IPublicModelClipboard,\n} from '@alilc/lowcode-types';\nimport {\n  ScrollTarget as InnerScrollTarget,\n  IDesigner,\n} from '@alilc/lowcode-designer';\nimport { editorSymbol, designerSymbol, nodeSymbol } from '../symbols';\nimport {\n  Dragon as ShellDragon,\n  DropLocation as ShellDropLocation,\n  ActiveTracker as ShellActiveTracker,\n  Clipboard as ShellClipboard,\n  DropLocation,\n} from '../model';\n\nconst clipboardInstanceSymbol = Symbol('clipboardInstace');\n\nexport class Canvas implements IPublicApiCanvas {\n  private readonly [editorSymbol]: IPublicModelEditor;\n  private readonly [clipboardInstanceSymbol]: IPublicModelClipboard;\n\n  private get [designerSymbol](): IDesigner {\n    return this[editorSymbol].get('designer') as IDesigner;\n  }\n\n  get dragon(): IPublicModelDragon | null {\n    return ShellDragon.create(this[designerSymbol].dragon, this.workspaceMode);\n  }\n\n  get activeTracker(): IPublicModelActiveTracker | null {\n    const activeTracker = new ShellActiveTracker(this[designerSymbol].activeTracker);\n    return activeTracker;\n  }\n\n  get isInLiveEditing(): boolean {\n    return Boolean(this[editorSymbol].get('designer')?.project?.simulator?.liveEditing?.editing);\n  }\n\n  get clipboard(): IPublicModelClipboard {\n    return this[clipboardInstanceSymbol];\n  }\n\n  constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) {\n    this[editorSymbol] = editor;\n    this[clipboardInstanceSymbol] = new ShellClipboard();\n  }\n\n  createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget {\n    return new InnerScrollTarget(shell);\n  }\n\n  createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller {\n    return this[designerSymbol].createScroller(scrollable);\n  }\n\n  /**\n   * 创建插入位置，考虑放到 dragon 中\n   */\n  createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation {\n    return new DropLocation(this[designerSymbol].createLocation({\n      ...locationData,\n      target: (locationData.target as any)[nodeSymbol],\n    }));\n  }\n\n  /**\n   * @deprecated\n   */\n  get dropLocation() {\n    return ShellDropLocation.create((this[designerSymbol] as any).dropLocation || null);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/command.ts",
    "content": "import { IPublicApiCommand, IPublicModelPluginContext, IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '@alilc/lowcode-types';\nimport { commandSymbol, pluginContextSymbol } from '../symbols';\nimport { ICommand, ICommandOptions } from '@alilc/lowcode-editor-core';\n\nconst optionsSymbol = Symbol('options');\nconst commandScopeSet = new Set<string>();\n\nexport class Command implements IPublicApiCommand {\n  [commandSymbol]: ICommand;\n  [optionsSymbol]?: ICommandOptions;\n  [pluginContextSymbol]?: IPublicModelPluginContext;\n\n  constructor(innerCommand: ICommand, pluginContext?: IPublicModelPluginContext, options?: ICommandOptions) {\n    this[commandSymbol] = innerCommand;\n    this[optionsSymbol] = options;\n    this[pluginContextSymbol] = pluginContext;\n    const commandScope = options?.commandScope;\n    if (commandScope && commandScopeSet.has(commandScope)) {\n      throw new Error(`Command scope \"${commandScope}\" has been registered.`);\n    }\n  }\n\n  registerCommand(command: IPublicTypeCommand): void {\n    this[commandSymbol].registerCommand(command, this[optionsSymbol]);\n  }\n\n  batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void {\n    this[commandSymbol].batchExecuteCommand(commands, this[pluginContextSymbol]);\n  }\n\n  executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void {\n    this[commandSymbol].executeCommand(name, args);\n  }\n\n  listCommands(): IPublicTypeListCommand[] {\n    return this[commandSymbol].listCommands();\n  }\n\n  unregisterCommand(name: string): void {\n    this[commandSymbol].unregisterCommand(name);\n  }\n\n  onCommandError(callback: (name: string, error: Error) => void): void {\n    this[commandSymbol].onCommandError(callback);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/common.tsx",
    "content": "import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol, settingFieldSymbol, editorCabinSymbol, skeletonCabinSymbol } from '../symbols';\nimport {\n  isFormEvent as innerIsFormEvent,\n  compatibleLegaoSchema as innerCompatibleLegaoSchema,\n  getNodeSchemaById as innerGetNodeSchemaById,\n  transactionManager,\n  isNodeSchema as innerIsNodeSchema,\n  isDragNodeDataObject as innerIsDragNodeDataObject,\n  isDragNodeObject as innerIsDragNodeObject,\n  isDragAnyObject as innerIsDragAnyObject,\n  isLocationChildrenDetail as innerIsLocationChildrenDetail,\n  isNode as innerIsNode,\n  isSettingField,\n  isSettingField as innerIsSettingField,\n} from '@alilc/lowcode-utils';\nimport {\n  IPublicTypeNodeSchema,\n  IPublicEnumTransitionType,\n  IPublicEnumTransformStage as InnerTransitionStage,\n  IPublicApiCommonDesignerCabin,\n  IPublicApiCommonSkeletonCabin,\n  IPublicApiCommonUtils,\n  IPublicApiCommon,\n  IPublicEnumDragObjectType as InnerDragObjectType,\n  IPublicTypeLocationDetailType as InnerLocationDetailType,\n  IPublicApiCommonEditorCabin,\n  IPublicModelDragon,\n  IPublicModelSettingField,\n  IPublicTypeI18nData,\n} from '@alilc/lowcode-types';\nimport {\n  SettingField as InnerSettingField,\n  LiveEditing as InnerLiveEditing,\n  isShaken as innerIsShaken,\n  contains as innerContains,\n  ScrollTarget as InnerScrollTarget,\n  getConvertedExtraKey as innerGetConvertedExtraKey,\n  getOriginalExtraKey as innerGetOriginalExtraKey,\n  IDesigner,\n  DropLocation as InnerDropLocation,\n  Designer as InnerDesigner,\n  Node as InnerNode,\n  LowCodePluginManager as InnerLowCodePluginManager,\n  DesignerView as InnerDesignerView,\n} from '@alilc/lowcode-designer';\nimport {\n  Skeleton as InnerSkeleton,\n  createSettingFieldView as innerCreateSettingFieldView,\n  PopupContext as InnerPopupContext,\n  PopupPipe as InnerPopupPipe,\n  Workbench as InnerWorkbench,\n  SettingsPrimaryPane as InnerSettingsPrimaryPane,\n  registerDefaults as InnerRegisterDefaults,\n} from '@alilc/lowcode-editor-skeleton';\nimport {\n  Editor,\n  Title as InnerTitle,\n  Tip as InnerTip,\n  shallowIntl as innerShallowIntl,\n  createIntl as innerCreateIntl,\n  intl as innerIntl,\n  globalLocale as innerGlobalLocale,\n  obx as innerObx,\n  observable as innerObservable,\n  makeObservable as innerMakeObservable,\n  untracked as innerUntracked,\n  computed as innerComputed,\n  observer as innerObserver,\n  action as innerAction,\n  runInAction as innerRunInAction,\n  engineConfig as innerEngineConfig,\n  globalContext,\n} from '@alilc/lowcode-editor-core';\nimport { Dragon as ShellDragon } from '../model';\nimport { ReactNode } from 'react';\n\nclass DesignerCabin implements IPublicApiCommonDesignerCabin {\n  private readonly [editorSymbol]: Editor;\n\n  /**\n   * @deprecated\n   */\n  readonly [designerCabinSymbol]: any;\n\n  private get [designerSymbol](): IDesigner {\n    return this[editorSymbol].get('designer') as IDesigner;\n  }\n\n  constructor(editor: Editor) {\n    this[editorSymbol] = editor;\n    this[designerCabinSymbol] = {\n      isDragNodeObject: innerIsDragNodeObject,\n      isDragAnyObject: innerIsDragAnyObject,\n      isShaken: innerIsShaken,\n      contains: innerContains,\n      LocationDetailType: InnerLocationDetailType,\n      isLocationChildrenDetail: innerIsLocationChildrenDetail,\n      ScrollTarget: InnerScrollTarget,\n      isSettingField: innerIsSettingField,\n      TransformStage: InnerTransitionStage,\n      SettingField: InnerSettingField,\n      LiveEditing: InnerLiveEditing,\n      DragObjectType: InnerDragObjectType,\n      isDragNodeDataObject: innerIsDragNodeDataObject,\n      isNode: innerIsNode,\n      DropLocation: InnerDropLocation,\n      Designer: InnerDesigner,\n      Node: InnerNode,\n      LowCodePluginManager: InnerLowCodePluginManager,\n      DesignerView: InnerDesignerView,\n    };\n  }\n\n  /**\n   * 是否是 SettingField 实例\n   * @deprecated use same function from @alilc/lowcode-utils directly\n   */\n  isSettingField(obj: any): boolean {\n    return isSettingField(obj);\n  }\n\n  /**\n   * 转换类型枚举对象，包含 init / upgrade / render 等类型\n   * [参考](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/transform-stage.ts)\n   * @deprecated use { TransformStage } from '@alilc/lowcode-types' instead\n   */\n  get TransformStage() {\n    return InnerTransitionStage;\n  }\n\n  /**\n   * @deprecated\n   */\n  get SettingField() {\n    return InnerSettingField;\n  }\n\n  /**\n   * @deprecated\n   */\n  get LiveEditing() {\n    return InnerLiveEditing;\n  }\n\n  /**\n   * @deprecated\n   */\n  get DragObjectType() {\n    return InnerDragObjectType;\n  }\n\n  /**\n   * @deprecated\n   */\n  isDragNodeDataObject(obj: any): boolean {\n    return innerIsDragNodeDataObject(obj);\n  }\n\n  /**\n   * @deprecated\n   */\n  isNode(node: any): boolean {\n    return innerIsNode(node);\n  }\n\n  /**\n   * @deprecated please use canvas.dragon\n   */\n  get dragon(): IPublicModelDragon | null {\n    return ShellDragon.create(this[designerSymbol].dragon, false);\n  }\n}\n\nclass SkeletonCabin implements IPublicApiCommonSkeletonCabin {\n  private readonly [skeletonSymbol]: InnerSkeleton;\n\n  readonly [skeletonCabinSymbol]: any;\n\n  constructor(skeleton: InnerSkeleton) {\n    this[skeletonSymbol] = skeleton;\n    this[skeletonCabinSymbol] = {\n      Workbench: InnerWorkbench,\n      createSettingFieldView: this.createSettingFieldView,\n      PopupContext: InnerPopupContext,\n      PopupPipe: InnerPopupPipe,\n      SettingsPrimaryPane: InnerSettingsPrimaryPane,\n      registerDefaults: InnerRegisterDefaults,\n      Skeleton: InnerSkeleton,\n    };\n  }\n\n  get Workbench(): any {\n    const innerSkeleton = this[skeletonSymbol];\n    return (props: any) => <InnerWorkbench {...props} skeleton={innerSkeleton} />;\n  }\n\n  /**\n   * @deprecated\n   */\n  createSettingFieldView(field: IPublicModelSettingField, fieldEntry: any) {\n    return innerCreateSettingFieldView((field as any)[settingFieldSymbol] || field, fieldEntry);\n  }\n\n  /**\n   * @deprecated\n   */\n  get PopupContext(): any {\n    return InnerPopupContext;\n  }\n\n  /**\n   * @deprecated\n   */\n   get PopupPipe(): any {\n    return InnerPopupPipe;\n  }\n}\n\nclass Utils implements IPublicApiCommonUtils {\n  isNodeSchema(data: any): data is IPublicTypeNodeSchema {\n    return innerIsNodeSchema(data);\n  }\n\n  isFormEvent(e: KeyboardEvent | MouseEvent): boolean {\n    return innerIsFormEvent(e);\n  }\n\n  /**\n   * @deprecated this is a legacy api, do not use this if not using is already\n   */\n  compatibleLegaoSchema(props: any): any {\n    return innerCompatibleLegaoSchema(props);\n  }\n\n  getNodeSchemaById(\n      schema: IPublicTypeNodeSchema,\n      nodeId: string,\n    ): IPublicTypeNodeSchema | undefined {\n    return innerGetNodeSchemaById(schema, nodeId);\n  }\n\n  getConvertedExtraKey(key: string): string {\n    return innerGetConvertedExtraKey(key);\n  }\n\n  getOriginalExtraKey(key: string): string {\n    return innerGetOriginalExtraKey(key);\n  }\n\n  executeTransaction(\n      fn: () => void,\n      type: IPublicEnumTransitionType = IPublicEnumTransitionType.REPAINT,\n    ): void {\n    transactionManager.executeTransaction(fn, type);\n  }\n\n  createIntl(instance: string | object): {\n      intlNode(id: string, params?: object): ReactNode;\n      intl(id: string, params?: object): string;\n      getLocale(): string;\n      setLocale(locale: string): void;\n    } {\n    return innerCreateIntl(instance);\n  }\n\n  intl(data: IPublicTypeI18nData | string, params?: object): any {\n    return innerIntl(data, params);\n  }\n}\n\nclass EditorCabin implements IPublicApiCommonEditorCabin {\n  private readonly [editorSymbol]: Editor;\n\n  /**\n   * @deprecated\n   */\n  readonly [editorCabinSymbol]: any;\n\n  constructor(editor: Editor) {\n    this[editorSymbol] = editor;\n    this[editorCabinSymbol] = {\n      Editor,\n      globalContext,\n      runInAction: innerRunInAction,\n      Title: InnerTitle,\n      Tip: InnerTip,\n      shallowIntl: innerShallowIntl,\n      createIntl: innerCreateIntl,\n      intl: innerIntl,\n      createSetterContent: this.createSetterContent.bind(this),\n      globalLocale: innerGlobalLocale,\n      obx: innerObx,\n      action: innerAction,\n      engineConfig: innerEngineConfig,\n      observable: innerObservable,\n      makeObservable: innerMakeObservable,\n      untracked: innerUntracked,\n      computed: innerComputed,\n      observer: innerObserver,\n    };\n  }\n\n  /**\n   * Title 组件\n   * @experimental unstable API, pay extra caution when trying to use this\n   */\n  get Title() {\n    return InnerTitle;\n  }\n\n  /**\n   * Tip 组件\n   * @experimental unstable API, pay extra caution when trying to use this\n   */\n  get Tip() {\n    return InnerTip;\n  }\n\n  /**\n   * @deprecated\n   */\n  shallowIntl(data: any): any {\n    return innerShallowIntl(data);\n  }\n\n  /**\n   * @deprecated use common.utils.createIntl instead\n   */\n  createIntl(instance: any): any {\n    return innerCreateIntl(instance);\n  }\n\n  /**\n   * @deprecated\n   */\n  intl(data: any, params?: object): any {\n    return innerIntl(data, params);\n  }\n\n  /**\n   * @deprecated\n   */\n  createSetterContent = (setter: any, props: Record<string, any>): ReactNode => {\n    const setters = this[editorSymbol].get('setters');\n    return setters.createSetterContent(setter, props);\n  };\n\n  /**\n   * @deprecated use common.utils.createIntl instead\n   */\n  get globalLocale(): any {\n    return innerGlobalLocale;\n  }\n\n  /**\n   * @deprecated\n   */\n  get obx() {\n    return innerObx;\n  }\n\n  /**\n   * @deprecated\n   */\n  get action() {\n    return innerAction;\n  }\n\n  /**\n   * @deprecated\n   */\n  get engineConfig() {\n    return innerEngineConfig;\n  }\n\n  /**\n   * @deprecated\n   */\n  get runInAction() {\n    return innerRunInAction;\n  }\n\n  /**\n   * @deprecated\n   */\n  get observable() {\n    return innerObservable;\n  }\n\n  /**\n   * @deprecated\n   */\n  makeObservable(target: any, annotations: any, options: any) {\n    return innerMakeObservable(target, annotations, options);\n  }\n\n  /**\n   * @deprecated\n   */\n  untracked(action: any) {\n    return innerUntracked(action);\n  }\n\n  /**\n   * @deprecated\n   */\n  get computed() {\n    return innerComputed;\n  }\n\n  /**\n   * @deprecated\n   */\n  observer(component: any) {\n    return innerObserver(component);\n  }\n}\n\nexport class Common implements IPublicApiCommon {\n  private readonly __designerCabin: any;\n  private readonly __skeletonCabin: any;\n  private readonly __editorCabin: any;\n  private readonly __utils: Utils;\n\n  constructor(editor: Editor, skeleton: InnerSkeleton) {\n    this.__designerCabin = new DesignerCabin(editor);\n    this.__skeletonCabin = new SkeletonCabin(skeleton);\n    this.__editorCabin = new EditorCabin(editor);\n    this.__utils = new Utils();\n  }\n\n  get utils(): any {\n    return this.__utils;\n  }\n\n  /**\n   * 历史原因导致此处设计不合理，慎用。\n   * this load of crap will be removed in some future versions, don`t use it.\n   * @deprecated\n   */\n  get editorCabin(): any {\n    return this.__editorCabin;\n  }\n\n  /**\n   * 历史原因导致此处设计不合理，慎用。\n   * this load of crap will be removed in some future versions, don`t use it.\n   * @deprecated use canvas api instead\n   */\n  get designerCabin(): any {\n    return this.__designerCabin;\n  }\n\n  get skeletonCabin(): any {\n    return this.__skeletonCabin;\n  }\n\n  /**\n   * 历史原因导致此处设计不合理，慎用。\n   * this load of crap will be removed in some future versions, don`t use it.\n   * @deprecated use { TransformStage } from '@alilc/lowcode-types' instead\n   */\n  get objects(): any {\n    return {\n      TransformStage: InnerTransitionStage,\n    };\n  }\n}"
  },
  {
    "path": "packages/shell/src/api/commonUI.tsx",
    "content": "import { IPublicApiCommonUI, IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types';\nimport {\n  HelpTip,\n  IEditor,\n  Tip as InnerTip,\n  Title as InnerTitle,\n } from '@alilc/lowcode-editor-core';\nimport { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next';\nimport { ContextMenu } from '../components/context-menu';\nimport { editorSymbol } from '../symbols';\nimport { ReactElement } from 'react';\n\nexport class CommonUI implements IPublicApiCommonUI {\n  [editorSymbol]: IEditor;\n\n  Balloon = Balloon;\n  Breadcrumb = Breadcrumb;\n  Button = Button;\n  Card = Card;\n  Checkbox = Checkbox;\n  DatePicker = DatePicker;\n  Dialog = Dialog;\n  Dropdown = Dropdown;\n  Form = Form;\n  Icon = Icon;\n  Input = Input;\n  Loading = Loading as any;\n  Message = Message;\n  Overlay = Overlay;\n  Pagination = Pagination;\n  Radio = Radio;\n  Search = Search;\n  Select = Select;\n  SplitButton = SplitButton;\n  Step = Step;\n  Switch = Switch;\n  Tab = Tab;\n  Table = Table;\n  Tree = Tree;\n  TreeSelect = TreeSelect;\n  Upload = Upload;\n  Divider = Divider;\n\n  ContextMenu: ((props: {\n    menus: IPublicTypeContextMenuAction[];\n    children: React.ReactElement[] | React.ReactElement;\n  }) => ReactElement) & {\n    create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void;\n  };\n\n  constructor(editor: IEditor) {\n    this[editorSymbol] = editor;\n\n    const innerContextMenu = (props: any) => {\n      const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext;\n      return <ContextMenu {...props} pluginContext={pluginContext} />;\n    };\n\n    innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => {\n      const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext;\n      return ContextMenu.create(pluginContext, menus, event);\n    };\n\n    this.ContextMenu = innerContextMenu;\n  }\n\n  get Tip() {\n    return InnerTip;\n  }\n\n  get HelpTip() {\n    return HelpTip;\n  }\n\n  get Title() {\n    return InnerTitle;\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/config.ts",
    "content": "import { IPublicModelEngineConfig, IPublicModelPreference, IPublicTypeDisposable } from '@alilc/lowcode-types';\nimport { configSymbol } from '../symbols';\nimport { IEngineConfig } from '@alilc/lowcode-editor-core';\n\nexport class Config implements IPublicModelEngineConfig {\n  private readonly [configSymbol]: IEngineConfig;\n\n  constructor(innerEngineConfig: IEngineConfig) {\n    this[configSymbol] = innerEngineConfig;\n  }\n\n  has(key: string): boolean {\n    return this[configSymbol].has(key);\n  }\n\n  get(key: string, defaultValue?: any): any {\n    return this[configSymbol].get(key, defaultValue);\n  }\n\n  set(key: string, value: any): void {\n    this[configSymbol].set(key, value);\n  }\n\n  setConfig(config: { [key: string]: any }): void {\n    this[configSymbol].setConfig(config);\n  }\n\n  onceGot(key: string): Promise<any> {\n    return this[configSymbol].onceGot(key);\n  }\n\n  onGot(key: string, fn: (data: any) => void): IPublicTypeDisposable {\n    return this[configSymbol].onGot(key, fn);\n  }\n\n  getPreference(): IPublicModelPreference {\n    return this[configSymbol].getPreference();\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/event.ts",
    "content": "import { IEditor, IEventBus } from '@alilc/lowcode-editor-core';\nimport { getLogger, isPluginEventName } from '@alilc/lowcode-utils';\nimport { IPublicApiEvent, IPublicTypeDisposable } from '@alilc/lowcode-types';\n\nconst logger = getLogger({ level: 'warn', bizName: 'shell-event' });\n\ntype EventOptions = {\n  prefix: string;\n};\n\nconst eventBusSymbol = Symbol('eventBus');\n\nexport class Event implements IPublicApiEvent {\n  private readonly [eventBusSymbol]: IEventBus;\n  private readonly options: EventOptions;\n\n  constructor(eventBus: IEventBus, options: EventOptions, public workspaceMode = false) {\n    this[eventBusSymbol] = eventBus;\n    this.options = options;\n    if (!this.options.prefix) {\n      logger.warn('prefix is required while initializing Event');\n    }\n  }\n\n  /**\n   * 监听事件\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  on(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable {\n    if (isPluginEventName(event)) {\n      return this[eventBusSymbol].on(event, listener);\n    } else {\n      logger.warn(`fail to monitor on event ${event}, event should have a prefix like 'somePrefix:eventName'`);\n      return () => {};\n    }\n  }\n\n  /**\n   * 监听事件，会在其他回调函数之前执行\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  prependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable {\n    if (isPluginEventName(event)) {\n      return this[eventBusSymbol].prependListener(event, listener);\n    } else {\n      logger.warn(`fail to prependListener event ${event}, event should have a prefix like 'somePrefix:eventName'`);\n      return () => {};\n    }\n  }\n\n  /**\n   * 取消监听事件\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  off(event: string, listener: (...args: any[]) => void) {\n    this[eventBusSymbol].off(event, listener);\n  }\n\n  /**\n   * 触发事件\n   * @param event 事件名称\n   * @param args 事件参数\n   * @returns\n   */\n  emit(event: string, ...args: any[]) {\n    if (!this.options.prefix) {\n      logger.warn('Event#emit has been forbidden while prefix is not specified');\n      return;\n    }\n    this[eventBusSymbol].emit(`${this.options.prefix}:${event}`, ...args);\n  }\n\n  /**\n   * DO NOT USE if u fully understand what this method does.\n   * @param event\n   * @param args\n   */\n  __internalEmit__(event: string, ...args: unknown[]) {\n    this[eventBusSymbol].emit(event, ...args);\n  }\n}\n\nexport function getEvent(editor: IEditor, options: any = { prefix: 'common' }) {\n  return new Event(editor.eventBus, options);\n}\n"
  },
  {
    "path": "packages/shell/src/api/hotkey.ts",
    "content": "import { globalContext, Hotkey as InnerHotkey } from '@alilc/lowcode-editor-core';\nimport { hotkeySymbol } from '../symbols';\nimport { IPublicTypeDisposable, IPublicTypeHotkeyCallback, IPublicTypeHotkeyCallbacks, IPublicApiHotkey } from '@alilc/lowcode-types';\n\nconst innerHotkeySymbol = Symbol('innerHotkey');\n\nexport class Hotkey implements IPublicApiHotkey {\n  private readonly [innerHotkeySymbol]: InnerHotkey;\n  get [hotkeySymbol](): InnerHotkey {\n    if (this.workspaceMode) {\n      return this[innerHotkeySymbol];\n    }\n    const workspace = globalContext.get('workspace');\n    if (workspace.isActive) {\n      return workspace.window.innerHotkey;\n    }\n\n    return this[innerHotkeySymbol];\n  }\n\n  constructor(hotkey: InnerHotkey, readonly workspaceMode: boolean = false) {\n    this[innerHotkeySymbol] = hotkey;\n  }\n\n  get callbacks(): IPublicTypeHotkeyCallbacks {\n    return this[hotkeySymbol].callBacks;\n  }\n\n  /**\n   * @deprecated\n   */\n  get callBacks() {\n    return this.callbacks;\n  }\n\n  /**\n   * 绑定快捷键\n   * @param combos 快捷键，格式如：['command + s'] 、['ctrl + shift + s'] 等\n   * @param callback 回调函数\n   * @param action\n   * @returns\n   */\n  bind(\n      combos: string[] | string,\n      callback: IPublicTypeHotkeyCallback,\n      action?: string,\n    ): IPublicTypeDisposable {\n    this[hotkeySymbol].bind(combos, callback, action);\n    return () => {\n      this[hotkeySymbol].unbind(combos, callback, action);\n    };\n  }\n}"
  },
  {
    "path": "packages/shell/src/api/index.ts",
    "content": "export * from './common';\nexport * from './event';\nexport * from './hotkey';\nexport * from './logger';\nexport * from './material';\nexport * from './plugins';\nexport * from './project';\nexport * from './setters';\nexport * from './simulator-host';\nexport * from './skeleton';\nexport * from './canvas';\nexport * from './workspace';\nexport * from './config';\nexport * from './commonUI';\nexport * from './command';"
  },
  {
    "path": "packages/shell/src/api/logger.ts",
    "content": "\nimport { getLogger } from '@alilc/lowcode-utils';\nimport { IPublicApiLogger, ILoggerOptions } from '@alilc/lowcode-types';\n\nconst innerLoggerSymbol = Symbol('logger');\n\nexport class Logger implements IPublicApiLogger {\n  private readonly [innerLoggerSymbol]: any;\n\n  constructor(options: ILoggerOptions) {\n    this[innerLoggerSymbol] = getLogger(options as any);\n  }\n\n  /**\n   * debug info\n   */\n  debug(...args: any | any[]): void {\n    this[innerLoggerSymbol].debug(...args);\n  }\n\n  /**\n   * normal info output\n   */\n  info(...args: any | any[]): void {\n    this[innerLoggerSymbol].info(...args);\n  }\n\n  /**\n   * warning info output\n   */\n  warn(...args: any | any[]): void {\n    this[innerLoggerSymbol].warn(...args);\n  }\n\n  /**\n   * error info output\n   */\n  error(...args: any | any[]): void {\n    this[innerLoggerSymbol].error(...args);\n  }\n\n  /**\n   * normal log output\n   */\n  log(...args: any | any[]): void {\n    this[innerLoggerSymbol].log(...args);\n  }\n}"
  },
  {
    "path": "packages/shell/src/api/material.ts",
    "content": "import { globalContext } from '@alilc/lowcode-editor-core';\nimport {\n  IDesigner,\n  isComponentMeta,\n} from '@alilc/lowcode-designer';\nimport { IPublicTypeAssetsJson, getLogger } from '@alilc/lowcode-utils';\nimport {\n  IPublicTypeComponentAction,\n  IPublicTypeComponentMetadata,\n  IPublicApiMaterial,\n  IPublicTypeMetadataTransducer,\n  IPublicModelComponentMeta,\n  IPublicTypeNpmInfo,\n  IPublicModelEditor,\n  IPublicTypeDisposable,\n  IPublicTypeContextMenuAction,\n  IPublicTypeContextMenuItem,\n} from '@alilc/lowcode-types';\nimport { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace';\nimport { editorSymbol, designerSymbol } from '../symbols';\nimport { ComponentMeta as ShellComponentMeta } from '../model';\nimport { ComponentType } from 'react';\n\nconst logger = getLogger({ level: 'warn', bizName: 'shell-material' });\n\nconst innerEditorSymbol = Symbol('editor');\nexport class Material implements IPublicApiMaterial {\n  private readonly [innerEditorSymbol]: IPublicModelEditor;\n\n  get [editorSymbol](): IPublicModelEditor {\n    if (this.workspaceMode) {\n      return this[innerEditorSymbol];\n    }\n    const workspace: InnerWorkspace = globalContext.get('workspace');\n    if (workspace.isActive) {\n      if (!workspace.window.editor) {\n        logger.error('Material api 调用时机出现问题，请检查');\n        return this[innerEditorSymbol];\n      }\n      return workspace.window.editor;\n    }\n\n    return this[innerEditorSymbol];\n  }\n\n  get [designerSymbol](): IDesigner {\n    return this[editorSymbol].get('designer')!;\n  }\n\n  constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) {\n    this[innerEditorSymbol] = editor;\n  }\n\n  /**\n   * 获取组件 map 结构\n   */\n  get componentsMap(): { [key: string]: IPublicTypeNpmInfo | ComponentType<any> | object } {\n    return this[designerSymbol].componentsMap;\n  }\n\n  /**\n   * 设置「资产包」结构\n   * @param assets\n   * @returns\n   */\n  async setAssets(assets: IPublicTypeAssetsJson) {\n    return await this[editorSymbol].setAssets(assets);\n  }\n\n  /**\n   * 获取「资产包」结构\n   * @returns\n   */\n  getAssets(): IPublicTypeAssetsJson | undefined {\n    return this[editorSymbol].get('assets');\n  }\n\n  /**\n   * 加载增量的「资产包」结构，该增量包会与原有的合并\n   * @param incrementalAssets\n   * @returns\n   */\n  loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson) {\n    return this[designerSymbol].loadIncrementalAssets(incrementalAssets);\n  }\n\n  /**\n   * 注册物料元数据管道函数\n   * @param transducer\n   * @param level\n   * @param id\n   */\n  registerMetadataTransducer = (\n    transducer: IPublicTypeMetadataTransducer,\n    level?: number,\n    id?: string | undefined,\n  ) => {\n    this[designerSymbol].componentActions.registerMetadataTransducer(transducer, level, id);\n  };\n\n  /**\n   * 获取所有物料元数据管道函数\n   * @returns\n   */\n  getRegisteredMetadataTransducers() {\n    return this[designerSymbol].componentActions.getRegisteredMetadataTransducers();\n  }\n\n  /**\n   * 获取指定名称的物料元数据\n   * @param componentName\n   * @returns\n   */\n  getComponentMeta(componentName: string): IPublicModelComponentMeta | null {\n    const innerMeta = this[designerSymbol].getComponentMeta(componentName);\n    return ShellComponentMeta.create(innerMeta);\n  }\n\n  /**\n   * create an instance of ComponentMeta by given metadata\n   * @param metadata\n   * @returns\n   */\n  createComponentMeta(metadata: IPublicTypeComponentMetadata) {\n    return ShellComponentMeta.create(this[designerSymbol].createComponentMeta(metadata));\n  }\n\n  /**\n   * test if the given object is a ComponentMeta instance or not\n   * @param obj\n   * @returns\n   */\n  isComponentMeta(obj: any) {\n    return isComponentMeta(obj);\n  }\n\n  /**\n   * 获取所有已注册的物料元数据\n   * @returns\n   */\n  getComponentMetasMap(): Map<string, IPublicModelComponentMeta> {\n    const map = new Map<string, IPublicModelComponentMeta>();\n    const originalMap = this[designerSymbol].getComponentMetasMap();\n    for (let componentName of originalMap.keys()) {\n      map.set(componentName, this.getComponentMeta(componentName)!);\n    }\n    return map;\n  }\n\n  /**\n   * 在设计器辅助层增加一个扩展 action\n   * @param action\n   */\n  addBuiltinComponentAction = (action: IPublicTypeComponentAction) => {\n    this[designerSymbol].componentActions.addBuiltinComponentAction(action);\n  };\n\n  /**\n   * 刷新 componentMetasMap，可触发模拟器里的 components 重新构建\n   */\n  refreshComponentMetasMap = () => {\n    this[designerSymbol].refreshComponentMetasMap();\n  };\n\n  /**\n   * 移除设计器辅助层的指定 action\n   * @param name\n   */\n  removeBuiltinComponentAction(name: string) {\n    this[designerSymbol].componentActions.removeBuiltinComponentAction(name);\n  }\n\n  /**\n   * 修改已有的设计器辅助层的指定 action\n   * @param actionName\n   * @param handle\n   */\n  modifyBuiltinComponentAction(\n      actionName: string,\n      handle: (action: IPublicTypeComponentAction) => void,\n    ) {\n    this[designerSymbol].componentActions.modifyBuiltinComponentAction(actionName, handle);\n  }\n\n  /**\n   * 监听 assets 变化的事件\n   * @param fn\n   */\n  onChangeAssets(fn: () => void): IPublicTypeDisposable {\n    const dispose = [\n      // 设置 assets，经过 setAssets 赋值\n      this[editorSymbol].onChange('assets', fn),\n      // 增量设置 assets，经过 loadIncrementalAssets 赋值\n      this[editorSymbol].eventBus.on('designer.incrementalAssetsReady', fn),\n    ];\n\n    return () => {\n      dispose.forEach(d => d && d());\n    };\n  }\n\n  addContextMenuOption(option: IPublicTypeContextMenuAction) {\n    this[designerSymbol].contextMenuActions.addMenuAction(option);\n  }\n\n  removeContextMenuOption(name: string) {\n    this[designerSymbol].contextMenuActions.removeMenuAction(name);\n  }\n\n  adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) {\n    this[designerSymbol].contextMenuActions.adjustMenuLayout(fn);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/plugins.ts",
    "content": "import {\n  ILowCodePluginManager,\n} from '@alilc/lowcode-designer';\nimport { globalContext } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicApiPlugins,\n  IPublicModelPluginInstance,\n  IPublicTypePlugin,\n  IPublicTypePluginRegisterOptions,\n  IPublicTypePreferenceValueType,\n} from '@alilc/lowcode-types';\nimport { PluginInstance as ShellPluginInstance } from '../model';\nimport { pluginsSymbol } from '../symbols';\n\nconst innerPluginsSymbol = Symbol('plugin');\nexport class Plugins implements IPublicApiPlugins {\n  private readonly [innerPluginsSymbol]: ILowCodePluginManager;\n  get [pluginsSymbol](): ILowCodePluginManager {\n    if (this.workspaceMode) {\n      return this[innerPluginsSymbol];\n    }\n    const workspace = globalContext.get('workspace');\n    if (workspace.isActive) {\n      return workspace.window.innerPlugins;\n    }\n\n    return this[innerPluginsSymbol];\n  }\n\n  constructor(plugins: ILowCodePluginManager, public workspaceMode: boolean = false) {\n    this[innerPluginsSymbol] = plugins;\n  }\n\n  async register(\n    pluginModel: IPublicTypePlugin,\n    options?: any,\n    registerOptions?: IPublicTypePluginRegisterOptions,\n  ): Promise<void> {\n    await this[pluginsSymbol].register(pluginModel, options, registerOptions);\n  }\n\n  async init(registerOptions: any) {\n    await this[pluginsSymbol].init(registerOptions);\n  }\n\n  getPluginPreference(\n      pluginName: string,\n    ): Record<string, IPublicTypePreferenceValueType> | null | undefined {\n    return this[pluginsSymbol].getPluginPreference(pluginName);\n  }\n\n  get(pluginName: string): IPublicModelPluginInstance | null {\n    const instance = this[pluginsSymbol].get(pluginName);\n    if (instance) {\n      return new ShellPluginInstance(instance);\n    }\n\n    return null;\n  }\n\n  getAll() {\n    return this[pluginsSymbol].getAll()?.map((d) => new ShellPluginInstance(d));\n  }\n\n  has(pluginName: string) {\n    return this[pluginsSymbol].has(pluginName);\n  }\n\n  async delete(pluginName: string) {\n    return await this[pluginsSymbol].delete(pluginName);\n  }\n\n  toProxy() {\n    return new Proxy(this, {\n      get(target, prop, receiver) {\n        const _target = target[pluginsSymbol];\n        if (_target.pluginsMap.has(prop as string)) {\n          // 禁用态的插件，直接返回 undefined\n          if (_target.pluginsMap.get(prop as string)!.disabled) {\n            return undefined;\n          }\n          return _target.pluginsMap.get(prop as string)?.toProxy();\n        }\n        return Reflect.get(target, prop, receiver);\n      },\n    });\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/project.ts",
    "content": "import {\n  BuiltinSimulatorHost,\n  IProject as InnerProject,\n} from '@alilc/lowcode-designer';\nimport { globalContext } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicTypeRootSchema,\n  IPublicTypeProjectSchema,\n  IPublicModelEditor,\n  IPublicApiProject,\n  IPublicApiSimulatorHost,\n  IPublicModelDocumentModel,\n  IPublicTypePropsTransducer,\n  IPublicEnumTransformStage,\n  IPublicTypeDisposable,\n  IPublicTypeAppConfig,\n} from '@alilc/lowcode-types';\nimport { DocumentModel as ShellDocumentModel } from '../model';\nimport { SimulatorHost } from './simulator-host';\nimport { editorSymbol, projectSymbol, simulatorHostSymbol, documentSymbol } from '../symbols';\nimport { getLogger } from '@alilc/lowcode-utils';\n\nconst logger = getLogger({ level: 'warn', bizName: 'shell-project' });\n\nconst innerProjectSymbol = Symbol('innerProject');\nexport class Project implements IPublicApiProject {\n  private readonly [innerProjectSymbol]: InnerProject;\n  private [simulatorHostSymbol]: BuiltinSimulatorHost;\n  get [projectSymbol](): InnerProject {\n    if (this.workspaceMode) {\n      return this[innerProjectSymbol];\n    }\n    const workspace = globalContext.get('workspace');\n    if (workspace.isActive) {\n      if (!workspace.window?.innerProject) {\n        logger.error('project api 调用时机出现问题，请检查');\n        return this[innerProjectSymbol];\n      }\n      return workspace.window.innerProject;\n    }\n\n    return this[innerProjectSymbol];\n  }\n\n  get [editorSymbol](): IPublicModelEditor {\n    return this[projectSymbol]?.designer.editor;\n  }\n\n  constructor(project: InnerProject, public workspaceMode: boolean = false) {\n    this[innerProjectSymbol] = project;\n  }\n\n  static create(project: InnerProject, workspaceMode: boolean = false) {\n    return new Project(project, workspaceMode);\n  }\n\n  /**\n   * 获取当前的 document\n   * @returns\n   */\n  get currentDocument(): IPublicModelDocumentModel | null {\n    return this.getCurrentDocument();\n  }\n\n  /**\n   * 获取当前 project 下所有 documents\n   * @returns\n   */\n  get documents(): IPublicModelDocumentModel[] {\n    return this[projectSymbol].documents.map((doc) => ShellDocumentModel.create(doc)!);\n  }\n\n  /**\n   * 获取模拟器的 host\n   */\n  get simulatorHost(): IPublicApiSimulatorHost | null {\n    return SimulatorHost.create(this[projectSymbol].simulator as any || this[simulatorHostSymbol]);\n  }\n\n  /**\n   * @deprecated use .simulatorHost instead.\n   */\n  get simulator() {\n    return this.simulatorHost;\n  }\n\n  /**\n   * 打开一个 document\n   * @param doc\n   * @returns\n   */\n  openDocument(doc?: string | IPublicTypeRootSchema | undefined) {\n    const documentModel = this[projectSymbol].open(doc);\n    if (!documentModel) {\n      return null;\n    }\n    return ShellDocumentModel.create(documentModel);\n  }\n\n  /**\n   * 创建一个 document\n   * @param data\n   * @returns\n   */\n  createDocument(data?: IPublicTypeRootSchema): IPublicModelDocumentModel | null {\n    const doc = this[projectSymbol].createDocument(data);\n    return ShellDocumentModel.create(doc);\n  }\n\n  /**\n   * 删除一个 document\n   * @param doc\n   */\n  removeDocument(doc: IPublicModelDocumentModel) {\n    this[projectSymbol].removeDocument((doc as any)[documentSymbol]);\n  }\n\n  /**\n   * 根据 fileName 获取 document\n   * @param fileName\n   * @returns\n   */\n  getDocumentByFileName(fileName: string): IPublicModelDocumentModel | null {\n    const innerDocumentModel = this[projectSymbol].getDocumentByFileName(fileName);\n    return ShellDocumentModel.create(innerDocumentModel);\n  }\n\n  /**\n   * 根据 id 获取 document\n   * @param id\n   * @returns\n   */\n  getDocumentById(id: string): IPublicModelDocumentModel | null {\n    return ShellDocumentModel.create(this[projectSymbol].getDocument(id));\n  }\n\n  /**\n   * 导出 project\n   * @returns\n   */\n  exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render) {\n    return this[projectSymbol].getSchema(stage);\n  }\n\n  /**\n   * 导入 project\n   * @param schema 待导入的 project 数据\n   */\n  importSchema(schema?: IPublicTypeProjectSchema): void {\n    this[projectSymbol].load(schema, true);\n  }\n\n  /**\n   * 获取当前的 document\n   * @returns\n   */\n  getCurrentDocument(): IPublicModelDocumentModel | null {\n    return ShellDocumentModel.create(this[projectSymbol].currentDocument);\n  }\n\n  /**\n   * 增加一个属性的管道处理函数\n   * @param transducer\n   * @param stage\n   */\n  addPropsTransducer(\n      transducer: IPublicTypePropsTransducer,\n      stage: IPublicEnumTransformStage,\n    ): void {\n    this[projectSymbol].designer.addPropsReducer(transducer, stage);\n  }\n\n  /**\n   * 绑定删除文档事件\n   * @param fn\n   * @returns\n   */\n  onRemoveDocument(fn: (data: { id: string}) => void): IPublicTypeDisposable {\n    return this[editorSymbol].eventBus.on(\n        'designer.document.remove',\n        (data: { id: string }) => fn(data),\n      );\n  }\n\n  /**\n   * 当前 project 内的 document 变更事件\n   */\n  onChangeDocument(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable {\n    const offFn = this[projectSymbol].onCurrentDocumentChange((originalDoc) => {\n      fn(ShellDocumentModel.create(originalDoc)!);\n    });\n    if (this[projectSymbol].currentDocument) {\n      fn(ShellDocumentModel.create(this[projectSymbol].currentDocument)!);\n    }\n    return offFn;\n  }\n\n  /**\n   * 当前 project 的模拟器 ready 事件\n   */\n  onSimulatorHostReady(fn: (host: IPublicApiSimulatorHost) => void): IPublicTypeDisposable {\n    const offFn = this[projectSymbol].onSimulatorReady((simulator: BuiltinSimulatorHost) => {\n      fn(SimulatorHost.create(simulator)!);\n    });\n    return offFn;\n  }\n\n  /**\n   * 当前 project 的渲染器 ready 事件\n   */\n  onSimulatorRendererReady(fn: () => void): IPublicTypeDisposable {\n    const offFn = this[projectSymbol].onRendererReady(() => {\n      fn();\n    });\n    return offFn;\n  }\n\n  /**\n   * 设置多语言语料\n   * 数据格式参考 https://github.com/alibaba/lowcode-engine/blob/main/specs/lowcode-spec.md#2434%E5%9B%BD%E9%99%85%E5%8C%96%E5%A4%9A%E8%AF%AD%E8%A8%80%E7%B1%BB%E5%9E%8Baa\n   * @param value object\n   * @returns\n   */\n  setI18n(value: object): void {\n    this[projectSymbol].set('i18n', value);\n  }\n\n  /**\n   * 设置项目配置\n   * @param value object\n   * @returns\n   */\n  setConfig<T extends keyof IPublicTypeAppConfig>(key: T, value: IPublicTypeAppConfig[T]): void;\n  setConfig(value: IPublicTypeAppConfig): void;\n  setConfig(...params: any[]): void {\n    if (params.length === 2) {\n      const oldConfig = this[projectSymbol].get('config');\n      this[projectSymbol].set('config', {\n        ...oldConfig,\n        [params[0]]: params[1],\n      });\n    } else {\n      this[projectSymbol].set('config', params[0]);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/setters.ts",
    "content": "import { IPublicTypeCustomView, IPublicApiSetters, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types';\nimport { ISetters, globalContext, untracked } from '@alilc/lowcode-editor-core';\nimport { ReactNode } from 'react';\nimport { getLogger } from '@alilc/lowcode-utils';\n\nconst innerSettersSymbol = Symbol('setters');\nconst settersSymbol = Symbol('setters');\n\nconst logger = getLogger({ level: 'warn', bizName: 'shell-setters' });\n\nexport class Setters implements IPublicApiSetters {\n  readonly [innerSettersSymbol]: ISetters;\n\n  get [settersSymbol](): ISetters {\n    if (this.workspaceMode) {\n      return this[innerSettersSymbol];\n    }\n\n    const workspace = globalContext.get('workspace');\n    if (workspace.isActive) {\n      return untracked(() => {\n        if (!workspace.window?.innerSetters) {\n          logger.error('setter api 调用时机出现问题，请检查');\n          return this[innerSettersSymbol];\n        }\n        return workspace.window.innerSetters;\n      });\n    }\n\n    return this[innerSettersSymbol];\n  }\n\n  constructor(innerSetters: ISetters, readonly workspaceMode = false) {\n    this[innerSettersSymbol] = innerSetters;\n  }\n\n  /**\n   * 获取指定 setter\n   * @param type\n   * @returns\n   */\n  getSetter = (type: string) => {\n    return this[settersSymbol].getSetter(type);\n  };\n\n  /**\n   * 获取已注册的所有 settersMap\n   * @returns\n   */\n  getSettersMap = (): Map<string, IPublicTypeRegisteredSetter & {\n    type: string;\n  }> => {\n    return this[settersSymbol].getSettersMap();\n  };\n\n  /**\n   * 注册一个 setter\n   * @param typeOrMaps\n   * @param setter\n   * @returns\n   */\n  registerSetter = (\n    typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter },\n    setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter | undefined,\n  ) => {\n    return this[settersSymbol].registerSetter(typeOrMaps, setter);\n  };\n\n  /**\n   * @deprecated\n   */\n  createSetterContent = (setter: any, props: Record<string, any>): ReactNode => {\n    return this[settersSymbol].createSetterContent(setter, props);\n  };\n}\n"
  },
  {
    "path": "packages/shell/src/api/simulator-host.ts",
    "content": "import {\n  BuiltinSimulatorHost,\n} from '@alilc/lowcode-designer';\nimport { simulatorHostSymbol, nodeSymbol } from '../symbols';\nimport { IPublicApiSimulatorHost, IPublicModelNode, IPublicModelSimulatorRender } from '@alilc/lowcode-types';\nimport { SimulatorRender } from '../model/simulator-render';\n\nexport class SimulatorHost implements IPublicApiSimulatorHost {\n  private readonly [simulatorHostSymbol]: BuiltinSimulatorHost;\n\n  constructor(simulator: BuiltinSimulatorHost) {\n    this[simulatorHostSymbol] = simulator;\n  }\n\n  static create(host: BuiltinSimulatorHost): IPublicApiSimulatorHost | null {\n    if (!host) return null;\n    return new SimulatorHost(host);\n  }\n\n  /**\n   * 获取 contentWindow\n   */\n  get contentWindow(): Window | undefined {\n    return this[simulatorHostSymbol].contentWindow;\n  }\n\n  /**\n   * 获取 contentDocument\n   */\n  get contentDocument(): Document | undefined {\n    return this[simulatorHostSymbol].contentDocument;\n  }\n\n  get renderer(): IPublicModelSimulatorRender | undefined {\n    if (this[simulatorHostSymbol].renderer) {\n      return SimulatorRender.create(this[simulatorHostSymbol].renderer);\n    }\n\n    return undefined;\n  }\n\n  /**\n   * 设置 host 配置值\n   * @param key\n   * @param value\n   */\n  set(key: string, value: any): void {\n    this[simulatorHostSymbol].set(key, value);\n  }\n\n  /**\n   * 获取 host 配置值\n   * @param key\n   * @returns\n   */\n  get(key: string): any {\n    return this[simulatorHostSymbol].get(key);\n  }\n\n  /**\n   * scroll to specific node\n   * @param node\n   */\n  scrollToNode(node: IPublicModelNode): void {\n    this[simulatorHostSymbol].scrollToNode((node as any)[nodeSymbol]);\n  }\n\n  /**\n   * 触发组件构建，并刷新渲染画布\n   */\n  rerender(): void {\n    this[simulatorHostSymbol].rerender();\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/skeleton.ts",
    "content": "import { globalContext } from '@alilc/lowcode-editor-core';\nimport {\n  ISkeleton,\n  SkeletonEvents,\n} from '@alilc/lowcode-editor-skeleton';\nimport { skeletonSymbol } from '../symbols';\nimport { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types';\nimport { getLogger } from '@alilc/lowcode-utils';\nimport { SkeletonItem } from '../model/skeleton-item';\n\nconst innerSkeletonSymbol = Symbol('skeleton');\n\nconst logger = getLogger({ level: 'warn', bizName: 'shell-skeleton' });\n\nexport class Skeleton implements IPublicApiSkeleton {\n  private readonly [innerSkeletonSymbol]: ISkeleton;\n  private readonly pluginName: string;\n\n  get [skeletonSymbol](): ISkeleton {\n    if (this.workspaceMode) {\n      return this[innerSkeletonSymbol];\n    }\n    const workspace = globalContext.get('workspace');\n    if (workspace.isActive) {\n      if (!workspace.window?.innerSkeleton) {\n        logger.error('skeleton api 调用时机出现问题，请检查');\n        return this[innerSkeletonSymbol];\n      }\n      return workspace.window.innerSkeleton;\n    }\n\n    return this[innerSkeletonSymbol];\n  }\n\n  constructor(\n      skeleton: ISkeleton,\n      pluginName: string,\n      readonly workspaceMode: boolean = false,\n    ) {\n    this[innerSkeletonSymbol] = skeleton;\n    this.pluginName = pluginName;\n  }\n\n  /**\n   * 增加一个面板实例\n   * @param config\n   * @param extraConfig\n   * @returns\n   */\n  add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IPublicModelSkeletonItem | undefined {\n    const configWithName = {\n      ...config,\n      pluginName: this.pluginName,\n    };\n    const item = this[skeletonSymbol].add(configWithName, extraConfig);\n    if (item) {\n      return new SkeletonItem(item);\n    }\n  }\n\n  /**\n   * 移除一个面板实例\n   * @param config\n   * @returns\n   */\n  remove(config: IPublicTypeSkeletonConfig): number | undefined {\n    const { area, name } = config;\n    const skeleton = this[skeletonSymbol];\n    if (!normalizeArea(area)) {\n      return;\n    }\n    skeleton[normalizeArea(area)].container?.remove(name);\n  }\n\n  getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] {\n    return this[skeletonSymbol][normalizeArea(areaName)].container.items?.map(d => new SkeletonItem(d));\n  }\n\n  getPanel(name: string) {\n    const item = this[skeletonSymbol].getPanel(name);\n    if (!item) {\n      return;\n    }\n\n    return new SkeletonItem(item);\n  }\n\n  /**\n   * 显示面板\n   * @param name\n   */\n  showPanel(name: string) {\n    this[skeletonSymbol].getPanel(name)?.show();\n  }\n\n  /**\n   * 隐藏面板\n   * @param name\n   */\n  hidePanel(name: string) {\n    this[skeletonSymbol].getPanel(name)?.hide();\n  }\n\n  /**\n   * 显示 widget\n   * @param name\n   */\n  showWidget(name: string) {\n    this[skeletonSymbol].getWidget(name)?.show();\n  }\n\n  /**\n   * enable widget\n   * @param name\n   */\n  enableWidget(name: string) {\n    this[skeletonSymbol].getWidget(name)?.enable?.();\n  }\n\n  /**\n   * 隐藏 widget\n   * @param name\n   */\n  hideWidget(name: string) {\n    this[skeletonSymbol].getWidget(name)?.hide();\n  }\n\n  /**\n   * disable widget，不可点击\n   * @param name\n   */\n  disableWidget(name: string) {\n    this[skeletonSymbol].getWidget(name)?.disable?.();\n  }\n\n  /**\n   * show area\n   * @param areaName name of area\n   */\n  showArea(areaName: string) {\n    (this[skeletonSymbol] as any)[areaName]?.show();\n  }\n\n  /**\n   * hide area\n   * @param areaName name of area\n   */\n  hideArea(areaName: string) {\n    (this[skeletonSymbol] as any)[areaName]?.hide();\n  }\n\n  /**\n   * 监听 panel 显示事件\n   * @param listener\n   * @returns\n   */\n  onShowPanel(listener: (paneName: string, panel: IPublicModelSkeletonItem) => void): IPublicTypeDisposable {\n    const { editor } = this[skeletonSymbol];\n    editor.eventBus.on(SkeletonEvents.PANEL_SHOW, (name: any, panel: any) => {\n      listener(name, new SkeletonItem(panel));\n    });\n    return () => editor.eventBus.off(SkeletonEvents.PANEL_SHOW, listener);\n  }\n\n  onDisableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {\n    const { editor } = this[skeletonSymbol];\n    editor.eventBus.on(SkeletonEvents.WIDGET_DISABLE, (name: any, panel: any) => {\n      listener(name, new SkeletonItem(panel));\n    });\n    return () => editor.eventBus.off(SkeletonEvents.WIDGET_DISABLE, listener);\n  }\n\n  onEnableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {\n    const { editor } = this[skeletonSymbol];\n    editor.eventBus.on(SkeletonEvents.WIDGET_ENABLE, (name: any, panel: any) => {\n      listener(name, new SkeletonItem(panel));\n    });\n    return () => editor.eventBus.off(SkeletonEvents.WIDGET_ENABLE, listener);\n  }\n\n  /**\n   * 监听 panel 隐藏事件\n   * @param listener\n   * @returns\n   */\n  onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable {\n    const { editor } = this[skeletonSymbol];\n    editor.eventBus.on(SkeletonEvents.PANEL_HIDE, (name: any, panel: any) => {\n      listener(name, new SkeletonItem(panel));\n    });\n    return () => editor.eventBus.off(SkeletonEvents.PANEL_HIDE, listener);\n  }\n\n  /**\n   * 监听 widget 显示事件\n   * @param listener\n   * @returns\n   */\n  onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {\n    const { editor } = this[skeletonSymbol];\n    editor.eventBus.on(SkeletonEvents.WIDGET_SHOW, (name: any, panel: any) => {\n      listener(name, new SkeletonItem(panel));\n    });\n    return () => editor.eventBus.off(SkeletonEvents.WIDGET_SHOW, listener);\n  }\n\n  /**\n   * 监听 widget 隐藏事件\n   * @param listener\n   * @returns\n   */\n  onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {\n    const { editor } = this[skeletonSymbol];\n    editor.eventBus.on(SkeletonEvents.WIDGET_HIDE, (name: any, panel: any) => {\n      listener(name, new SkeletonItem(panel));\n    });\n    return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener);\n  }\n\n  registerConfigTransducer(fn: IPublicTypeConfigTransducer, level: number, id?: string) {\n    this[skeletonSymbol].registerConfigTransducer(fn, level, id);\n  }\n}\n\nfunction normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' | 'subTopArea' {\n  switch (area) {\n    case 'leftArea':\n    case 'left':\n      return 'leftArea';\n    case 'rightArea':\n    case 'right':\n      return 'rightArea';\n    case 'topArea':\n    case 'top':\n      return 'topArea';\n    case 'toolbar':\n      return 'toolbar';\n    case 'mainArea':\n    case 'main':\n    case 'center':\n    case 'centerArea':\n      return 'mainArea';\n    case 'bottomArea':\n    case 'bottom':\n      return 'bottomArea';\n    case 'leftFixedArea':\n      return 'leftFixedArea';\n    case 'leftFloatArea':\n      return 'leftFloatArea';\n    case 'stages':\n      return 'stages';\n    case 'subTopArea':\n      return 'subTopArea';\n    default:\n      throw new Error(`${area} not supported`);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/api/workspace.ts",
    "content": "import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';\nimport { IWorkspace } from '@alilc/lowcode-workspace';\nimport { resourceSymbol, workspaceSymbol } from '../symbols';\nimport { Resource as ShellResource, Window as ShellWindow } from '../model';\nimport { Plugins } from './plugins';\nimport { Skeleton } from './skeleton';\n\nexport class Workspace implements IPublicApiWorkspace {\n  readonly [workspaceSymbol]: IWorkspace;\n\n  constructor(innerWorkspace: IWorkspace) {\n    this[workspaceSymbol] = innerWorkspace;\n  }\n\n  get resourceList() {\n    return this[workspaceSymbol].getResourceList().map((d) => new ShellResource(d));\n  }\n\n  setResourceList(resourceList: IPublicResourceList) {\n    this[workspaceSymbol].setResourceList(resourceList);\n  }\n\n  onResourceListChange(fn: (resourceList: IPublicResourceList) => void): IPublicTypeDisposable {\n    return this[workspaceSymbol].onResourceListChange(fn);\n  }\n\n  get isActive() {\n    return this[workspaceSymbol].isActive;\n  }\n\n  get window() {\n    if (!this[workspaceSymbol].window) {\n      return null;\n    }\n    return new ShellWindow(this[workspaceSymbol].window);\n  }\n\n  get resourceTypeList() {\n    return Array.from(this[workspaceSymbol].resourceTypeMap.values()).map((d) => {\n      const { name: resourceName, type: resourceType } = d;\n      const {\n        description,\n        editorViews,\n      } = d.resourceTypeModel({} as any, {});\n\n      return {\n        resourceName,\n        resourceType,\n        description,\n        editorViews: editorViews.map(d => (\n          {\n            viewName: d.viewName,\n            viewType: d.viewType || 'editor',\n          }\n        )),\n      };\n    });\n  }\n\n  onWindowRendererReady(fn: () => void): IPublicTypeDisposable {\n    return this[workspaceSymbol].onWindowRendererReady(fn);\n  }\n\n  registerResourceType(resourceTypeModel: IPublicTypeResourceType): void {\n    this[workspaceSymbol].registerResourceType(resourceTypeModel);\n  }\n\n  async openEditorWindow(): Promise<void> {\n    if (typeof arguments[0] === 'string') {\n      await this[workspaceSymbol].openEditorWindow(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);\n    } else {\n      await this[workspaceSymbol].openEditorWindowByResource(arguments[0]?.[resourceSymbol], arguments[1]);\n    }\n  }\n\n  openEditorWindowById(id: string) {\n    this[workspaceSymbol].openEditorWindowById(id);\n  }\n\n  removeEditorWindow() {\n    if (typeof arguments[0] === 'string') {\n      this[workspaceSymbol].removeEditorWindow(arguments[0], arguments[1]);\n    } else {\n      this[workspaceSymbol].removeEditorWindowByResource(arguments[0]?.[resourceSymbol]);\n    }\n  }\n\n  removeEditorWindowById(id: string) {\n    this[workspaceSymbol].removeEditorWindowById(id);\n  }\n\n  get plugins() {\n    return new Plugins(this[workspaceSymbol].plugins, true).toProxy();\n  }\n\n  get skeleton() {\n    return new Skeleton(this[workspaceSymbol].skeleton, 'workspace', true);\n  }\n\n  get windows() {\n    return this[workspaceSymbol].windows.map((d) => new ShellWindow(d));\n  }\n\n  onChangeWindows(fn: () => void): IPublicTypeDisposable {\n    return this[workspaceSymbol].onChangeWindows(fn);\n  }\n\n  onChangeActiveWindow(fn: () => void): IPublicTypeDisposable {\n    return this[workspaceSymbol].onChangeActiveWindow(fn);\n  }\n\n  onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable {\n    return this[workspaceSymbol].onChangeActiveEditorView(fn);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/components/context-menu.tsx",
    "content": "import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils';\nimport { engineConfig } from '@alilc/lowcode-editor-core';\nimport { IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types';\nimport React, { useCallback } from 'react';\n\nexport function ContextMenu({ children, menus, pluginContext }: {\n  menus: IPublicTypeContextMenuAction[];\n  children: React.ReactElement[] | React.ReactElement;\n  pluginContext: IPublicModelPluginContext;\n}): React.ReactElement<any, string | React.JSXElementConstructor<any>> {\n  const handleContextMenu = useCallback((event: React.MouseEvent) => {\n    event.preventDefault();\n    event.stopPropagation();\n\n    let destroyFn: Function | undefined;\n    const destroy = () => {\n      destroyFn?.();\n    };\n    const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, {\n      destroy,\n      pluginContext,\n    }), { pluginContext });\n\n    if (!children?.length) {\n      return;\n    }\n\n    destroyFn = createContextMenu(children, { event });\n  }, [menus]);\n\n  if (!engineConfig.get('enableContextMenu')) {\n    return (\n      <>{ children }</>\n    );\n  }\n\n  if (!menus) {\n    return (\n      <>{ children }</>\n    );\n  }\n\n  // 克隆 children 并添加 onContextMenu 事件处理器\n  const childrenWithContextMenu = React.Children.map(children, (child) =>\n    React.cloneElement(\n      child,\n      { onContextMenu: handleContextMenu },\n    ));\n\n  return (\n    <>{childrenWithContextMenu}</>\n  );\n}\n\nContextMenu.create = (pluginContext: IPublicModelPluginContext, menus: IPublicTypeContextMenuAction[], event: MouseEvent) => {\n  event.preventDefault();\n  event.stopPropagation();\n\n  const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, {\n    pluginContext,\n  }), {\n    pluginContext,\n  });\n\n  if (!children?.length) {\n    return;\n  }\n\n  return createContextMenu(children, {\n    event,\n  });\n};"
  },
  {
    "path": "packages/shell/src/index.ts",
    "content": "import {\n  Detecting,\n  DocumentModel,\n  History,\n  Node,\n  NodeChildren,\n  Prop,\n  Selection,\n  Dragon,\n  SettingTopEntry,\n  Clipboard,\n  SettingField,\n  Window,\n  SkeletonItem,\n} from './model';\nimport {\n  Project,\n  Material,\n  Logger,\n  Plugins,\n  Skeleton,\n  Setters,\n  Hotkey,\n  Common,\n  getEvent,\n  Event,\n  Canvas,\n  Workspace,\n  SimulatorHost,\n  Config,\n  CommonUI,\n  Command,\n} from './api';\n\nexport * from './symbols';\n\n/**\n * 所有 shell 层模型的 API 设计约定：\n *  1. 所有 API 命名空间都按照 variables / functions / events 来组织\n *  2. 事件（events）的命名格式为：on[Will|Did]VerbNoun?，参考 https://code.visualstudio.com/api/references/vscode-api#events\n *  3. 基于 Disposable 模式，对于事件的绑定、快捷键的绑定函数，返回值则是解绑函数\n *  4. 对于属性的导出，统一用 .xxx 的 getter 模式，不能使用 .getXxx()\n */\nexport {\n  DocumentModel,\n  Detecting,\n  Event,\n  History,\n  Material,\n  Node,\n  NodeChildren,\n  Project,\n  Prop,\n  Selection,\n  Setters,\n  Hotkey,\n  Window,\n  Skeleton,\n  SettingField as SettingPropEntry,\n  SettingTopEntry,\n  Dragon,\n  Common,\n  getEvent,\n  Plugins,\n  Logger,\n  Canvas,\n  Workspace,\n  Clipboard,\n  SimulatorHost,\n  Config,\n  SettingField,\n  SkeletonItem,\n  CommonUI,\n  Command,\n};\n"
  },
  {
    "path": "packages/shell/src/model/active-tracker.ts",
    "content": "import { IPublicModelActiveTracker, IPublicModelNode, IPublicTypeActiveTarget } from '@alilc/lowcode-types';\nimport { IActiveTracker as InnerActiveTracker, ActiveTarget } from '@alilc/lowcode-designer';\nimport { Node as ShellNode } from './node';\nimport { nodeSymbol } from '../symbols';\n\nconst activeTrackerSymbol = Symbol('activeTracker');\n\nexport class ActiveTracker implements IPublicModelActiveTracker {\n  private readonly [activeTrackerSymbol]: InnerActiveTracker;\n\n  constructor(innerTracker: InnerActiveTracker) {\n    this[activeTrackerSymbol] = innerTracker;\n  }\n\n  get target() {\n    const _target = this[activeTrackerSymbol]._target;\n\n    if (!_target) {\n      return null;\n    }\n\n    const { node: innerNode, detail, instance } = _target;\n    const publicNode = ShellNode.create(innerNode);\n    return {\n      node: publicNode!,\n      detail,\n      instance,\n    };\n  }\n\n  onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void {\n    if (!fn) {\n      return () => {};\n    }\n    return this[activeTrackerSymbol].onChange((t: ActiveTarget) => {\n      const { node: innerNode, detail, instance } = t;\n      const publicNode = ShellNode.create(innerNode);\n      const publicActiveTarget = {\n        node: publicNode!,\n        detail,\n        instance,\n      };\n      fn(publicActiveTarget);\n    });\n  }\n\n  track(node: IPublicModelNode) {\n    this[activeTrackerSymbol].track((node as any)[nodeSymbol]);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/clipboard.ts",
    "content": "import { IPublicModelClipboard } from '@alilc/lowcode-types';\nimport { clipboardSymbol } from '../symbols';\nimport { IClipboard, clipboard } from '@alilc/lowcode-designer';\n\nexport class Clipboard implements IPublicModelClipboard {\n  private readonly [clipboardSymbol]: IClipboard;\n\n  constructor() {\n    this[clipboardSymbol] = clipboard;\n  }\n\n  setData(data: any): void {\n    this[clipboardSymbol].setData(data);\n  }\n\n  waitPasteData(\n      keyboardEvent: KeyboardEvent,\n      cb: (data: any, clipboardEvent: ClipboardEvent) => void,\n    ): void {\n    this[clipboardSymbol].waitPasteData(keyboardEvent, cb);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/component-meta.ts",
    "content": "import {\n  IComponentMeta as InnerComponentMeta,\n  INode,\n} from '@alilc/lowcode-designer';\nimport { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicModelComponentMeta, IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeTransformedComponentMetadata, IPublicModelNode, IPublicTypeAdvanced, IPublicTypeFieldConfig } from '@alilc/lowcode-types';\nimport { componentMetaSymbol, nodeSymbol } from '../symbols';\nimport { ReactElement } from 'react';\n\nexport class ComponentMeta implements IPublicModelComponentMeta {\n  private readonly [componentMetaSymbol]: InnerComponentMeta;\n\n  isComponentMeta = true;\n\n  constructor(componentMeta: InnerComponentMeta) {\n    this[componentMetaSymbol] = componentMeta;\n  }\n\n  static create(componentMeta: InnerComponentMeta | null): IPublicModelComponentMeta | null {\n    if (!componentMeta) {\n      return null;\n    }\n    return new ComponentMeta(componentMeta);\n  }\n\n  /**\n   * 组件名\n   */\n  get componentName(): string {\n    return this[componentMetaSymbol].componentName;\n  }\n\n  /**\n   * 是否是「容器型」组件\n   */\n  get isContainer(): boolean {\n    return this[componentMetaSymbol].isContainer;\n  }\n\n  /**\n   * 是否是最小渲染单元。\n   * 当组件需要重新渲染时：\n   *  若为最小渲染单元，则只渲染当前组件，\n   *  若不为最小渲染单元，则寻找到上层最近的最小渲染单元进行重新渲染，直至根节点。\n   */\n  get isMinimalRenderUnit(): boolean {\n    return this[componentMetaSymbol].isMinimalRenderUnit;\n  }\n\n  /**\n   * 是否为「模态框」组件\n   */\n  get isModal(): boolean {\n    return this[componentMetaSymbol].isModal;\n  }\n\n  /**\n   * 元数据配置\n   */\n  get configure(): IPublicTypeFieldConfig[] {\n    return this[componentMetaSymbol].configure;\n  }\n\n  /**\n   * 标题\n   */\n  get title(): string | IPublicTypeI18nData | ReactElement {\n    return this[componentMetaSymbol].title;\n  }\n\n  /**\n   * 图标\n   */\n  get icon(): IPublicTypeIconType {\n    return this[componentMetaSymbol].icon;\n  }\n\n  /**\n   * 组件 npm 信息\n   */\n  get npm(): IPublicTypeNpmInfo {\n    return this[componentMetaSymbol].npm;\n  }\n\n  /**\n   * @deprecated\n   */\n  get prototype() {\n    return (this[componentMetaSymbol] as any).prototype;\n  }\n\n  get availableActions(): any {\n    return this[componentMetaSymbol].availableActions;\n  }\n\n  get advanced(): IPublicTypeAdvanced {\n    return this[componentMetaSymbol].advanced;\n  }\n\n  /**\n   * 设置 npm 信息\n   * @param npm\n   */\n  setNpm(npm: IPublicTypeNpmInfo): void {\n    this[componentMetaSymbol].setNpm(npm);\n  }\n\n  /**\n   * 获取元数据\n   * @returns\n   */\n  getMetadata(): IPublicTypeTransformedComponentMetadata {\n    return this[componentMetaSymbol].getMetadata();\n  }\n\n  /**\n   * check if the current node could be placed in parent node\n   * @param my\n   * @param parent\n   * @returns\n   */\n  checkNestingUp(my: IPublicModelNode | IPublicTypeNodeData, parent: INode): boolean {\n    const curNode = (my as any).isNode ? (my as any)[nodeSymbol] : my;\n    return this[componentMetaSymbol].checkNestingUp(curNode as any, parent);\n  }\n\n  /**\n   * check if the target node(s) could be placed in current node\n   * @param my\n   * @param parent\n   * @returns\n   */\n  checkNestingDown(\n      my: IPublicModelNode | IPublicTypeNodeData,\n      target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[],\n    ) {\n    const curNode = (my as any)?.isNode ? (my as any)[nodeSymbol] : my;\n    return this[componentMetaSymbol].checkNestingDown(\n        curNode as any,\n        (target as any)[nodeSymbol] || target,\n      );\n  }\n\n  refreshMetadata(): void {\n    this[componentMetaSymbol].refreshMetadata();\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/condition-group.ts",
    "content": "import type { IExclusiveGroup } from '@alilc/lowcode-designer';\nimport { IPublicModelExclusiveGroup, IPublicModelNode } from '@alilc/lowcode-types';\nimport { conditionGroupSymbol, nodeSymbol } from '../symbols';\nimport { Node } from './node';\n\nexport class ConditionGroup implements IPublicModelExclusiveGroup {\n  private [conditionGroupSymbol]: IExclusiveGroup | null;\n\n  constructor(conditionGroup: IExclusiveGroup | null) {\n    this[conditionGroupSymbol] = conditionGroup;\n  }\n\n  get id() {\n    return this[conditionGroupSymbol]?.id;\n  }\n\n  get title() {\n    return this[conditionGroupSymbol]?.title;\n  }\n\n  get firstNode() {\n    return Node.create(this[conditionGroupSymbol]?.firstNode);\n  }\n\n  setVisible(node: IPublicModelNode) {\n    this[conditionGroupSymbol]?.setVisible((node as any)[nodeSymbol] ? (node as any)[nodeSymbol] : node);\n  }\n\n  static create(conditionGroup: IExclusiveGroup | null) {\n    if (!conditionGroup) {\n      return null;\n    }\n    // @ts-ignore\n    if (conditionGroup[conditionGroupSymbol]) {\n      return (conditionGroup as any)[conditionGroupSymbol];\n    }\n    const shellConditionGroup = new ConditionGroup(conditionGroup);\n    // @ts-ignore\n    shellConditionGroup[conditionGroupSymbol] = shellConditionGroup;\n    return shellConditionGroup;\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/detecting.ts",
    "content": "import { Node as ShellNode } from './node';\nimport {\n  Detecting as InnerDetecting,\n  IDocumentModel as InnerDocumentModel,\n  INode as InnerNode,\n} from '@alilc/lowcode-designer';\nimport { documentSymbol, detectingSymbol } from '../symbols';\nimport { IPublicModelDetecting, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types';\n\nexport class Detecting implements IPublicModelDetecting {\n  private readonly [documentSymbol]: InnerDocumentModel;\n  private readonly [detectingSymbol]: InnerDetecting;\n\n  constructor(document: InnerDocumentModel) {\n    this[documentSymbol] = document;\n    this[detectingSymbol] = document.designer?.detecting;\n  }\n\n  /**\n   * 控制大纲树 hover 时是否出现悬停效果\n   */\n  get enable(): boolean {\n    return this[detectingSymbol].enable;\n  }\n\n  /**\n   * 当前 hover 的节点\n   */\n  get current() {\n    return ShellNode.create(this[detectingSymbol].current);\n  }\n\n  /**\n   * hover 指定节点\n   * @param id 节点 id\n   */\n  capture(id: string) {\n    this[detectingSymbol].capture(this[documentSymbol].getNode(id));\n  }\n\n  /**\n   * hover 离开指定节点\n   * @param id 节点 id\n   */\n  release(id: string) {\n    this[detectingSymbol].release(this[documentSymbol].getNode(id));\n  }\n\n  /**\n   * 清空 hover 态\n   */\n  leave() {\n    this[detectingSymbol].leave(this[documentSymbol]);\n  }\n\n  onDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable {\n    const innerFn = (innerNode: InnerNode) => {\n      const shellNode = ShellNode.create(innerNode);\n      fn(shellNode);\n    };\n    return this[detectingSymbol].onDetectingChange(innerFn);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/document-model.ts",
    "content": "import {\n  IDocumentModel as InnerDocumentModel,\n  INode as InnerNode,\n} from '@alilc/lowcode-designer';\nimport {\n  IPublicEnumTransformStage,\n  IPublicTypeRootSchema,\n  GlobalEvent,\n  IPublicModelDocumentModel,\n  IPublicTypeOnChangeOptions,\n  IPublicTypeDragNodeObject,\n  IPublicTypeDragNodeDataObject,\n  IPublicModelNode,\n  IPublicModelSelection,\n  IPublicModelDetecting,\n  IPublicModelHistory,\n  IPublicApiProject,\n  IPublicModelModalNodesManager,\n  IPublicTypePropChangeOptions,\n  IPublicModelDropLocation,\n  IPublicApiCanvas,\n  IPublicTypeDisposable,\n  IPublicModelEditor,\n  IPublicTypeNodeSchema,\n} from '@alilc/lowcode-types';\nimport { isDragNodeObject } from '@alilc/lowcode-utils';\nimport { Node as ShellNode } from './node';\nimport { Selection as ShellSelection } from './selection';\nimport { Detecting as ShellDetecting } from './detecting';\nimport { History as ShellHistory } from './history';\nimport { DropLocation as ShellDropLocation } from './drop-location';\nimport { Project as ShellProject, Canvas as ShellCanvas } from '../api';\nimport { Prop as ShellProp } from './prop';\nimport { ModalNodesManager } from './modal-nodes-manager';\nimport { documentSymbol, editorSymbol, nodeSymbol } from '../symbols';\n\nconst shellDocSymbol = Symbol('shellDocSymbol');\n\nexport class DocumentModel implements IPublicModelDocumentModel {\n  private readonly [documentSymbol]: InnerDocumentModel;\n  private readonly [editorSymbol]: IPublicModelEditor;\n  private _focusNode: IPublicModelNode | null;\n  selection: IPublicModelSelection;\n  detecting: IPublicModelDetecting;\n  history: IPublicModelHistory;\n\n  /**\n   * @deprecated use canvas API instead\n   */\n  canvas: IPublicApiCanvas;\n\n  constructor(document: InnerDocumentModel) {\n    this[documentSymbol] = document;\n    this[editorSymbol] = document.designer?.editor as IPublicModelEditor;\n    this.selection = new ShellSelection(document);\n    this.detecting = new ShellDetecting(document);\n    this.history = new ShellHistory(document);\n    this.canvas = new ShellCanvas(this[editorSymbol]);\n\n    this._focusNode = ShellNode.create(this[documentSymbol].focusNode);\n  }\n\n  static create(document: InnerDocumentModel | undefined | null): IPublicModelDocumentModel | null {\n    if (!document) {\n      return null;\n    }\n    // @ts-ignore 直接返回已挂载的 shell doc 实例\n    if (document[shellDocSymbol]) {\n      return (document as any)[shellDocSymbol];\n    }\n    const shellDoc = new DocumentModel(document);\n    // @ts-ignore 直接返回已挂载的 shell doc 实例\n    document[shellDocSymbol] = shellDoc;\n    return shellDoc;\n  }\n\n  /**\n   * id\n   */\n  get id(): string {\n    return this[documentSymbol].id;\n  }\n\n  set id(id) {\n    this[documentSymbol].id = id;\n  }\n\n  /**\n   * 获取当前文档所属的 project\n   * @returns\n   */\n  get project(): IPublicApiProject {\n    return ShellProject.create(this[documentSymbol].project, true);\n  }\n\n  /**\n   * 获取文档的根节点\n   * root node of this documentModel\n   * @returns\n   */\n  get root(): IPublicModelNode | null {\n    return ShellNode.create(this[documentSymbol].rootNode);\n  }\n\n  get focusNode(): IPublicModelNode | null {\n    return this._focusNode || this.root;\n  }\n\n  set focusNode(node: IPublicModelNode | null) {\n    this._focusNode = node;\n    this[editorSymbol].eventBus.emit(\n      'shell.document.focusNodeChanged',\n        { document: this, focusNode: node },\n      );\n  }\n\n  /**\n   * 获取文档下所有节点 Map, key 为 nodeId\n   * get map of all nodes , using node.id as key\n   */\n  get nodesMap(): Map<string, IPublicModelNode> {\n    const map = new Map<string, IPublicModelNode>();\n    for (let id of this[documentSymbol].nodesMap.keys()) {\n      map.set(id, this.getNodeById(id)!);\n    }\n    return map;\n  }\n\n  /**\n   * 模态节点管理\n   */\n  get modalNodesManager(): IPublicModelModalNodesManager | null {\n    return ModalNodesManager.create(this[documentSymbol].modalNodesManager);\n  }\n\n  get dropLocation(): IPublicModelDropLocation | null {\n    return ShellDropLocation.create(this[documentSymbol].dropLocation);\n  }\n\n  set dropLocation(loc: IPublicModelDropLocation | null) {\n    this[documentSymbol].dropLocation = loc;\n  }\n\n  /**\n   * 根据 nodeId 返回 Node 实例\n   * get node instance by nodeId\n   * @param {string} nodeId\n   */\n  getNodeById(nodeId: string): IPublicModelNode | null {\n    return ShellNode.create(this[documentSymbol].getNode(nodeId));\n  }\n\n  /**\n   * 导入 schema\n   * @param schema\n   */\n  importSchema(schema: IPublicTypeRootSchema): void {\n    this[documentSymbol].import(schema);\n    this[editorSymbol].eventBus.emit('shell.document.importSchema', schema);\n  }\n\n  /**\n   * 导出 schema\n   * @param stage\n   * @returns\n   */\n  exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render): IPublicTypeRootSchema | undefined {\n    return this[documentSymbol].export(stage);\n  }\n\n  /**\n   * 插入节点\n   * @param parent\n   * @param thing\n   * @param at\n   * @param copy\n   * @returns\n   */\n  insertNode(\n    parent: IPublicModelNode,\n    thing: IPublicModelNode,\n    at?: number | null | undefined,\n    copy?: boolean | undefined,\n  ): IPublicModelNode | null {\n    const node = this[documentSymbol].insertNode(\n      (parent as any)[nodeSymbol] ? (parent as any)[nodeSymbol] : parent,\n      (thing as any)?.[nodeSymbol] ? (thing as any)[nodeSymbol] : thing,\n      at,\n      copy,\n    );\n    return ShellNode.create(node);\n  }\n\n  /**\n   * 创建一个节点\n   * @param data\n   * @returns\n   */\n  createNode<IPublicModelNode>(data: IPublicTypeNodeSchema): IPublicModelNode | null {\n    return ShellNode.create(this[documentSymbol].createNode(data));\n  }\n\n  /**\n   * 移除指定节点/节点id\n   * @param idOrNode\n   */\n  removeNode(idOrNode: string | IPublicModelNode): void {\n    this[documentSymbol].removeNode(idOrNode as any);\n  }\n\n  /**\n   * componentsMap of documentModel\n   * @param extraComps\n   * @returns\n   */\n  getComponentsMap(extraComps?: string[]): any {\n    return this[documentSymbol].getComponentsMap(extraComps);\n  }\n\n  /**\n   * 检查拖拽放置的目标节点是否可以放置该拖拽对象\n   * @param dropTarget 拖拽放置的目标节点\n   * @param dragObject 拖拽的对象\n   * @returns boolean 是否可以放置\n   */\n  checkNesting(\n      dropTarget: IPublicModelNode,\n      dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject,\n    ): boolean {\n    let innerDragObject = dragObject;\n    if (isDragNodeObject(dragObject)) {\n      innerDragObject.nodes = innerDragObject.nodes?.map(\n          (node: IPublicModelNode) => ((node as any)[nodeSymbol] || node),\n        );\n    }\n    return this[documentSymbol].checkNesting(\n      ((dropTarget as any)[nodeSymbol] || dropTarget) as any,\n      innerDragObject as any,\n    );\n  }\n\n  /**\n   * 当前 document 新增节点事件\n   */\n  onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {\n    return this[documentSymbol].onNodeCreate((node: InnerNode) => {\n      fn(ShellNode.create(node)!);\n    });\n  }\n\n  /**\n   * 当前 document 新增节点事件，此时节点已经挂载到 document 上\n   */\n  onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable {\n    return this[documentSymbol].onMountNode(({\n      node,\n    }) => {\n      fn({ node: ShellNode.create(node)! });\n    });\n  }\n\n  /**\n   * 当前 document 删除节点事件\n   */\n  onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {\n    return this[documentSymbol].onNodeDestroy((node: InnerNode) => {\n      fn(ShellNode.create(node)!);\n    });\n  }\n\n  /**\n   * 当前 document 的 hover 变更事件\n   */\n  onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {\n    return this[documentSymbol].designer.detecting.onDetectingChange((node: InnerNode) => {\n      fn(ShellNode.create(node)!);\n    });\n  }\n\n  /**\n   * 当前 document 的选中变更事件\n   */\n  onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable {\n    return this[documentSymbol].selection.onSelectionChange((ids: string[]) => {\n      fn(ids);\n    });\n  }\n\n  /**\n   * 当前 document 的节点显隐状态变更事件\n   * @param fn\n   */\n  onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable {\n    return this[documentSymbol].onChangeNodeVisible((node: InnerNode, visible: boolean) => {\n      fn(ShellNode.create(node)!, visible);\n    });\n  }\n\n  /**\n   * 当前 document 的节点 children 变更事件\n   * @param fn\n   */\n  onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable {\n    return this[documentSymbol].onChangeNodeChildren((info?: IPublicTypeOnChangeOptions<InnerNode>) => {\n      if (!info) {\n        return;\n      }\n      fn({\n        type: info.type,\n        node: ShellNode.create(info.node)!,\n      });\n    });\n  }\n\n  /**\n   * 当前 document 节点属性修改事件\n   * @param fn\n   */\n  onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable {\n    const callback = (info: GlobalEvent.Node.Prop.ChangeOptions) => {\n      fn({\n        key: info.key,\n        oldValue: info.oldValue,\n        newValue: info.newValue,\n        prop: ShellProp.create(info.prop)!,\n        node: ShellNode.create(info.node as any)!,\n      });\n    };\n    this[editorSymbol].on(\n      GlobalEvent.Node.Prop.InnerChange,\n      callback,\n    );\n\n    return () => {\n      this[editorSymbol].off(\n        GlobalEvent.Node.Prop.InnerChange,\n        callback,\n      );\n    };\n  }\n\n  /**\n   * import schema event\n   * @param fn\n   */\n  onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable {\n    return this[editorSymbol].eventBus.on('shell.document.importSchema', fn as any);\n  }\n\n  isDetectingNode(node: IPublicModelNode): boolean {\n    return this.detecting.current === node;\n  }\n\n  onFocusNodeChanged(\n    fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void,\n  ): IPublicTypeDisposable {\n    if (!fn) {\n      return () => {};\n    }\n    return this[editorSymbol].eventBus.on(\n      'shell.document.focusNodeChanged',\n      (payload) => {\n        const { document, focusNode } = payload;\n        fn(document, focusNode);\n      },\n    );\n  }\n\n  onDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable {\n    if (!fn) {\n      return () => {};\n    }\n    return this[editorSymbol].eventBus.on(\n      'document.dropLocation.changed',\n      (payload) => {\n        const { document } = payload;\n        fn(document);\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/drag-object.ts",
    "content": "import { dragObjectSymbol } from '../symbols';\nimport { IPublicModelDragObject, IPublicModelDragObject as InnerDragObject, IPublicTypeDragNodeDataObject, IPublicTypeNodeSchema } from '@alilc/lowcode-types';\nimport { Node } from './node';\n\nexport class DragObject implements IPublicModelDragObject {\n  private readonly [dragObjectSymbol]: InnerDragObject;\n\n  constructor(dragObject: InnerDragObject) {\n    this[dragObjectSymbol] = dragObject;\n  }\n\n  static create(dragObject: InnerDragObject | null): IPublicModelDragObject | null {\n    if (!dragObject) {\n      return null;\n    }\n    return new DragObject(dragObject);\n  }\n\n  get type() {\n    return this[dragObjectSymbol].type;\n  }\n\n  get nodes() {\n    const { nodes } = this[dragObjectSymbol];\n    if (!nodes) {\n      return null;\n    }\n    return nodes.map(Node.create);\n  }\n\n  get data(): IPublicTypeNodeSchema | IPublicTypeNodeSchema[] {\n    return (this[dragObjectSymbol] as IPublicTypeDragNodeDataObject).data;\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/dragon.ts",
    "content": "import {\n  IDragon,\n  ILocateEvent as InnerLocateEvent,\n  INode,\n} from '@alilc/lowcode-designer';\nimport { dragonSymbol, nodeSymbol } from '../symbols';\nimport LocateEvent from './locate-event';\nimport { DragObject } from './drag-object';\nimport { globalContext } from '@alilc/lowcode-editor-core';\nimport {\n  IPublicModelDragon,\n  IPublicModelLocateEvent,\n  IPublicModelDragObject,\n  IPublicTypeDragNodeDataObject,\n  IPublicModelNode,\n  IPublicTypeDragObject,\n} from '@alilc/lowcode-types';\n\nexport const innerDragonSymbol = Symbol('innerDragonSymbol');\n\nexport class Dragon implements IPublicModelDragon {\n  private readonly [innerDragonSymbol]: IDragon;\n\n  constructor(innerDragon: IDragon, readonly workspaceMode: boolean) {\n    this[innerDragonSymbol] = innerDragon;\n  }\n\n  get [dragonSymbol](): IDragon {\n    if (this.workspaceMode) {\n      return this[innerDragonSymbol];\n    }\n    const workspace = globalContext.get('workspace');\n    let editor = globalContext.get('editor');\n\n    if (workspace.isActive) {\n      editor = workspace.window.editor;\n    }\n\n    const designer = editor.get('designer');\n    return designer.dragon;\n  }\n\n  static create(\n      dragon: IDragon | null,\n      workspaceMode: boolean,\n    ): IPublicModelDragon | null {\n    if (!dragon) {\n      return null;\n    }\n    return new Dragon(dragon, workspaceMode);\n  }\n\n  /**\n   * is dragging or not\n   */\n  get dragging(): boolean {\n    return this[dragonSymbol].dragging;\n  }\n\n  /**\n   * 绑定 dragstart 事件\n   * @param func\n   * @returns\n   */\n  onDragstart(func: (e: IPublicModelLocateEvent) => any): () => void {\n    return this[dragonSymbol].onDragstart((e: InnerLocateEvent) => func(LocateEvent.create(e)!));\n  }\n\n  /**\n   * 绑定 drag 事件\n   * @param func\n   * @returns\n   */\n  onDrag(func: (e: IPublicModelLocateEvent) => any): () => void {\n    return this[dragonSymbol].onDrag((e: InnerLocateEvent) => func(LocateEvent.create(e)!));\n  }\n\n  /**\n   * 绑定 dragend 事件\n   * @param func\n   * @returns\n   */\n  onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): () => void {\n    return this[dragonSymbol].onDragend(\n      (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => {\n        const dragObject = DragObject.create(o.dragObject);\n        const { copy } = o;\n        return func({ dragObject: dragObject!, copy });\n      },\n    );\n  }\n\n  /**\n   * 设置拖拽监听的区域 shell，以及自定义拖拽转换函数 boost\n   * @param shell 拖拽监听的区域\n   * @param boost 拖拽转换函数\n   */\n  from(shell: Element, boost: (e: MouseEvent) => IPublicTypeDragNodeDataObject | null): any {\n    return this[dragonSymbol].from(shell, boost);\n  }\n\n  /**\n   * boost your dragObject for dragging(flying) 发射拖拽对象\n   *\n   * @param dragObject 拖拽对象\n   * @param boostEvent 拖拽初始时事件\n   */\n  boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode & {\n    [nodeSymbol]: INode;\n  }): void {\n    return this[dragonSymbol].boost({\n      ...dragObject,\n      nodes: dragObject.nodes.map((node: any) => node[nodeSymbol]),\n    }, boostEvent, fromRglNode?.[nodeSymbol]);\n  }\n\n  /**\n   * 添加投放感应区\n   */\n  addSensor(sensor: any): void {\n    return this[dragonSymbol].addSensor(sensor);\n  }\n\n  /**\n   * 移除投放感应\n   */\n  removeSensor(sensor: any): void {\n    return this[dragonSymbol].removeSensor(sensor);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/drop-location.ts",
    "content": "import {\n  IDropLocation as InnerDropLocation,\n} from '@alilc/lowcode-designer';\nimport { dropLocationSymbol } from '../symbols';\nimport { Node as ShellNode } from './node';\nimport { IPublicModelDropLocation, IPublicTypeLocationDetail, IPublicModelLocateEvent } from '@alilc/lowcode-types';\n\nexport class DropLocation implements IPublicModelDropLocation {\n  private readonly [dropLocationSymbol]: InnerDropLocation;\n\n  constructor(dropLocation: InnerDropLocation) {\n    this[dropLocationSymbol] = dropLocation;\n  }\n\n  static create(dropLocation: InnerDropLocation | null): IPublicModelDropLocation | null {\n    if (!dropLocation) {\n      return null;\n    }\n    return new DropLocation(dropLocation);\n  }\n\n  get target() {\n    return ShellNode.create(this[dropLocationSymbol].target);\n  }\n\n  get detail(): IPublicTypeLocationDetail {\n    return this[dropLocationSymbol].detail;\n  }\n\n  get event(): IPublicModelLocateEvent {\n    return this[dropLocationSymbol].event;\n  }\n\n  clone(event: IPublicModelLocateEvent): IPublicModelDropLocation {\n    return new DropLocation(this[dropLocationSymbol].clone(event));\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/editor-view.ts",
    "content": "import { editorViewSymbol, pluginContextSymbol } from '../symbols';\nimport { IPublicModelPluginContext } from '@alilc/lowcode-types';\nimport { IViewContext } from '@alilc/lowcode-workspace';\n\nexport class EditorView {\n  [editorViewSymbol]: IViewContext;\n\n  [pluginContextSymbol]: IPublicModelPluginContext;\n\n  constructor(editorView: IViewContext) {\n    this[editorViewSymbol] = editorView;\n    this[pluginContextSymbol] = this[editorViewSymbol].innerPlugins._getLowCodePluginContext({\n      pluginName: editorView.editorWindow + editorView.viewName,\n    });\n  }\n\n  toProxy() {\n    return new Proxy(this, {\n      get(target, prop, receiver) {\n        if ((target[pluginContextSymbol] as any)[prop as string]) {\n          return Reflect.get(target[pluginContextSymbol], prop, receiver);\n        }\n        return Reflect.get(target, prop, receiver);\n      },\n    });\n  }\n\n  get viewName() {\n    return this[editorViewSymbol].viewName;\n  }\n\n  get viewType() {\n    return this[editorViewSymbol].viewType;\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/history.ts",
    "content": "import type { IDocumentModel as InnerDocumentModel, IHistory as InnerHistory } from '@alilc/lowcode-designer';\nimport { historySymbol, documentSymbol } from '../symbols';\nimport { IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types';\n\nexport class History implements IPublicModelHistory {\n  private readonly [documentSymbol]: InnerDocumentModel;\n\n  private get [historySymbol](): InnerHistory {\n    return this[documentSymbol].getHistory();\n  }\n\n  constructor(document: InnerDocumentModel) {\n    this[documentSymbol] = document;\n  }\n\n  /**\n   * 历史记录跳转到指定位置\n   * @param cursor\n   */\n  go(cursor: number): void {\n    this[historySymbol].go(cursor);\n  }\n\n  /**\n   * 历史记录后退\n   */\n  back(): void {\n    this[historySymbol].back();\n  }\n\n  /**\n   * 历史记录前进\n   */\n  forward(): void {\n    this[historySymbol].forward();\n  }\n\n  /**\n   * 保存当前状态\n   */\n  savePoint(): void {\n    this[historySymbol].savePoint();\n  }\n\n  /**\n   * 当前是否是「保存点」，即是否有状态变更但未保存\n   * @returns\n   */\n  isSavePoint(): boolean {\n    return this[historySymbol].isSavePoint();\n  }\n\n  /**\n   * 获取 state，判断当前是否为「可回退」、「可前进」的状态\n   * @returns\n   */\n  getState(): number {\n    return this[historySymbol].getState();\n  }\n\n  /**\n   * 监听 state 变更事件\n   * @param func\n   * @returns\n   */\n  onChangeState(func: () => any): IPublicTypeDisposable {\n    return this[historySymbol].onChangeState(func);\n  }\n\n  /**\n   * 监听历史记录游标位置变更事件\n   * @param func\n   * @returns\n   */\n  onChangeCursor(func: () => any): IPublicTypeDisposable {\n    return this[historySymbol].onChangeCursor(func);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/index.ts",
    "content": "export * from './component-meta';\nexport * from './detecting';\nexport * from './document-model';\nexport * from './drag-object';\nexport * from './dragon';\nexport * from './drop-location';\nexport * from './history';\nexport * from './locate-event';\nexport * from './modal-nodes-manager';\nexport * from './node-children';\nexport * from './node';\nexport * from './prop';\nexport * from './props';\nexport * from './selection';\nexport * from './setting-top-entry';\nexport * from './setting-field';\nexport * from './resource';\nexport * from './active-tracker';\nexport * from './plugin-instance';\nexport * from './window';\nexport * from './clipboard';\nexport * from './editor-view';\nexport * from './skeleton-item';\n"
  },
  {
    "path": "packages/shell/src/model/locate-event.ts",
    "content": "import { ILocateEvent } from '@alilc/lowcode-designer';\nimport { locateEventSymbol } from '../symbols';\nimport { DragObject } from './drag-object';\nimport { IPublicModelLocateEvent, IPublicModelDragObject } from '@alilc/lowcode-types';\n\nexport default class LocateEvent implements IPublicModelLocateEvent {\n  private readonly [locateEventSymbol]: ILocateEvent;\n\n  constructor(locateEvent: ILocateEvent) {\n    this[locateEventSymbol] = locateEvent;\n  }\n\n  static create(locateEvent: ILocateEvent): IPublicModelLocateEvent | null {\n    if (!locateEvent) {\n      return null;\n    }\n    return new LocateEvent(locateEvent);\n  }\n\n  get type(): string {\n    return this[locateEventSymbol].type;\n  }\n\n  get globalX(): number {\n    return this[locateEventSymbol].globalX;\n  }\n\n  get globalY(): number {\n    return this[locateEventSymbol].globalY;\n  }\n\n  get originalEvent(): MouseEvent | DragEvent {\n    return this[locateEventSymbol].originalEvent;\n  }\n\n  get target(): Element | null | undefined {\n    return this[locateEventSymbol].target;\n  }\n\n  get canvasX(): number | undefined {\n    return this[locateEventSymbol].canvasX;\n  }\n\n  get canvasY(): number | undefined {\n    return this[locateEventSymbol].canvasY;\n  }\n\n  get dragObject(): IPublicModelDragObject | null {\n    return DragObject.create(this[locateEventSymbol].dragObject);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/modal-nodes-manager.ts",
    "content": "import {\n  IModalNodesManager as InnerModalNodesManager,\n  INode as InnerNode,\n} from '@alilc/lowcode-designer';\nimport { IPublicModelModalNodesManager, IPublicModelNode } from '@alilc/lowcode-types';\nimport { Node as ShellNode } from './node';\nimport { nodeSymbol, modalNodesManagerSymbol } from '../symbols';\n\nexport class ModalNodesManager implements IPublicModelModalNodesManager {\n  private readonly [modalNodesManagerSymbol]: InnerModalNodesManager;\n\n  constructor(modalNodesManager: InnerModalNodesManager) {\n    this[modalNodesManagerSymbol] = modalNodesManager;\n  }\n\n  static create(\n    modalNodesManager: InnerModalNodesManager | null,\n  ): IPublicModelModalNodesManager | null {\n    if (!modalNodesManager) {\n      return null;\n    }\n    return new ModalNodesManager(modalNodesManager);\n  }\n\n  /**\n   * 设置模态节点，触发内部事件\n   */\n  setNodes(): void {\n    this[modalNodesManagerSymbol].setNodes();\n  }\n\n  /**\n   * 获取模态节点（们）\n   */\n  getModalNodes(): IPublicModelNode[] {\n    const innerNodes = this[modalNodesManagerSymbol].getModalNodes();\n    const shellNodes: IPublicModelNode[] = [];\n    innerNodes?.forEach((node: InnerNode) => {\n      const shellNode = ShellNode.create(node);\n      if (shellNode) {\n        shellNodes.push(shellNode);\n      }\n    });\n    return shellNodes;\n  }\n\n  /**\n   * 获取当前可见的模态节点\n   */\n  getVisibleModalNode(): IPublicModelNode | null {\n    return ShellNode.create(this[modalNodesManagerSymbol].getVisibleModalNode());\n  }\n\n  /**\n   * 隐藏模态节点（们）\n   */\n  hideModalNodes(): void {\n    this[modalNodesManagerSymbol].hideModalNodes();\n  }\n\n  /**\n   * 设置指定节点为可见态\n   * @param node Node\n   */\n  setVisible(node: IPublicModelNode): void {\n    this[modalNodesManagerSymbol].setVisible((node as any)[nodeSymbol]);\n  }\n\n  /**\n   * 设置指定节点为不可见态\n   * @param node Node\n   */\n   setInvisible(node: IPublicModelNode): void {\n    this[modalNodesManagerSymbol].setInvisible((node as any)[nodeSymbol]);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/node-children.ts",
    "content": "import { INode as InnerNode, INodeChildren } from '@alilc/lowcode-designer';\nimport { IPublicTypeNodeData, IPublicEnumTransformStage, IPublicModelNodeChildren, IPublicModelNode } from '@alilc/lowcode-types';\nimport { Node as ShellNode } from './node';\nimport { nodeSymbol, nodeChildrenSymbol } from '../symbols';\n\nexport class NodeChildren implements IPublicModelNodeChildren {\n  private readonly [nodeChildrenSymbol]: INodeChildren;\n\n  constructor(nodeChildren: INodeChildren) {\n    this[nodeChildrenSymbol] = nodeChildren;\n  }\n\n  static create(nodeChildren: INodeChildren | null): IPublicModelNodeChildren | null {\n    if (!nodeChildren) {\n      return null;\n    }\n    return new NodeChildren(nodeChildren);\n  }\n\n  /**\n   * 返回当前 children 实例所属的节点实例\n   */\n  get owner(): IPublicModelNode | null {\n    return ShellNode.create(this[nodeChildrenSymbol].owner);\n  }\n\n  /**\n   * children 内的节点实例数\n   */\n  get size(): number {\n    return this[nodeChildrenSymbol].size;\n  }\n\n  /**\n   * @deprecated\n   * 是否为空\n   * @returns\n   */\n  get isEmpty(): boolean {\n    return this[nodeChildrenSymbol].isEmptyNode;\n  }\n\n  /**\n   * 是否为空\n   * @returns\n   */\n  get isEmptyNode(): boolean {\n    return this[nodeChildrenSymbol].isEmptyNode;\n  }\n\n  /**\n   * @deprecated\n   * judge if it is not empty\n   */\n  get notEmpty(): boolean {\n    return this[nodeChildrenSymbol].notEmptyNode;\n  }\n\n  /**\n   * judge if it is not empty\n   */\n  get notEmptyNode(): boolean {\n    return this[nodeChildrenSymbol].notEmptyNode;\n  }\n\n  /**\n   * 删除指定节点\n   * delete the node\n   * @param node\n   */\n  delete(node: IPublicModelNode): boolean {\n    return this[nodeChildrenSymbol].delete((node as any)?.[nodeSymbol]);\n  }\n\n  /**\n   * 插入一个节点\n   * @param node 待插入节点\n   * @param at 插入下标\n   * @returns\n   */\n  insert(node: IPublicModelNode, at?: number | null): void {\n    return this[nodeChildrenSymbol].insert((node as any)?.[nodeSymbol], at);\n  }\n\n  /**\n   * 返回指定节点的下标\n   * @param node\n   * @returns\n   */\n  indexOf(node: IPublicModelNode): number {\n    return this[nodeChildrenSymbol].indexOf((node as any)?.[nodeSymbol]);\n  }\n\n  /**\n   * 类似数组 splice 操作\n   * @param start\n   * @param deleteCount\n   * @param node\n   */\n  splice(start: number, deleteCount: number, node?: IPublicModelNode): any {\n    this[nodeChildrenSymbol].splice(start, deleteCount, (node as any)?.[nodeSymbol]);\n  }\n\n  /**\n   * 返回指定下标的节点\n   * @param index\n   * @returns\n   */\n  get(index: number): IPublicModelNode | null {\n    return ShellNode.create(this[nodeChildrenSymbol].get(index));\n  }\n\n  /**\n   * 是否包含指定节点\n   * @param node\n   * @returns\n   */\n  has(node: IPublicModelNode): boolean {\n    return this[nodeChildrenSymbol].has((node as any)?.[nodeSymbol]);\n  }\n\n  /**\n   * 类似数组的 forEach\n   * @param fn\n   */\n  forEach(fn: (node: IPublicModelNode, index: number) => void): void {\n    this[nodeChildrenSymbol].forEach((item: InnerNode, index: number) => {\n      fn(ShellNode.create(item)!, index);\n    });\n  }\n\n  /**\n   * 类似数组的 reverse\n   */\n  reverse(): IPublicModelNode[] {\n    return this[nodeChildrenSymbol].reverse().map(d => {\n      return ShellNode.create(d)!;\n    });\n  }\n\n  /**\n   * 类似数组的 map\n   * @param fn\n   */\n  map<T = any>(fn: (node: IPublicModelNode, index: number) => T): T[] | null {\n    return this[nodeChildrenSymbol].map<T>((item: InnerNode, index: number): T => {\n      return fn(ShellNode.create(item)!, index);\n    });\n  }\n\n  /**\n   * 类似数组的 every\n   * @param fn\n   */\n  every(fn: (node: IPublicModelNode, index: number) => boolean): boolean {\n    return this[nodeChildrenSymbol].every((item: InnerNode, index: number) => {\n      return fn(ShellNode.create(item)!, index);\n    });\n  }\n\n  /**\n   * 类似数组的 some\n   * @param fn\n   */\n  some(fn: (node: IPublicModelNode, index: number) => boolean): boolean {\n    return this[nodeChildrenSymbol].some((item: InnerNode, index: number) => {\n      return fn(ShellNode.create(item)!, index);\n    });\n  }\n\n  /**\n   * 类似数组的 filter\n   * @param fn\n   */\n  filter(fn: (node: IPublicModelNode, index: number) => boolean): any {\n    return this[nodeChildrenSymbol]\n      .filter((item: InnerNode, index: number) => {\n        return fn(ShellNode.create(item)!, index);\n      })\n      .map((item: InnerNode) => ShellNode.create(item)!);\n  }\n\n  /**\n   * 类似数组的 find\n   * @param fn\n   */\n  find(fn: (node: IPublicModelNode, index: number) => boolean): IPublicModelNode | null {\n    return ShellNode.create(\n      this[nodeChildrenSymbol].find((item: InnerNode, index: number) => {\n        return fn(ShellNode.create(item)!, index);\n      }),\n    );\n  }\n\n  /**\n   * 类似数组的 reduce\n   * @param fn\n   */\n  reduce(fn: (acc: any, cur: IPublicModelNode) => any, initialValue: any): void {\n    return this[nodeChildrenSymbol].reduce((acc: any, cur: InnerNode) => {\n      return fn(acc, ShellNode.create(cur)!);\n    }, initialValue);\n  }\n\n  /**\n   * 导入 schema\n   * @param data\n   */\n  importSchema(data?: IPublicTypeNodeData | IPublicTypeNodeData[]): void {\n    this[nodeChildrenSymbol].import(data);\n  }\n\n  /**\n   * 导出 schema\n   * @param stage\n   * @returns\n   */\n  exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render): any {\n    return this[nodeChildrenSymbol].export(stage);\n  }\n\n  /**\n   * 执行新增、删除、排序等操作\n   * @param remover\n   * @param adder\n   * @param sorter\n   */\n  mergeChildren(\n    remover: (node: IPublicModelNode, idx: number) => boolean,\n    adder: (children: IPublicModelNode[]) => any,\n    originalSorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number,\n  ) {\n    let sorter = originalSorter;\n    if (!sorter) {\n      sorter = () => 0;\n    }\n    this[nodeChildrenSymbol].mergeChildren(\n      (node: InnerNode, idx: number) => remover(ShellNode.create(node)!, idx),\n      (children: InnerNode[]) => adder(children.map((node) => ShellNode.create(node)!)),\n      (firstNode: InnerNode, secondNode: InnerNode) => {\n        return sorter(ShellNode.create(firstNode)!, ShellNode.create(secondNode)!);\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/node.ts",
    "content": "import {\n  IDocumentModel as InnerDocumentModel,\n  INode as InnerNode,\n} from '@alilc/lowcode-designer';\nimport {\n  IPublicTypeCompositeValue,\n  IPublicTypeNodeSchema,\n  IPublicEnumTransformStage,\n  IPublicModelNode,\n  IPublicTypeIconType,\n  IPublicTypeI18nData,\n  IPublicModelComponentMeta,\n  IPublicModelDocumentModel,\n  IPublicModelNodeChildren,\n  IPublicModelProp,\n  IPublicModelProps,\n  IPublicTypePropsMap,\n  IPublicTypePropsList,\n  IPublicModelSettingTopEntry,\n  IPublicModelExclusiveGroup,\n} from '@alilc/lowcode-types';\nimport { Prop as ShellProp } from './prop';\nimport { Props as ShellProps } from './props';\nimport { DocumentModel as ShellDocumentModel } from './document-model';\nimport { NodeChildren as ShellNodeChildren } from './node-children';\nimport { ComponentMeta as ShellComponentMeta } from './component-meta';\nimport { SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry';\nimport { documentSymbol, nodeSymbol } from '../symbols';\nimport { ReactElement } from 'react';\nimport { ConditionGroup } from './condition-group';\n\nconst shellNodeSymbol = Symbol('shellNodeSymbol');\n\nfunction isShellNode(node: any): node is IPublicModelNode {\n  return node[shellNodeSymbol];\n}\n\nexport class Node implements IPublicModelNode {\n  private readonly [documentSymbol]: InnerDocumentModel | null;\n  private readonly [nodeSymbol]: InnerNode;\n\n  private _id: string;\n\n  /**\n   * 节点 id\n   */\n  get id() {\n    return this._id;\n  }\n\n  /**\n   * set id\n   */\n  set id(id: string) {\n    this._id = id;\n  }\n\n  /**\n   * 节点标题\n   */\n  get title(): string | IPublicTypeI18nData | ReactElement {\n    return this[nodeSymbol].title;\n  }\n\n  /**\n   * @deprecated\n   * 是否为「容器型」节点\n   */\n  get isContainer(): boolean {\n    return this[nodeSymbol].isContainerNode;\n  }\n\n  /**\n   * 是否为「容器型」节点\n   */\n  get isContainerNode(): boolean {\n    return this[nodeSymbol].isContainerNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为根节点\n   */\n  get isRoot(): boolean {\n    return this[nodeSymbol].isRootNode;\n  }\n\n  /**\n   * 是否为根节点\n   */\n  get isRootNode(): boolean {\n    return this[nodeSymbol].isRootNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为空节点（无 children 或者 children 为空）\n   */\n  get isEmpty(): boolean {\n    return this[nodeSymbol].isEmptyNode;\n  }\n\n  /**\n   * 是否为空节点（无 children 或者 children 为空）\n   */\n  get isEmptyNode(): boolean {\n    return this[nodeSymbol].isEmptyNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为 Page 节点\n   */\n  get isPage(): boolean {\n    return this[nodeSymbol].isPageNode;\n  }\n\n  /**\n   * 是否为 Page 节点\n   */\n  get isPageNode(): boolean {\n    return this[nodeSymbol].isPageNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为 Component 节点\n   */\n  get isComponent(): boolean {\n    return this[nodeSymbol].isComponentNode;\n  }\n\n  /**\n   * 是否为 Component 节点\n   */\n  get isComponentNode(): boolean {\n    return this[nodeSymbol].isComponentNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为「模态框」节点\n   */\n  get isModal(): boolean {\n    return this[nodeSymbol].isModalNode;\n  }\n\n  /**\n   * 是否为「模态框」节点\n   */\n  get isModalNode(): boolean {\n    return this[nodeSymbol].isModalNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为插槽节点\n   */\n  get isSlot(): boolean {\n    return this[nodeSymbol].isSlotNode;\n  }\n\n  /**\n   * 是否为插槽节点\n   */\n  get isSlotNode(): boolean {\n    return this[nodeSymbol].isSlotNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为父类/分支节点\n   */\n  get isParental(): boolean {\n    return this[nodeSymbol].isParentalNode;\n  }\n\n  /**\n   * 是否为父类/分支节点\n   */\n  get isParentalNode(): boolean {\n    return this[nodeSymbol].isParentalNode;\n  }\n\n  /**\n   * @deprecated\n   * 是否为叶子节点\n   */\n  get isLeaf(): boolean {\n    return this[nodeSymbol].isLeafNode;\n  }\n\n  /**\n   * 是否为叶子节点\n   */\n  get isLeafNode(): boolean {\n    return this[nodeSymbol].isLeafNode;\n  }\n\n  /**\n   * judge if it is a node or not\n   */\n  readonly isNode = true;\n\n  /**\n   * 获取当前节点的锁定状态\n   */\n  get isLocked(): boolean {\n    return this[nodeSymbol].isLocked;\n  }\n\n  /**\n   * 下标\n   */\n  get index() {\n    return this[nodeSymbol].index;\n  }\n\n  /**\n   * 图标\n   */\n  get icon(): IPublicTypeIconType {\n    return this[nodeSymbol].icon;\n  }\n\n  /**\n   * 节点所在树的层级深度，根节点深度为 0\n   */\n  get zLevel(): number {\n    return this[nodeSymbol].zLevel;\n  }\n\n  /**\n   * 节点 componentName\n   */\n  get componentName(): string {\n    return this[nodeSymbol].componentName;\n  }\n\n  /**\n   * 节点的物料元数据\n   */\n  get componentMeta(): IPublicModelComponentMeta | null {\n    return ShellComponentMeta.create(this[nodeSymbol].componentMeta);\n  }\n\n  /**\n   * 获取节点所属的文档模型对象\n   * @returns\n   */\n  get document(): IPublicModelDocumentModel | null {\n    return ShellDocumentModel.create(this[documentSymbol]);\n  }\n\n  /**\n   * 获取当前节点的前一个兄弟节点\n   * @returns\n   */\n  get prevSibling(): IPublicModelNode | null {\n    return Node.create(this[nodeSymbol].prevSibling);\n  }\n\n  /**\n   * 获取当前节点的后一个兄弟节点\n   * @returns\n   */\n  get nextSibling(): IPublicModelNode | null {\n    return Node.create(this[nodeSymbol].nextSibling);\n  }\n\n  /**\n   * 获取当前节点的父亲节点\n   * @returns\n   */\n  get parent(): IPublicModelNode | null {\n    return Node.create(this[nodeSymbol].parent);\n  }\n\n  /**\n   * 获取当前节点的孩子节点模型\n   * @returns\n   */\n  get children(): IPublicModelNodeChildren | null {\n    return ShellNodeChildren.create(this[nodeSymbol].children);\n  }\n\n  /**\n   * 节点上挂载的插槽节点们\n   */\n  get slots(): IPublicModelNode[] {\n    return this[nodeSymbol].slots.map((node: InnerNode) => Node.create(node)!);\n  }\n\n  /**\n   * 当前节点为插槽节点时，返回节点对应的属性实例\n   */\n  get slotFor(): IPublicModelProp | null | undefined {\n    return ShellProp.create(this[nodeSymbol].slotFor);\n  }\n\n  /**\n   * 返回节点的属性集\n   */\n  get props(): IPublicModelProps | null {\n    return ShellProps.create(this[nodeSymbol].props);\n  }\n\n  /**\n   * 返回节点的属性集\n   */\n  get propsData(): IPublicTypePropsMap | IPublicTypePropsList | null {\n    return this[nodeSymbol].propsData;\n  }\n\n  /**\n   * 获取符合搭建协议 - 节点 schema 结构\n   */\n  get schema(): IPublicTypeNodeSchema {\n    return this[nodeSymbol].schema;\n  }\n\n  get settingEntry(): IPublicModelSettingTopEntry {\n    return ShellSettingTopEntry.create(this[nodeSymbol].settingEntry as any);\n  }\n\n  constructor(node: InnerNode) {\n    this[nodeSymbol] = node;\n    this[documentSymbol] = node.document;\n\n    this._id = this[nodeSymbol].id;\n  }\n\n  static create(node: InnerNode | IPublicModelNode | null | undefined): IPublicModelNode | null {\n    if (!node) {\n      return null;\n    }\n    // @ts-ignore 直接返回已挂载的 shell node 实例\n    if (isShellNode(node)) {\n      return (node as any)[shellNodeSymbol];\n    }\n    const shellNode = new Node(node);\n    // @ts-ignore 挂载 shell node 实例\n    // eslint-disable-next-line no-param-reassign\n    node[shellNodeSymbol] = shellNode;\n    return shellNode;\n  }\n\n  /**\n   * @deprecated use .children instead\n   */\n  getChildren() {\n    return this.children;\n  }\n\n  /**\n   * 获取节点实例对应的 dom 节点\n   */\n  getDOMNode() {\n    return (this[nodeSymbol] as any).getDOMNode();\n  }\n\n  /**\n   * 执行新增、删除、排序等操作\n   * @param remover\n   * @param adder\n   * @param sorter\n   */\n  mergeChildren(\n    remover: (node: IPublicModelNode, idx: number) => boolean,\n    adder: (children: IPublicModelNode[]) => any,\n    sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number,\n  ): any {\n    return this.children?.mergeChildren(remover, adder, sorter);\n  }\n\n  /**\n   * 返回节点的尺寸、位置信息\n   * @returns\n   */\n  getRect(): DOMRect | null {\n    return this[nodeSymbol].getRect();\n  }\n\n  /**\n   * 是否有挂载插槽节点\n   * @returns\n   */\n  hasSlots(): boolean {\n    return this[nodeSymbol].hasSlots();\n  }\n\n  /**\n   * 是否设定了渲染条件\n   * @returns\n   */\n  hasCondition(): boolean {\n    return this[nodeSymbol].hasCondition();\n  }\n\n  /**\n   * 是否设定了循环数据\n   * @returns\n   */\n  hasLoop(): boolean {\n    return this[nodeSymbol].hasLoop();\n  }\n\n  get visible(): boolean {\n    return this[nodeSymbol].getVisible();\n  }\n\n  set visible(value: boolean) {\n    this[nodeSymbol].setVisible(value);\n  }\n\n  getVisible(): boolean {\n    return this[nodeSymbol].getVisible();\n  }\n\n  setVisible(flag: boolean): void {\n    this[nodeSymbol].setVisible(flag);\n  }\n\n  isConditionalVisible(): boolean | undefined {\n    return this[nodeSymbol].isConditionalVisible();\n  }\n\n  /**\n   * 设置节点锁定状态\n   * @param flag\n   */\n  lock(flag?: boolean): void {\n    this[nodeSymbol].lock(flag);\n  }\n\n  /**\n   * @deprecated use .props instead\n   */\n  getProps() {\n    return this.props;\n  }\n\n  contains(node: IPublicModelNode): boolean {\n    return this[nodeSymbol].contains((node as any)[nodeSymbol]);\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getProp(path: string, createIfNone = true): IPublicModelProp | null {\n    return ShellProp.create(this[nodeSymbol].getProp(path, createIfNone));\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例值\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getPropValue(path: string) {\n    return this.getProp(path, false)?.getValue();\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例，\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param createIfNone 当没有属性的时候，是否创建一个属性\n   * @returns\n   */\n  getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null {\n    return ShellProp.create(this[nodeSymbol].getExtraProp(path, createIfNone));\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例，\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getExtraPropValue(path: string): any {\n    return this.getExtraProp(path)?.getValue();\n  }\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   * @returns\n   */\n  setPropValue(path: string, value: IPublicTypeCompositeValue): void {\n    return this.getProp(path)?.setValue(value);\n  }\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   * @returns\n   */\n  setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void {\n    return this.getExtraProp(path)?.setValue(value);\n  }\n\n  /**\n   * 导入节点数据\n   * @param data\n   */\n  importSchema(data: IPublicTypeNodeSchema): void {\n    this[nodeSymbol].import(data);\n  }\n\n  /**\n   * 导出节点数据\n   * @param stage\n   * @param options\n   * @returns\n   */\n  exportSchema(\n      stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render,\n      options?: any,\n    ): IPublicTypeNodeSchema {\n    return this[nodeSymbol].export(stage, options);\n  }\n\n  /**\n   * 在指定位置之前插入一个节点\n   * @param node\n   * @param ref\n   * @param useMutator\n   */\n  insertBefore(\n      node: IPublicModelNode,\n      ref?: IPublicModelNode | undefined,\n      useMutator?: boolean,\n    ): void {\n    this[nodeSymbol].insertBefore(\n        (node as any)[nodeSymbol] || node,\n        (ref as any)?.[nodeSymbol],\n        useMutator,\n      );\n  }\n\n  /**\n   * 在指定位置之后插入一个节点\n   * @param node\n   * @param ref\n   * @param useMutator\n   */\n  insertAfter(\n      node: IPublicModelNode,\n      ref?: IPublicModelNode | undefined,\n      useMutator?: boolean,\n    ): void {\n    this[nodeSymbol].insertAfter(\n        (node as any)[nodeSymbol] || node,\n        (ref as any)?.[nodeSymbol],\n        useMutator,\n      );\n  }\n\n  /**\n   * 替换指定节点\n   * @param node 待替换的子节点\n   * @param data 用作替换的节点对象或者节点描述\n   * @returns\n   */\n  replaceChild(node: IPublicModelNode, data: any): IPublicModelNode | null {\n    return Node.create(this[nodeSymbol].replaceChild((node as any)[nodeSymbol], data));\n  }\n\n  /**\n   * 将当前节点替换成指定节点描述\n   * @param schema\n   */\n  replaceWith(schema: IPublicTypeNodeSchema): any {\n    this[nodeSymbol].replaceWith(schema);\n  }\n\n  /**\n   * 选中当前节点实例\n   */\n  select(): void {\n    this[nodeSymbol].select();\n  }\n\n  /**\n   * 设置悬停态\n   * @param flag\n   */\n  hover(flag = true): void {\n    this[nodeSymbol].hover(flag);\n  }\n\n  /**\n   * 删除当前节点实例\n   */\n  remove(): void {\n    this[nodeSymbol].remove();\n  }\n\n  /**\n   * @deprecated\n   * 设置为磁贴布局节点\n   */\n  set isRGLContainer(flag: boolean) {\n    this[nodeSymbol].isRGLContainerNode = flag;\n  }\n\n  /**\n   * @deprecated\n   * 获取磁贴布局节点设置状态\n   * @returns Boolean\n   */\n  get isRGLContainer() {\n    return this[nodeSymbol].isRGLContainerNode;\n  }\n\n  /**\n   * 设置为磁贴布局节点\n   */\n  set isRGLContainerNode(flag: boolean) {\n    this[nodeSymbol].isRGLContainerNode = flag;\n  }\n\n  /**\n   * 获取磁贴布局节点设置状态\n   * @returns Boolean\n   */\n  get isRGLContainerNode() {\n    return this[nodeSymbol].isRGLContainerNode;\n  }\n\n  internalToShellNode() {\n    return this;\n  }\n\n  canPerformAction(actionName: string): boolean {\n    return this[nodeSymbol].canPerformAction(actionName);\n  }\n\n  /**\n   * get conditionGroup\n   * @since v1.1.0\n   */\n  get conditionGroup(): IPublicModelExclusiveGroup | null {\n    return ConditionGroup.create(this[nodeSymbol].conditionGroup);\n  }\n\n  /**\n   * set value for conditionalVisible\n   * @since v1.1.0\n   */\n  setConditionalVisible(): void {\n    this[nodeSymbol].setConditionalVisible();\n  }\n\n  getRGL() {\n    const {\n      isContainerNode,\n      isEmptyNode,\n      isRGLContainerNode,\n      isRGLNode,\n      isRGL,\n      rglNode,\n    } = this[nodeSymbol].getRGL();\n\n    return {\n      isContainerNode,\n      isEmptyNode,\n      isRGLContainerNode,\n      isRGLNode,\n      isRGL,\n      rglNode: Node.create(rglNode),\n    };\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/plugin-instance.ts",
    "content": "import { ILowCodePluginRuntime } from '@alilc/lowcode-designer';\nimport { IPublicModelPluginInstance } from '@alilc/lowcode-types';\nimport { pluginInstanceSymbol } from '../symbols';\n\nexport class PluginInstance implements IPublicModelPluginInstance {\n  private readonly [pluginInstanceSymbol]: ILowCodePluginRuntime;\n\n  constructor(pluginInstance: ILowCodePluginRuntime) {\n    this[pluginInstanceSymbol] = pluginInstance;\n  }\n\n  get pluginName(): string {\n    return this[pluginInstanceSymbol].name;\n  }\n\n  get dep(): string[] {\n    return this[pluginInstanceSymbol].dep;\n  }\n\n  get disabled(): boolean {\n    return this[pluginInstanceSymbol].disabled;\n  }\n\n  set disabled(disabled: boolean) {\n    this[pluginInstanceSymbol].setDisabled(disabled);\n  }\n\n  get meta() {\n    return this[pluginInstanceSymbol].meta;\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/prop.ts",
    "content": "import { IProp as InnerProp } from '@alilc/lowcode-designer';\nimport { IPublicTypeCompositeValue, IPublicEnumTransformStage, IPublicModelProp, IPublicModelNode } from '@alilc/lowcode-types';\nimport { propSymbol } from '../symbols';\nimport { Node as ShellNode } from './node';\n\nexport class Prop implements IPublicModelProp {\n  private readonly [propSymbol]: InnerProp;\n\n  constructor(prop: InnerProp) {\n    this[propSymbol] = prop;\n  }\n\n  static create(prop: InnerProp | undefined | null): IPublicModelProp | null {\n    if (!prop) {\n      return null;\n    }\n    return new Prop(prop);\n  }\n\n  /**\n   * id\n   */\n  get id(): string {\n    return this[propSymbol].id;\n  }\n\n  /**\n   * key 值\n   * get key of prop\n   */\n  get key(): string | number | undefined {\n    return this[propSymbol].key;\n  }\n\n  /**\n   * 返回当前 prop 的路径\n   */\n  get path(): string[] {\n    return this[propSymbol].path;\n  }\n\n  /**\n   * 返回所属的节点实例\n   */\n  get node(): IPublicModelNode | null {\n    return ShellNode.create(this[propSymbol].getNode());\n  }\n\n  /**\n   * return the slot node (only if the current prop represents a slot)\n   */\n  get slotNode(): IPublicModelNode | null {\n    return ShellNode.create(this[propSymbol].slotNode);\n  }\n\n  /**\n   * judge if it is a prop or not\n   */\n  get isProp(): boolean {\n    return true;\n  }\n\n  /**\n   * 设置值\n   * @param val\n   */\n  setValue(val: IPublicTypeCompositeValue): void {\n    this[propSymbol].setValue(val);\n  }\n\n  /**\n   * 获取值\n   * @returns\n   */\n  getValue(): any {\n    return this[propSymbol].getValue();\n  }\n\n  /**\n   * 移除值\n   */\n  remove(): void {\n    this[propSymbol].remove();\n  }\n\n  /**\n   * 导出值\n   * @param stage\n   * @returns\n   */\n  exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render) {\n    return this[propSymbol].export(stage);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/props.ts",
    "content": "import { IProps as InnerProps, getConvertedExtraKey } from '@alilc/lowcode-designer';\nimport { IPublicTypeCompositeValue, IPublicModelProps, IPublicModelNode, IPublicModelProp } from '@alilc/lowcode-types';\nimport { propsSymbol } from '../symbols';\nimport { Node as ShellNode } from './node';\nimport { Prop as ShellProp } from './prop';\n\nexport class Props implements IPublicModelProps {\n  private readonly [propsSymbol]: InnerProps;\n\n  constructor(props: InnerProps) {\n    this[propsSymbol] = props;\n  }\n\n  static create(props: InnerProps | undefined | null): IPublicModelProps | null {\n    if (!props) {\n      return null;\n    }\n    return new Props(props);\n  }\n\n  /**\n   * id\n   */\n  get id(): string {\n    return this[propsSymbol].id;\n  }\n\n  /**\n   * 返回当前 props 的路径\n   */\n  get path(): string[] {\n    return this[propsSymbol].path;\n  }\n\n  /**\n   * 返回所属的 node 实例\n   */\n  get node(): IPublicModelNode | null {\n    return ShellNode.create(this[propsSymbol].getNode());\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getProp(path: string): IPublicModelProp | null {\n    return ShellProp.create(this[propsSymbol].getProp(path));\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例值\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getPropValue(path: string): any {\n    return this.getProp(path)?.getValue();\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例，\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getExtraProp(path: string): IPublicModelProp | null {\n    return ShellProp.create(this[propsSymbol].getProp(getConvertedExtraKey(path)));\n  }\n\n  /**\n   * 获取指定 path 的属性模型实例值\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getExtraPropValue(path: string): any {\n    return this.getExtraProp(path)?.getValue();\n  }\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   * @returns\n   */\n  setPropValue(path: string, value: IPublicTypeCompositeValue): void {\n    return this.getProp(path)?.setValue(value);\n  }\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   * @returns\n   */\n  setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void {\n    return this.getExtraProp(path)?.setValue(value);\n  }\n\n  /**\n   * test if the specified key is existing or not.\n   * @param key\n   * @returns\n   */\n  has(key: string): boolean {\n    return this[propsSymbol].has(key);\n  }\n\n  /**\n   * add a key with given value\n   * @param value\n   * @param key\n   * @returns\n   */\n  add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any {\n    return this[propsSymbol].add(value, key);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/resource.ts",
    "content": "import { IPublicModelResource } from '@alilc/lowcode-types';\nimport { IResource } from '@alilc/lowcode-workspace';\nimport { resourceSymbol } from '../symbols';\n\nexport class Resource implements IPublicModelResource {\n  readonly [resourceSymbol]: IResource;\n\n  constructor(resource: IResource) {\n    this[resourceSymbol] = resource;\n  }\n\n  get title() {\n    return this[resourceSymbol].title;\n  }\n\n  get id() {\n    return this[resourceSymbol].id;\n  }\n\n  get icon() {\n    return this[resourceSymbol].icon;\n  }\n\n  get options() {\n    return this[resourceSymbol].options;\n  }\n\n  get name() {\n    return this[resourceSymbol].resourceType.name;\n  }\n\n  get config() {\n    return this[resourceSymbol].config;\n  }\n\n  get type() {\n    return this[resourceSymbol].resourceType.type;\n  }\n\n  get category() {\n    return this[resourceSymbol].category;\n  }\n\n  get description() {\n    return this[resourceSymbol].description;\n  }\n\n  get children() {\n    return this[resourceSymbol].children.map((child) => new Resource(child));\n  }\n\n  get viewName() {\n    return this[resourceSymbol].viewName;\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/selection.ts",
    "content": "import {\n  IDocumentModel as InnerDocumentModel,\n  INode as InnerNode,\n  ISelection,\n} from '@alilc/lowcode-designer';\nimport { Node as ShellNode } from './node';\nimport { selectionSymbol } from '../symbols';\nimport { IPublicModelSelection, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types';\n\nexport class Selection implements IPublicModelSelection {\n  private readonly [selectionSymbol]: ISelection;\n\n  constructor(document: InnerDocumentModel) {\n    this[selectionSymbol] = document.selection;\n  }\n\n  /**\n   * 返回选中的节点 id\n   */\n  get selected(): string[] {\n    return this[selectionSymbol].selected;\n  }\n\n  /**\n   * return selected Node instance\n   */\n  get node(): IPublicModelNode | null {\n    const nodes = this.getNodes();\n    return nodes && nodes.length > 0 ? nodes[0] : null;\n  }\n\n  /**\n   * 选中指定节点（覆盖方式）\n   * @param id\n   */\n  select(id: string): void {\n    this[selectionSymbol].select(id);\n  }\n\n  /**\n   * 批量选中指定节点们\n   * @param ids\n   */\n  selectAll(ids: string[]): void {\n    this[selectionSymbol].selectAll(ids);\n  }\n\n  /**\n   * 移除选中的指定节点\n   * @param id\n   */\n  remove(id: string): void {\n    this[selectionSymbol].remove(id);\n  }\n\n  /**\n   * 清除所有选中节点\n   */\n  clear(): void {\n    this[selectionSymbol].clear();\n  }\n\n  /**\n   * 判断是否选中了指定节点\n   * @param id\n   * @returns\n   */\n  has(id: string): boolean {\n    return this[selectionSymbol].has(id);\n  }\n\n  /**\n   * 选中指定节点（增量方式）\n   * @param id\n   */\n  add(id: string): void {\n    this[selectionSymbol].add(id);\n  }\n\n  /**\n   * 获取选中的节点实例\n   * @returns\n   */\n  getNodes(): IPublicModelNode[] {\n    const innerNodes = this[selectionSymbol].getNodes();\n    const nodes: IPublicModelNode[] = [];\n    innerNodes.forEach((node: InnerNode) => {\n      const shellNode = ShellNode.create(node);\n      if (shellNode) {\n        nodes.push(shellNode);\n      }\n    });\n    return nodes;\n  }\n\n  /**\n   * 获取选区的顶层节点\n   * for example:\n   *  getNodes() returns [A, subA, B], then\n   *  getTopNodes() will return [A, B], subA will be removed\n   * @returns\n   */\n  getTopNodes(includeRoot: boolean = false): IPublicModelNode[] {\n    const innerNodes = this[selectionSymbol].getTopNodes(includeRoot);\n    const nodes: IPublicModelNode[] = [];\n    innerNodes.forEach((node: InnerNode) => {\n      const shellNode = ShellNode.create(node);\n      if (shellNode) {\n        nodes.push(shellNode);\n      }\n    });\n    return nodes;\n  }\n\n  onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable {\n    return this[selectionSymbol].onSelectionChange(fn);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/setting-field.ts",
    "content": "import { ISettingField, isSettingField } from '@alilc/lowcode-designer';\nimport {\n  IPublicTypeCompositeValue,\n  IPublicTypeFieldConfig,\n  IPublicTypeCustomView,\n  IPublicTypeSetterType,\n  IPublicTypeFieldExtraProps,\n  IPublicModelSettingTopEntry,\n  IPublicModelNode,\n  IPublicModelComponentMeta,\n  IPublicTypeSetValueOptions,\n  IPublicModelSettingField,\n  IPublicTypeDisposable,\n} from '@alilc/lowcode-types';\nimport { settingFieldSymbol } from '../symbols';\nimport { Node as ShellNode } from './node';\nimport { SettingTopEntry, SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry';\nimport { ComponentMeta as ShellComponentMeta } from './component-meta';\nimport { isCustomView } from '@alilc/lowcode-utils';\n\nexport class SettingField implements IPublicModelSettingField {\n  private readonly [settingFieldSymbol]: ISettingField;\n\n  constructor(prop: ISettingField) {\n    this[settingFieldSymbol] = prop;\n  }\n\n  static create(prop: ISettingField): IPublicModelSettingField {\n    return new SettingField(prop);\n  }\n\n  /**\n   * 获取设置属性的 isGroup\n   */\n  get isGroup(): boolean {\n    return this[settingFieldSymbol].isGroup;\n  }\n\n  /**\n   * 获取设置属性的 id\n   */\n  get id(): string {\n    return this[settingFieldSymbol].id;\n  }\n\n  /**\n   * 获取设置属性的 name\n   */\n  get name(): string | number | undefined {\n    return this[settingFieldSymbol].name;\n  }\n\n  /**\n   * 获取设置属性的 key\n   */\n  get key(): string | number | undefined {\n    return this[settingFieldSymbol].getKey();\n  }\n\n  /**\n   * 获取设置属性的 path\n   */\n  get path(): any[] {\n    return this[settingFieldSymbol].path;\n  }\n\n  /**\n   * 获取设置属性的 title\n   */\n  get title(): any {\n    return this[settingFieldSymbol].title;\n  }\n\n  /**\n   * 获取设置属性的 setter\n   */\n  get setter(): IPublicTypeSetterType | null {\n    return this[settingFieldSymbol].setter;\n  }\n\n  /**\n   * 获取设置属性的 expanded\n   */\n  get expanded(): boolean {\n    return this[settingFieldSymbol].expanded;\n  }\n\n  /**\n   * 获取设置属性的 extraProps\n   */\n  get extraProps(): IPublicTypeFieldExtraProps {\n    return this[settingFieldSymbol].extraProps;\n  }\n\n  get props(): IPublicModelSettingTopEntry {\n    return ShellSettingTopEntry.create(this[settingFieldSymbol].props);\n  }\n\n  /**\n   * 获取设置属性对应的节点实例\n   */\n  get node(): IPublicModelNode | null {\n    return ShellNode.create(this[settingFieldSymbol].getNode());\n  }\n\n  /**\n   * 获取设置属性的父设置属性\n   */\n  get parent(): IPublicModelSettingField | IPublicModelSettingTopEntry {\n    if (isSettingField(this[settingFieldSymbol].parent)) {\n      return SettingField.create(this[settingFieldSymbol].parent);\n    }\n\n    return SettingTopEntry.create(this[settingFieldSymbol].parent);\n  }\n\n  /**\n   * 获取顶级设置属性\n   */\n  get top(): IPublicModelSettingTopEntry {\n    return ShellSettingTopEntry.create(this[settingFieldSymbol].top);\n  }\n\n  /**\n   * 是否是 SettingField 实例\n   */\n  get isSettingField(): boolean {\n    return this[settingFieldSymbol].isSettingField;\n  }\n\n  /**\n   * componentMeta\n   */\n  get componentMeta(): IPublicModelComponentMeta | null {\n    return ShellComponentMeta.create(this[settingFieldSymbol].componentMeta);\n  }\n\n  /**\n   * 获取设置属性的 items\n   */\n  get items(): Array<IPublicModelSettingField | IPublicTypeCustomView> {\n    return this[settingFieldSymbol].items?.map((item) => {\n      if (isCustomView(item)) {\n        return item;\n      }\n      return item.internalToShellField();\n    });\n  }\n\n  /**\n   * 设置 key 值\n   * @param key\n   */\n  setKey(key: string | number): void {\n    this[settingFieldSymbol].setKey(key);\n  }\n\n  /**\n   * @deprecated use .node instead\n   */\n  getNode() {\n    return this.node;\n  }\n\n  /**\n   * @deprecated use .parent instead\n   */\n  getParent() {\n    return this.parent;\n  }\n\n  /**\n   * 设置值\n   * @param val 值\n   */\n  setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void {\n    this[settingFieldSymbol].setValue(val, false, false, extraOptions);\n  }\n\n  /**\n   * 设置子级属性值\n   * @param propName 子属性名\n   * @param value 值\n   */\n  setPropValue(propName: string | number, value: any): void {\n    this[settingFieldSymbol].setPropValue(propName, value);\n  }\n\n  /**\n   * 清空指定属性值\n   * @param propName\n   */\n  clearPropValue(propName: string | number): void {\n    this[settingFieldSymbol].clearPropValue(propName);\n  }\n\n  /**\n   * 获取配置的默认值\n   * @returns\n   */\n  getDefaultValue(): any {\n    return this[settingFieldSymbol].getDefaultValue();\n  }\n\n  /**\n   * 获取值\n   * @returns\n   */\n  getValue(): any {\n    return this[settingFieldSymbol].getValue();\n  }\n\n  /**\n   * 获取子级属性值\n   * @param propName 子属性名\n   * @returns\n   */\n  getPropValue(propName: string | number): any {\n    return this[settingFieldSymbol].getPropValue(propName);\n  }\n\n  /**\n   * 获取顶层附属属性值\n   */\n  getExtraPropValue(propName: string): any {\n    return this[settingFieldSymbol].getExtraPropValue(propName);\n  }\n\n  /**\n   * 设置顶层附属属性值\n   */\n  setExtraPropValue(propName: string, value: any): void {\n    this[settingFieldSymbol].setExtraPropValue(propName, value);\n  }\n\n  /**\n   * 获取设置属性集\n   * @returns\n   */\n  getProps(): IPublicModelSettingTopEntry {\n    return ShellSettingTopEntry.create(this[settingFieldSymbol].getProps());\n  }\n\n  /**\n   * 是否绑定了变量\n   * @returns\n   */\n  isUseVariable(): boolean {\n    return this[settingFieldSymbol].isUseVariable();\n  }\n\n  /**\n   * 设置绑定变量\n   * @param flag\n   */\n  setUseVariable(flag: boolean): void {\n    this[settingFieldSymbol].setUseVariable(flag);\n  }\n\n  /**\n   * 创建一个设置 field 实例\n   * @param config\n   * @returns\n   */\n  createField(config: IPublicTypeFieldConfig): IPublicModelSettingField {\n    return SettingField.create(this[settingFieldSymbol].createField(config));\n  }\n\n  /**\n   * 获取值，当为变量时，返回 mock\n   * @returns\n   */\n  getMockOrValue(): any {\n    return this[settingFieldSymbol].getMockOrValue();\n  }\n\n  /**\n   * 销毁当前 field 实例\n   */\n  purge(): void {\n    this[settingFieldSymbol].purge();\n  }\n\n  /**\n   * 移除当前 field 实例\n   */\n  remove(): void {\n    this[settingFieldSymbol].remove();\n  }\n\n  /**\n   * 设置 autorun\n   * @param action\n   * @returns\n   */\n  onEffect(action: () => void): IPublicTypeDisposable {\n    return this[settingFieldSymbol].onEffect(action);\n  }\n\n  /**\n   * 返回 shell 模型，兼容某些场景下 field 已经是 shell field 了\n   * @returns\n   */\n  internalToShellField() {\n    return this;\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/model/setting-top-entry.ts",
    "content": "import { ISettingTopEntry } from '@alilc/lowcode-designer';\nimport { settingTopEntrySymbol } from '../symbols';\nimport { Node as ShellNode } from './node';\nimport { IPublicModelSettingTopEntry, IPublicModelNode, IPublicModelSettingField } from '@alilc/lowcode-types';\nimport { SettingField } from './setting-field';\n\nexport class SettingTopEntry implements IPublicModelSettingTopEntry {\n  private readonly [settingTopEntrySymbol]: ISettingTopEntry;\n\n  constructor(prop: ISettingTopEntry) {\n    this[settingTopEntrySymbol] = prop;\n  }\n\n  static create(prop: ISettingTopEntry): IPublicModelSettingTopEntry {\n    return new SettingTopEntry(prop);\n  }\n\n  /**\n   * 返回所属的节点实例\n   */\n  get node(): IPublicModelNode | null {\n    return ShellNode.create(this[settingTopEntrySymbol].getNode());\n  }\n\n  /**\n   * 获取子级属性对象\n   * @param propName\n   * @returns\n   */\n  get(propName: string | number): IPublicModelSettingField {\n    return SettingField.create(this[settingTopEntrySymbol].get(propName)!);\n  }\n\n  /**\n   * @deprecated use .node instead\n   */\n  getNode() {\n    return this.node;\n  }\n\n  /**\n   * 获取指定 propName 的值\n   * @param propName\n   * @returns\n   */\n  getPropValue(propName: string | number): any {\n    return this[settingTopEntrySymbol].getPropValue(propName);\n  }\n\n  /**\n   * 设置指定 propName 的值\n   * @param propName\n   * @param value\n   */\n  setPropValue(propName: string | number, value: any): void {\n    this[settingTopEntrySymbol].setPropValue(propName, value);\n  }\n\n  clearPropValue(propName: string | number) {\n    this[settingTopEntrySymbol].clearPropValue(propName);\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/simulator-render.ts",
    "content": "import { IPublicModelSimulatorRender } from '@alilc/lowcode-types';\nimport { simulatorRenderSymbol } from '../symbols';\nimport { BuiltinSimulatorRenderer } from '@alilc/lowcode-designer';\n\nexport class SimulatorRender implements IPublicModelSimulatorRender {\n  private readonly [simulatorRenderSymbol]: BuiltinSimulatorRenderer;\n\n  constructor(simulatorRender: BuiltinSimulatorRenderer) {\n    this[simulatorRenderSymbol] = simulatorRender;\n  }\n\n  static create(simulatorRender: BuiltinSimulatorRenderer): IPublicModelSimulatorRender {\n    return new SimulatorRender(simulatorRender);\n  }\n\n  get components() {\n    return this[simulatorRenderSymbol].components;\n  }\n\n  rerender() {\n    return this[simulatorRenderSymbol].rerender();\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/skeleton-item.ts",
    "content": "import { skeletonItemSymbol } from '../symbols';\nimport { IPublicModelSkeletonItem } from '@alilc/lowcode-types';\nimport { Dock, IWidget, Panel, PanelDock, Stage, Widget } from '@alilc/lowcode-editor-skeleton';\n\nexport class SkeletonItem implements IPublicModelSkeletonItem {\n  private [skeletonItemSymbol]: IWidget | Widget | Panel | Stage | Dock | PanelDock;\n\n  constructor(skeletonItem: IWidget | Widget | Panel | Stage | Dock | PanelDock) {\n    this[skeletonItemSymbol] = skeletonItem;\n  }\n\n  get name() {\n    return this[skeletonItemSymbol].name;\n  }\n\n  get visible() {\n    return this[skeletonItemSymbol].visible;\n  }\n\n  disable() {\n    this[skeletonItemSymbol].disable?.();\n  }\n\n  enable() {\n    this[skeletonItemSymbol].enable?.();\n  }\n\n  hide() {\n    this[skeletonItemSymbol].hide();\n  }\n\n  show() {\n    this[skeletonItemSymbol].show();\n  }\n\n  toggle() {\n    this[skeletonItemSymbol].toggle();\n  }\n}"
  },
  {
    "path": "packages/shell/src/model/window.ts",
    "content": "import { windowSymbol } from '../symbols';\nimport { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types';\nimport { IEditorWindow } from '@alilc/lowcode-workspace';\nimport { Resource as ShellResource } from './resource';\nimport { EditorView } from './editor-view';\n\nexport class Window implements IPublicModelWindow {\n  private readonly [windowSymbol]: IEditorWindow;\n\n  get id() {\n    return this[windowSymbol]?.id;\n  }\n\n  get title() {\n    return this[windowSymbol].title;\n  }\n\n  get icon() {\n    return this[windowSymbol].icon;\n  }\n\n  get resource(): IPublicModelResource {\n    return new ShellResource(this[windowSymbol].resource);\n  }\n\n  constructor(editorWindow: IEditorWindow) {\n    this[windowSymbol] = editorWindow;\n  }\n\n  importSchema(schema: any): any {\n    this[windowSymbol].importSchema(schema);\n  }\n\n  changeViewType(viewName: string) {\n    this[windowSymbol].changeViewName(viewName, false);\n  }\n\n  onChangeViewType(fun: (viewName: string) => void): IPublicTypeDisposable {\n    return this[windowSymbol].onChangeViewType(fun);\n  }\n\n  async save() {\n    return await this[windowSymbol].save();\n  }\n\n  onSave(fn: () => void) {\n    return this[windowSymbol].onSave(fn);\n  }\n\n  get currentEditorView() {\n    if (this[windowSymbol]._editorView) {\n      return new EditorView(this[windowSymbol]._editorView).toProxy() as any;\n    }\n    return null;\n  }\n\n  get editorViews() {\n    return Array.from(this[windowSymbol].editorViews.values()).map(d => new EditorView(d).toProxy() as any);\n  }\n}\n"
  },
  {
    "path": "packages/shell/src/symbols.ts",
    "content": "/**\n * 以下 symbol 均用于在 shell 层对外暴露的模型中存储相应内部模型的 key\n */\nexport const projectSymbol = Symbol('project');\nexport const designerSymbol = Symbol('designer');\nexport const skeletonSymbol = Symbol('skeleton');\nexport const documentSymbol = Symbol('document');\nexport const editorSymbol = Symbol('editor');\nexport const nodeSymbol = Symbol('node');\nexport const modalNodesManagerSymbol = Symbol('modalNodesManager');\nexport const nodeChildrenSymbol = Symbol('nodeChildren');\nexport const propSymbol = Symbol('prop');\nexport const settingFieldSymbol = Symbol('settingField');\nexport const settingTopEntrySymbol = Symbol('settingTopEntry');\nexport const propsSymbol = Symbol('props');\nexport const detectingSymbol = Symbol('detecting');\nexport const selectionSymbol = Symbol('selection');\nexport const historySymbol = Symbol('history');\nexport const canvasSymbol = Symbol('canvas');\nexport const dragonSymbol = Symbol('dragon');\nexport const componentMetaSymbol = Symbol('componentMeta');\nexport const dropLocationSymbol = Symbol('dropLocation');\nexport const simulatorHostSymbol = Symbol('simulatorHost');\nexport const simulatorRenderSymbol = Symbol('simulatorRender');\nexport const dragObjectSymbol = Symbol('dragObject');\nexport const locateEventSymbol = Symbol('locateEvent');\nexport const designerCabinSymbol = Symbol('designerCabin');\nexport const editorCabinSymbol = Symbol('editorCabin');\nexport const skeletonCabinSymbol = Symbol('skeletonCabin');\nexport const hotkeySymbol = Symbol('hotkey');\nexport const pluginsSymbol = Symbol('plugins');\nexport const workspaceSymbol = Symbol('workspace');\nexport const windowSymbol = Symbol('window');\nexport const pluginInstanceSymbol = Symbol('plugin-instance');\nexport const resourceTypeSymbol = Symbol('resourceType');\nexport const resourceSymbol = Symbol('resource');\nexport const clipboardSymbol = Symbol('clipboard');\nexport const configSymbol = Symbol('configSymbol');\nexport const conditionGroupSymbol = Symbol('conditionGroup');\nexport const editorViewSymbol = Symbol('editorView');\nexport const pluginContextSymbol = Symbol('pluginContext');\nexport const skeletonItemSymbol = Symbol('skeletonItem');\nexport const commandSymbol = Symbol('command');"
  },
  {
    "path": "packages/types/.eslintignore",
    "content": "lib\nes\nnode_modules"
  },
  {
    "path": "packages/types/.prettierrc.js",
    "content": "module.exports = {\n  printWidth: 80,\n  singleQuote: true,\n  trailingComma: 'all',\n  tabSize: 2,\n};\n"
  },
  {
    "path": "packages/types/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.55](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.54...v1.0.55) (2021-06-17)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.54](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.53...v1.0.54) (2021-06-08)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.53](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.52...v1.0.53) (2021-06-07)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.52](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.51...v1.0.52) (2021-06-07)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.51](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.49...v1.0.51) (2021-06-03)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.49](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48...v1.0.49) (2021-05-20)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.48](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.4...v1.0.48) (2021-05-17)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.48-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.3...v1.0.48-beta.4) (2021-05-14)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.48-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.2...v1.0.48-beta.3) (2021-05-13)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.48-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.1...v1.0.48-beta.2) (2021-05-12)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.48-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.0...v1.0.48-beta.1) (2021-05-12)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.48-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.47...v1.0.48-beta.0) (2021-05-11)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.47](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.47-beta.1...v1.0.47) (2021-04-28)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.47-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.47-beta.0...v1.0.47-beta.1) (2021-04-28)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.47-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.46...v1.0.47-beta.0) (2021-04-28)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.46](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.46-beta.0...v1.0.46) (2021-04-27)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.46-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.45...v1.0.46-beta.0) (2021-04-25)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.45](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.45-beta.1...v1.0.45) (2021-04-23)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.45-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.45-beta.0...v1.0.45-beta.1) (2021-04-22)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.45-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44...v1.0.45-beta.0) (2021-04-21)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.44](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44-beta.2...v1.0.44) (2021-04-14)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.44-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44-beta.1...v1.0.44-beta.2) (2021-04-14)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.44-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44-beta.0...v1.0.44-beta.1) (2021-04-14)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.44-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.43...v1.0.44-beta.0) (2021-04-13)\n\n\n### Bug Fixes\n\n* componentsMap 中加入低代码组件信息 ([b7c1183](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b7c11834602d8e4ea84d2dea035a3abf97b33d5c))\n\n\n\n\n\n## [1.0.43](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.43-beta.0...v1.0.43) (2021-04-13)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.43-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.42...v1.0.43-beta.0) (2021-04-13)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.42](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.42-beta.1...v1.0.42) (2021-04-06)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.42-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.42-beta.0...v1.0.42-beta.1) (2021-04-06)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.42-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41...v1.0.42-beta.0) (2021-04-06)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.41](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41-beta.1...v1.0.41) (2021-04-06)\n\n\n### Bug Fixes\n\n* bypass dataSource ([3cb331d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3cb331dcbeee62959ef0b1614c6c3cb2bd3c1a3e))\n\n\n\n\n\n## [1.0.41-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41-beta.1...v1.0.41-beta.2) (2021-04-06)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.41-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41-beta.0...v1.0.41-beta.1) (2021-04-06)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.41-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.40...v1.0.41-beta.0) (2021-04-02)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.40](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.40-beta.1...v1.0.40) (2021-03-31)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.40-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.40-beta.0...v1.0.40-beta.1) (2021-03-31)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.40-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.5...v1.0.40-beta.0) (2021-03-31)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.39-beta.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.4...v1.0.39-beta.5) (2021-03-31)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.39-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.3...v1.0.39-beta.4) (2021-03-30)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.39-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.2...v1.0.39-beta.3) (2021-03-22)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.39-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.1...v1.0.39-beta.2) (2021-03-22)\n\n\n### Bug Fixes\n\n* renderer-core 在非设计渲染态时, 不应处理 hidden 属性 ([7857096](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7857096c0f56308195cc9e27de4f549eee72a10e))\n\n\n\n\n\n## [1.0.39-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.3...v1.0.39-beta.1) (2021-03-12)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.39-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.3...v1.0.39-beta.0) (2021-03-12)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.38-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.1...v1.0.38-beta.3) (2021-03-11)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.38-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.1...v1.0.38-beta.2) (2021-03-11)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.38-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.0...v1.0.38-beta.1) (2021-03-09)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.38-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37...v1.0.38-beta.0) (2021-03-08)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.37](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.6...v1.0.37) (2021-03-05)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.37](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.6...v1.0.37) (2021-03-05)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.37-beta.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.3...v1.0.37-beta.6) (2021-03-03)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.37-beta.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.4...v1.0.37-beta.5) (2021-02-24)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.37-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.3...v1.0.37-beta.4) (2021-02-24)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n## [1.0.37-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.2...v1.0.37-beta.3) (2021-02-24)\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n\n\n\n\n<a name=\"1.0.37-beta.2\"></a>\n## [1.0.37-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.1...v1.0.37-beta.2) (2021-02-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.37-beta.1\"></a>\n## [1.0.37-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.36...v1.0.37-beta.1) (2021-02-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.36\"></a>\n## [1.0.36](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.36-beta.0...v1.0.36) (2021-02-04)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.36-beta.0\"></a>\n## [1.0.36-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.35...v1.0.36-beta.0) (2021-02-04)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.35\"></a>\n## [1.0.35](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.35-beta.1...v1.0.35) (2021-02-03)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.35-beta.1\"></a>\n## [1.0.35-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.35-beta.0...v1.0.35-beta.1) (2021-02-03)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.35-beta.0\"></a>\n## [1.0.35-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33...v1.0.35-beta.0) (2021-02-01)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.33\"></a>\n## [1.0.33](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33-beta.1...v1.0.33) (2021-01-29)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.33-beta.1\"></a>\n## [1.0.33-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33-beta.0...v1.0.33-beta.1) (2021-01-28)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.33-beta.0\"></a>\n## [1.0.33-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32...v1.0.33-beta.0) (2021-01-28)\n\n\n### Bug Fixes\n\n* 修复从其他页面粘贴过来的 modal 位置不对 ([158b6a6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/158b6a6))\n\n\n\n\n<a name=\"1.0.32\"></a>\n## [1.0.32](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32-beta.2...v1.0.32) (2021-01-26)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.32-beta.2\"></a>\n## [1.0.32-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32-beta.0...v1.0.32-beta.2) (2021-01-26)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.32-beta.0\"></a>\n## [1.0.32-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.31...v1.0.32-beta.0) (2021-01-25)\n\n\n### Features\n\n* meta 增加 hideSelectTools ([e7287d4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e7287d4))\n* metadata 增加 canHovering 配置 ([88e128e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/88e128e))\n* 增加 plugin 的 autoInit 注册方式 ([4f9be73](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4f9be73))\n\n\n\n\n<a name=\"1.0.31\"></a>\n## [1.0.31](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.31-beta.1...v1.0.31) (2021-01-15)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.31-beta.1\"></a>\n## [1.0.31-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30...v1.0.31-beta.1) (2021-01-15)\n\n\n### Bug Fixes\n\n* 延迟加载内置 setter ([99cbdd5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/99cbdd5))\n\n\n\n\n<a name=\"1.0.31-beta.0\"></a>\n## [1.0.31-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30...v1.0.31-beta.0) (2021-01-15)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30\"></a>\n## [1.0.30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.17...v1.0.30) (2021-01-14)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.17\"></a>\n## [1.0.30-beta.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.16...v1.0.30-beta.17) (2021-01-14)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.16\"></a>\n## [1.0.30-beta.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.14...v1.0.30-beta.16) (2021-01-14)\n\n\n### Features\n\n* 将 typings 在顶层导出 ([d2aed7d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2aed7d))\n\n\n\n\n<a name=\"1.0.30-beta.15\"></a>\n## [1.0.30-beta.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.14...v1.0.30-beta.15) (2021-01-13)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.14\"></a>\n## [1.0.30-beta.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.13...v1.0.30-beta.14) (2021-01-13)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.13\"></a>\n## [1.0.30-beta.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.12...v1.0.30-beta.13) (2021-01-13)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.12\"></a>\n## [1.0.30-beta.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.11...v1.0.30-beta.12) (2021-01-13)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.11\"></a>\n## [1.0.30-beta.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.10...v1.0.30-beta.11) (2021-01-12)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.10\"></a>\n## [1.0.30-beta.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.9...v1.0.30-beta.10) (2021-01-12)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.9\"></a>\n## [1.0.30-beta.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.8...v1.0.30-beta.9) (2021-01-11)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.8\"></a>\n## [1.0.30-beta.8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.7...v1.0.30-beta.8) (2021-01-11)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.7\"></a>\n## [1.0.30-beta.7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.6...v1.0.30-beta.7) (2021-01-11)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.30-beta.6\"></a>\n## [1.0.30-beta.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.29...v1.0.30-beta.6) (2021-01-09)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.29\"></a>\n## [1.0.29](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.28-beta.2...v1.0.29) (2021-01-05)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.28-beta.2\"></a>\n## [1.0.28-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.28-beta.1...v1.0.28-beta.2) (2021-01-04)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.28-beta.1\"></a>\n## [1.0.28-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27...v1.0.28-beta.1) (2021-01-04)\n\n\n### Features\n\n* 🎸 utils 的定义中增加对于 function 类型的支持 ([29b1daf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/29b1daf))\n* 支持新版的 plugin 机制 ([1e8fc63](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1e8fc63))\n\n\n\n\n<a name=\"1.0.28-beta.0\"></a>\n## [1.0.28-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27...v1.0.28-beta.0) (2021-01-04)\n\n\n### Features\n\n* 🎸 utils 的定义中增加对于 function 类型的支持 ([29b1daf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/29b1daf))\n* 支持新版的 plugin 机制 ([1e8fc63](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1e8fc63))\n\n\n\n\n<a name=\"1.0.27\"></a>\n## [1.0.27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.2...v1.0.27) (2020-12-24)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.27-beta.2\"></a>\n## [1.0.27-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.1...v1.0.27-beta.2) (2020-12-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.27-beta.1\"></a>\n## [1.0.27-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.0...v1.0.27-beta.1) (2020-12-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.27-beta.0\"></a>\n## [1.0.27-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26...v1.0.27-beta.0) (2020-12-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.26\"></a>\n## [1.0.26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26-beta.1...v1.0.26) (2020-12-22)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.26-beta.1\"></a>\n## [1.0.26-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26-beta.0...v1.0.26-beta.1) (2020-12-22)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.26-beta.0\"></a>\n## [1.0.26-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.25-beta.1...v1.0.26-beta.0) (2020-12-22)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.25-beta.1\"></a>\n## [1.0.25-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.4...v1.0.25-beta.1) (2020-12-15)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.24-beta.4\"></a>\n## [1.0.24-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.3...v1.0.24-beta.4) (2020-12-14)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.24-beta.3\"></a>\n## [1.0.24-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.2...v1.0.24-beta.3) (2020-12-11)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.24-beta.2\"></a>\n## [1.0.24-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.1...v1.0.24-beta.2) (2020-12-10)\n\n\n### Bug Fixes\n\n* 删除无用代码, 解决 ts 编译报错 ([1f241ea](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1f241ea))\n\n\n\n\n<a name=\"1.0.24-beta.1\"></a>\n## [1.0.24-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.0...v1.0.24-beta.1) (2020-12-09)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.24-beta.0\"></a>\n## [1.0.24-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23...v1.0.24-beta.0) (2020-12-09)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.23\"></a>\n## [1.0.23](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.2...v1.0.23) (2020-12-08)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.23-beta.5\"></a>\n## [1.0.23-beta.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.4...v1.0.23-beta.5) (2020-12-08)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.23-beta.4\"></a>\n## [1.0.23-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.3...v1.0.23-beta.4) (2020-12-08)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.23-beta.3\"></a>\n## [1.0.23-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.2...v1.0.23-beta.3) (2020-12-08)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.23-beta.2\"></a>\n## [1.0.23-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.1...v1.0.23-beta.2) (2020-12-08)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.23-beta.1\"></a>\n## [1.0.23-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-29...v1.0.23-beta.1) (2020-12-07)\n\n\n### Bug Fixes\n\n* 🐛 use lowcode types ([b11425b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b11425b))\n* 🐛 根据低代码规范,数据源的配置中isInit和 type 都是有默认值的,所以应该是可选的 ([4baf0b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4baf0b4))\n* datasource版本错误问题 ([a247878](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a247878))\n* fix test result ([7f6fbe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7f6fbe8))\n* JSExpression 增加 compiled ([9f51e39](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f51e39))\n* miniAppBuildType config(temp) ([584b4c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/584b4c2))\n* typo of onResizeEnd and remove ([8df5f05](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8df5f05))\n* will fetch 按照协议修改 ([b9bf800](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9bf800))\n\n\n### Features\n\n* 🎸 urlParams 类型的数据源不需要 options, 所以 options 改成可选为好 ([8114c6f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8114c6f))\n* 🎸 按照中后台搭建协议规范文档补充 JSFunction 的定义和数据源定义中一些字段 ([8b1d0c7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b1d0c7))\n* 🎸 根据低代码协议文档, 完善UtilsMap的定义 ([7fe4bc0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7fe4bc0))\n* 🎸 根据低代码协议文档, 将 BlockSchema 也改成继承自 ContainerSchema ([7901c8e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7901c8e))\n* 🎸 补充规范中定义的 JSFunction 类型 ([9e32525](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9e32525))\n* split datasource types ([fd80698](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd80698))\n* update datasource engine ([cf3c7db](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cf3c7db))\n* 合入 trunk-vision 代码 ([ea6bc7a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea6bc7a))\n* 调整 datasource-handlers ([2b9bcb5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2b9bcb5))\n\n\n\n\n<a name=\"1.0.23-beta.0\"></a>\n## [1.0.23-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-29...v1.0.23-beta.0) (2020-12-07)\n\n\n### Bug Fixes\n\n* 🐛 use lowcode types ([b11425b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b11425b))\n* 🐛 根据低代码规范,数据源的配置中isInit和 type 都是有默认值的,所以应该是可选的 ([4baf0b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4baf0b4))\n* datasource版本错误问题 ([a247878](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a247878))\n* fix test result ([7f6fbe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7f6fbe8))\n* JSExpression 增加 compiled ([9f51e39](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f51e39))\n* miniAppBuildType config(temp) ([584b4c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/584b4c2))\n* typo of onResizeEnd and remove ([8df5f05](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8df5f05))\n* will fetch 按照协议修改 ([b9bf800](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9bf800))\n\n\n### Features\n\n* 🎸 urlParams 类型的数据源不需要 options, 所以 options 改成可选为好 ([8114c6f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8114c6f))\n* 🎸 按照中后台搭建协议规范文档补充 JSFunction 的定义和数据源定义中一些字段 ([8b1d0c7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b1d0c7))\n* 🎸 根据低代码协议文档, 完善UtilsMap的定义 ([7fe4bc0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7fe4bc0))\n* 🎸 根据低代码协议文档, 将 BlockSchema 也改成继承自 ContainerSchema ([7901c8e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7901c8e))\n* 🎸 补充规范中定义的 JSFunction 类型 ([9e32525](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9e32525))\n* split datasource types ([fd80698](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd80698))\n* update datasource engine ([cf3c7db](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cf3c7db))\n* 合入 trunk-vision 代码 ([ea6bc7a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea6bc7a))\n* 调整 datasource-handlers ([2b9bcb5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2b9bcb5))\n\n\n\n\n<a name=\"1.0.20\"></a>\n## [1.0.20](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.19...@ali/lowcode-types@1.0.20) (2020-11-16)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.19\"></a>\n## [1.0.19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.18...@ali/lowcode-types@1.0.19) (2020-11-10)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.18\"></a>\n## [1.0.18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.17...@ali/lowcode-types@1.0.18) (2020-11-10)\n\n\n### Bug Fixes\n\n* typo of onResizeEnd and remove ([8df5f05](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8df5f05))\n\n\n\n\n<a name=\"1.0.17\"></a>\n## [1.0.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.16...@ali/lowcode-types@1.0.17) (2020-11-05)\n\n\n### Bug Fixes\n\n* datasource版本错误问题 ([a247878](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a247878))\n\n\n### Features\n\n* split datasource types ([fd80698](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd80698))\n\n\n\n\n<a name=\"1.0.16\"></a>\n## [1.0.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.15...@ali/lowcode-types@1.0.16) (2020-11-05)\n* 低成本方案支持绝对布局容器 ([a6067e8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a6067e8))\n\n\n\n<a name=\"0.12.1-18\"></a>\n## [0.12.1-18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-17...v0.12.1-18) (2020-10-17)\n\n\n\n<a name=\"0.12.1-17\"></a>\n## [0.12.1-17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-16...v0.12.1-17) (2020-10-14)\n\n\n\n<a name=\"0.12.1-16\"></a>\n## [0.12.1-16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-15...v0.12.1-16) (2020-10-12)\n\n\n\n<a name=\"0.12.1-15\"></a>\n## [0.12.1-15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-1...v0.12.1-15) (2020-10-12)\n\n\n\n<a name=\"0.12.1-14\"></a>\n## [0.12.1-14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-13...v0.12.1-14) (2020-10-10)\n\n\n\n<a name=\"0.12.1-13\"></a>\n## [0.12.1-13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-12...v0.12.1-13) (2020-09-28)\n\n\n\n<a name=\"0.12.1-12\"></a>\n## [0.12.1-12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-11...v0.12.1-12) (2020-09-28)\n\n\n\n<a name=\"0.12.1-11\"></a>\n## [0.12.1-11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-10...v0.12.1-11) (2020-09-27)\n\n\n\n<a name=\"0.12.1-10\"></a>\n## [0.12.1-10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-9...v0.12.1-10) (2020-09-27)\n\n\n\n<a name=\"0.12.1-9\"></a>\n## [0.12.1-9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-8...v0.12.1-9) (2020-09-27)\n\n\n\n<a name=\"0.12.1-8\"></a>\n## [0.12.1-8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-7...v0.12.1-8) (2020-09-27)\n\n\n\n<a name=\"0.12.1-7\"></a>\n## [0.12.1-7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-2...v0.12.1-7) (2020-09-27)\n\n\n\n\n<a name=\"0.13.1-11\"></a>\n## [0.13.1-11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-10...v0.13.1-11) (2020-11-02)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-10\"></a>\n## [0.13.1-10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-9...v0.13.1-10) (2020-10-26)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-9\"></a>\n## [0.13.1-9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-7...v0.13.1-9) (2020-10-26)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-8\"></a>\n## [0.13.1-8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-7...v0.13.1-8) (2020-10-26)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-7\"></a>\n## [0.13.1-7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-6...v0.13.1-7) (2020-10-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-6\"></a>\n## [0.13.1-6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-5...v0.13.1-6) (2020-10-22)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-5\"></a>\n## [0.13.1-5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-4...v0.13.1-5) (2020-10-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-4\"></a>\n## [0.13.1-4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-3...v0.13.1-4) (2020-10-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-3\"></a>\n## [0.13.1-3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-2...v0.13.1-3) (2020-10-19)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-2\"></a>\n## [0.13.1-2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-1...v0.13.1-2) (2020-10-19)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.1-1\"></a>\n## [0.13.1-1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-3...v0.13.1-1) (2020-10-12)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.12.1-3\"></a>\n## [0.12.1-3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-2...v0.12.1-3) (2020-10-12)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.15\"></a>\n## [1.0.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.14...@ali/lowcode-types@1.0.15) (2020-11-05)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.14\"></a>\n## [1.0.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.13...@ali/lowcode-types@1.0.14) (2020-11-04)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.13\"></a>\n## [1.0.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.12...@ali/lowcode-types@1.0.13) (2020-11-04)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.13\"></a>\n## [1.0.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.12...@ali/lowcode-types@1.0.13) (2020-11-02)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.12\"></a>\n## [1.0.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.11...@ali/lowcode-types@1.0.12) (2020-10-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.11\"></a>\n## [1.0.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.10...@ali/lowcode-types@1.0.11) (2020-10-19)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.10\"></a>\n## [1.0.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.9...@ali/lowcode-types@1.0.10) (2020-09-29)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.9\"></a>\n## [1.0.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.8...@ali/lowcode-types@1.0.9) (2020-09-28)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.8\"></a>\n## [1.0.8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.8-0...@ali/lowcode-types@1.0.8) (2020-09-28)\n\n\n### Bug Fixes\n\n* 🐛 根据低代码规范,数据源的配置中isInit和 type 都是有默认值的,所以应该是可选的 ([4baf0b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4baf0b4))\n* 🐛 use lowcode types ([b11425b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b11425b))\n* fix test result ([7f6fbe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7f6fbe8))\n* miniAppBuildType config(temp) ([584b4c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/584b4c2))\n* currentPage.id 返回 formUuid ([775725d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/775725d))\n* fix NextTable callback function ([ce77375](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ce77375))\n* panel visible time ([18ac1fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/18ac1fa))\n* supports ([371b84c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/371b84c))\n* 低代码组件 props 显示 object 问题 ([116498e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/116498e))\n* 修复 slot 获取初始值异常的 bug ([63b19f1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/63b19f1))\n* 修复判断动态 setter 的逻辑 ([d195d7f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d195d7f))\n* 兼容事件绑定 ([f4c07af](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f4c07af))\n* 可以降级到历史的 JSBlock 格式 ([af1746b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af1746b))\n* 合并master分支 ([bd2c6ad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd2c6ad))\n\n\n### Features\n\n* 🎸 按照中后台搭建协议规范文档补充 JSFunction 的定义和数据源定义中一些字段 ([8b1d0c7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b1d0c7))\n* 🎸 补充规范中定义的 JSFunction 类型 ([9e32525](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9e32525))\n* 🎸 根据低代码协议文档, 将 BlockSchema 也改成继承自 ContainerSchema ([7901c8e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7901c8e))\n* 🎸 根据低代码协议文档, 完善UtilsMap的定义 ([7fe4bc0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7fe4bc0))\n* 🎸 urlParams 类型的数据源不需要 options, 所以 options 改成可选为好 ([8114c6f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8114c6f))\n* 🎸 增加icon相关的判断函数 ([89064f5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/89064f5))\n* add filter reducer ([17c6ed3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/17c6ed3))\n* merge live mode ([92c3039](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/92c3039))\n* show value state ([bd49e50](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd49e50))\n* support plaintext liveediting ([ea62f12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea62f12))\n* support prop.autorun ([c0a5235](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c0a5235))\n* 修复状态切换失效 ([2e3f60d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2e3f60d))\n* 编辑器 hooks 能力实现 ([f3ac23b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f3ac23b))\n\n\n\n\n<a name=\"1.0.8-0\"></a>\n## [1.0.8-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.19...@ali/lowcode-types@1.0.8-0) (2020-09-09)\n\n\n### Bug Fixes\n\n* 合并master分支 ([bd2c6ad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd2c6ad))\n* fix NextTable callback function ([ce77375](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ce77375))\n\n\n\n\n<a name=\"0.8.19\"></a>\n## [0.8.19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.18...@ali/lowcode-types@0.8.19) (2020-09-03)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.8.18\"></a>\n## [0.8.18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.17...@ali/lowcode-types@0.8.18) (2020-09-03)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.8.17\"></a>\n## [0.8.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.16...@ali/lowcode-types@0.8.17) (2020-08-24)\n<a name=\"1.0.7-0\"></a>\n## [1.0.7-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.6-0...@ali/lowcode-types@1.0.7-0) (2020-09-02)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.6-0\"></a>\n## [1.0.6-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.17...@ali/lowcode-types@1.0.6-0) (2020-09-02)\n\n\n### Bug Fixes\n\n* 合并master分支 ([bd2c6ad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd2c6ad))\n* fix NextTable callback function ([ce77375](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ce77375))\n\n\n\n\n<a name=\"1.0.5-0\"></a>\n## [1.0.5-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.4-0...@ali/lowcode-types@1.0.5-0) (2020-08-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.4-0\"></a>\n## [1.0.4-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.3-0...@ali/lowcode-types@1.0.4-0) (2020-08-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.3-0\"></a>\n## [1.0.3-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.2-0...@ali/lowcode-types@1.0.3-0) (2020-08-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.2-0\"></a>\n## [1.0.2-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@1.0.1-0...@ali/lowcode-types@1.0.2-0) (2020-08-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.1-0\"></a>\n## [1.0.1-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.16...@ali/lowcode-types@1.0.1-0) (2020-08-20)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"1.0.0\"></a>\n# [1.0.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.13.0...@ali/lowcode-types@1.0.0) (2020-08-17)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.13.0\"></a>\n# [0.13.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.12.0...@ali/lowcode-types@0.13.0) (2020-08-17)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.12.0\"></a>\n# [0.12.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.10.0...@ali/lowcode-types@0.12.0) (2020-08-17)\n<a name=\"0.8.16\"></a>\n## [0.8.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.15...@ali/lowcode-types@0.8.16) (2020-08-19)\n\n\n### Bug Fixes\n\n* currentPage.id 返回 formUuid ([775725d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/775725d))\n\n\n\n\n<a name=\"0.8.15\"></a>\n## [0.8.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.14...@ali/lowcode-types@0.8.15) (2020-08-17)\n\n\n### Bug Fixes\n\n* 修复判断动态 setter 的逻辑 ([d195d7f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d195d7f))\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.11.0\"></a>\n# [0.11.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.10.0...@ali/lowcode-types@0.11.0) (2020-08-17)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.10.0\"></a>\n# [0.10.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.9.0...@ali/lowcode-types@0.10.0) (2020-08-16)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.9.0\"></a>\n# [0.9.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.14...@ali/lowcode-types@0.9.0) (2020-08-14)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.8.14\"></a>\n## [0.8.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.13...@ali/lowcode-types@0.8.14) (2020-08-04)\n\n\n### Bug Fixes\n\n* 修复 slot 获取初始值异常的 bug ([63b19f1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/63b19f1))\n\n\n\n\n<a name=\"0.8.13\"></a>\n## [0.8.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.12...@ali/lowcode-types@0.8.13) (2020-07-21)\n\n\n### Bug Fixes\n\n* 兼容事件绑定 ([f4c07af](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f4c07af))\n\n\n\n\n<a name=\"0.8.12\"></a>\n## [0.8.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.11...@ali/lowcode-types@0.8.12) (2020-07-21)\n\n\n### Bug Fixes\n\n* 可以降级到历史的 JSBlock 格式 ([af1746b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af1746b))\n\n\n\n\n<a name=\"0.8.11\"></a>\n## [0.8.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.10...@ali/lowcode-types@0.8.11) (2020-07-13)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.8.10\"></a>\n## [0.8.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.9...@ali/lowcode-types@0.8.10) (2020-07-12)\n\n\n### Bug Fixes\n\n* 低代码组件 props 显示 object 问题 ([116498e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/116498e))\n\n\n\n\n<a name=\"0.8.9\"></a>\n## [0.8.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.7...@ali/lowcode-types@0.8.9) (2020-06-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.8.7\"></a>\n## [0.8.7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.6...@ali/lowcode-types@0.8.7) (2020-06-23)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.8.6\"></a>\n## [0.8.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.5...@ali/lowcode-types@0.8.6) (2020-06-15)\n\n\n### Features\n\n* support prop.autorun ([c0a5235](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c0a5235))\n\n\n\n\n<a name=\"0.8.5\"></a>\n## [0.8.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.4...@ali/lowcode-types@0.8.5) (2020-05-18)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n\n<a name=\"0.8.4\"></a>\n## [0.8.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.3...@ali/lowcode-types@0.8.4) (2020-05-15)\n\n\n### Features\n\n* add filter reducer ([17c6ed3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/17c6ed3))\n\n\n\n\n<a name=\"0.8.3\"></a>\n## [0.8.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.2...@ali/lowcode-types@0.8.3) (2020-05-13)\n\n\n### Bug Fixes\n\n* panel visible time ([18ac1fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/18ac1fa))\n* supports ([371b84c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/371b84c))\n\n\n### Features\n\n* show value state ([bd49e50](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd49e50))\n* support plaintext liveediting ([ea62f12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea62f12))\n\n\n\n\n<a name=\"0.8.2\"></a>\n## [0.8.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-types@0.8.1...@ali/lowcode-types@0.8.2) (2020-05-07)\n\n\n### Features\n\n* 🎸 增加icon相关的判断函数 ([89064f5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/89064f5))\n* 修复状态切换失效 ([2e3f60d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2e3f60d))\n\n\n\n\n<a name=\"0.8.1\"></a>\n## 0.8.1 (2020-04-27)\n\n\n\n\n**Note:** Version bump only for package @ali/lowcode-types\n"
  },
  {
    "path": "packages/types/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\"\n  ]\n}\n"
  },
  {
    "path": "packages/types/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-types\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Types for Ali lowCode engine\",\n  \"files\": [\n    \"es\",\n    \"lib\"\n  ],\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"scripts\": {\n    \"build\": \"build-scripts build\"\n  },\n  \"dependencies\": {\n    \"@alilc/lowcode-datasource-types\": \"^1.0.0\",\n    \"react\": \"^16.9\",\n    \"strict-event-emitter-types\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/types\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/types/src/activity.ts",
    "content": "import { IPublicTypeNodeSchema } from './shell';\n\nexport enum ActivityType {\n  'ADDED' = 'added',\n  'DELETED' = 'deleted',\n  'MODIFIED' = 'modified',\n  'COMPOSITE' = 'composite',\n}\n\ninterface IActivityPayload {\n  schema: IPublicTypeNodeSchema;\n  location?: {\n    parent: {\n      nodeId: string;\n      index: number;\n    };\n  };\n  prop: any;\n  oldValue: any;\n  newValue: any;\n}\n\n/**\n * TODO: not sure if this is used anywhere\n * @deprecated\n */\nexport type ActivityData = {\n  type: ActivityType;\n  payload: IActivityPayload;\n};\n"
  },
  {
    "path": "packages/types/src/assets.ts",
    "content": "export enum AssetLevel {\n  // 环境依赖库 比如 react, react-dom\n  Environment = 1,\n  // 基础类库，比如 lodash deep fusion antd\n  Library = 2,\n  // 主题\n  Theme = 3,\n  // 运行时\n  Runtime = 4,\n  // 业务组件\n  Components = 5,\n  // 应用 & 页面\n  App = 6,\n}\n\nexport const AssetLevels = [\n  AssetLevel.Environment,\n  AssetLevel.Library,\n  AssetLevel.Theme,\n  AssetLevel.Runtime,\n  AssetLevel.Components,\n  AssetLevel.App,\n];\n\nexport type URL = string;\n\nexport enum AssetType {\n  JSUrl = 'jsUrl',\n  CSSUrl = 'cssUrl',\n  CSSText = 'cssText',\n  JSText = 'jsText',\n  Bundle = 'bundle',\n}\n\nexport interface AssetItem {\n  type: AssetType;\n  content?: string | null;\n  device?: string;\n  level?: AssetLevel;\n  id?: string;\n  scriptType?: string;\n}\n\nexport type AssetList = Array<Asset | undefined | null>;\n\nexport type Asset = AssetList | AssetBundle | AssetItem | URL;\n\nexport interface AssetBundle {\n  type: AssetType.Bundle;\n  level?: AssetLevel;\n  assets?: Asset | AssetList | null;\n}\n"
  },
  {
    "path": "packages/types/src/code-intermediate.ts",
    "content": "export interface PackageJSON {\n  name: string;\n  version: string;\n  description?: string;\n  dependencies: Record<string, string>;\n  devDependencies: Record<string, string>;\n  scripts?: Record<string, string>;\n  engines?: Record<string, string>;\n  repository?: {\n    type: string;\n    url: string;\n  };\n  private?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/code-result.ts",
    "content": "/**\n * 导出内容结构，文件夹\n *\n * @export\n * @interface ResultDir\n */\nexport interface ResultDir {\n  /**\n   * 文件夹名称，Root 名称默认为 .\n   *\n   * @type {string}\n   * @memberof ResultDir\n   */\n  name: string;\n  /**\n   * 子目录\n   *\n   * @type {ResultDir[]}\n   * @memberof ResultDir\n   */\n  dirs: ResultDir[];\n  /**\n   * 文件夹内文件\n   *\n   * @type {ResultFile[]}\n   * @memberof ResultDir\n   */\n  files: ResultFile[];\n}\n\n/**\n * 导出内容，对文件的描述\n *\n * @export\n * @interface ResultFile\n */\nexport interface ResultFile {\n  /**\n   * 文件名\n   *\n   * @type {string}\n   * @memberof ResultFile\n   */\n  name: string;\n  /**\n   * 文件类型扩展名，例如 .js .less\n   *\n   * @type {string}\n   * @memberof ResultFile\n   */\n  ext: string;\n  /**\n   * 文件内容\n   *\n   * @type {string}\n   * @memberof ResultFile\n   */\n  content: string;\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/index.ts",
    "content": "export * from './isActionContentObject';\nexport * from './isCustomView';\nexport * from './isDOMText';\nexport * from './isDynamicSetter';\nexport * from './isI18nData';\nexport * from './isJSBlock';\nexport * from './isJSExpression';\nexport * from './isJSFunction';\nexport * from './isJSSlot';\nexport * from './isLowCodeComponentType';\nexport * from './isNodeSchema';\nexport * from './isPlainObject';\nexport * from './isProCodeComponentType';\nexport * from './isProjectSchema';\nexport * from './isReactClass';\nexport * from './isReactComponent';\nexport * from './isSetterConfig';\nexport * from './isTitleConfig';"
  },
  {
    "path": "packages/types/src/deprecated/isActionContentObject.ts",
    "content": "import { IPublicTypeActionContentObject } from '../shell';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject {\n  return obj && typeof obj === 'object';\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isCustomView.ts",
    "content": "import { isValidElement } from 'react';\nimport { isReactComponent } from './isReactComponent';\nimport { IPublicTypeCustomView } from '../shell/type/custom-view';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isCustomView(obj: any): obj is IPublicTypeCustomView {\n  return obj && (isValidElement(obj) || isReactComponent(obj));\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isDOMText.ts",
    "content": "import { IPublicTypeDOMText } from '../shell/type/dom-text';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isDOMText(data: any): data is IPublicTypeDOMText {\n  return typeof data === 'string';\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isDynamicSetter.ts",
    "content": "import { isReactClass } from './isReactClass';\nimport { IPublicTypeDynamicSetter } from '../shell/type/dynamic-setter';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isDynamicSetter(obj: any): obj is IPublicTypeDynamicSetter {\n  return obj && typeof obj === 'function' && !isReactClass(obj);\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isI18nData.ts",
    "content": "\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isI18nData(obj: any): boolean {\n  return obj && obj.type === 'i18n';\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isJSBlock.ts",
    "content": "import { IPublicTypeJSBlock } from '../shell/type/value-type';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isJSBlock(data: any): data is IPublicTypeJSBlock {\n  return data && data.type === 'JSBlock';\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isJSExpression.ts",
    "content": "import { IPublicTypeJSExpression } from '../shell/type/value-type';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isJSExpression(data: any): data is IPublicTypeJSExpression {\n  return data && data.type === 'JSExpression' && data.extType !== 'function';\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isJSFunction.ts",
    "content": "import { IPublicTypeJSFunction } from '../shell/type/value-type';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isJSFunction(x: any): x is IPublicTypeJSFunction {\n  return typeof x === 'object' && x && x.type === 'JSFunction';\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isJSSlot.ts",
    "content": "import { IPublicTypeJSSlot } from '../shell/type/value-type';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isJSSlot(data: any): data is IPublicTypeJSSlot {\n  return data && data.type === 'JSSlot';\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isLowCodeComponentType.ts",
    "content": "import { isProCodeComponentType } from './isProCodeComponentType';\nimport { IPublicTypeComponentMap, IPublicTypeLowCodeComponent } from '../shell/type/npm';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isLowCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeLowCodeComponent {\n  return !isProCodeComponentType(desc);\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isNodeSchema.ts",
    "content": "import { IPublicTypeNodeSchema } from '../shell';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isNodeSchema(data: any): data is IPublicTypeNodeSchema {\n  return data && data.componentName;\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isPlainObject.ts",
    "content": "/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isPlainObject(value: any): value is Record<string, unknown> {\n  if (typeof value !== 'object') {\n    return false;\n  }\n  const proto = Object.getPrototypeOf(value);\n  return proto === Object.prototype || proto === null || Object.getPrototypeOf(proto) === null;\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isProCodeComponentType.ts",
    "content": "import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '../shell/type/npm';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent {\n  return 'package' in desc;\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isProjectSchema.ts",
    "content": "/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isProjectSchema(data: any): boolean {\n  return data && data.componentsTree;\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isReactClass.ts",
    "content": "import { ComponentClass, Component } from 'react';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isReactClass(obj: any): obj is ComponentClass<any> {\n  return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component);\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isReactComponent.ts",
    "content": "import { ComponentType } from 'react';\nimport { isReactClass } from './isReactClass';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isReactComponent(obj: any): obj is ComponentType<any> {\n  return obj && (isReactClass(obj) || typeof obj === 'function');\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isSetterConfig.ts",
    "content": "import { IPublicTypeSetterConfig } from '../shell/type/setter-config';\nimport { isCustomView } from './isCustomView';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isSetterConfig(obj: any): obj is IPublicTypeSetterConfig {\n  return obj && typeof obj === 'object' && 'componentName' in obj && !isCustomView(obj);\n}\n"
  },
  {
    "path": "packages/types/src/deprecated/isTitleConfig.ts",
    "content": "import { isI18nData } from './isI18nData';\nimport { isPlainObject } from './isPlainObject';\nimport { IPublicTypeTitleConfig } from '../shell/type/title-config';\n\n/**\n * @deprecated use same function from '@alilc/lowcode-utils' instead\n */\nexport function isTitleConfig(obj: any): obj is IPublicTypeTitleConfig {\n  return isPlainObject(obj) && !isI18nData(obj);\n}\n"
  },
  {
    "path": "packages/types/src/editor.ts",
    "content": "import { ReactNode, ComponentType } from 'react';\nimport { IPublicTypeNpmInfo, IPublicModelEditor } from './shell';\n\nexport interface EditorConfig {\n  skeleton?: SkeletonConfig;\n  theme?: ThemeConfig;\n  plugins?: PluginsConfig;\n  hooks?: HooksConfig;\n  shortCuts?: ShortCutsConfig;\n  utils?: UtilsConfig;\n  constants?: ConstantsConfig;\n  lifeCycles?: LifeCyclesConfig;\n  i18n?: I18nConfig;\n}\n\nexport interface SkeletonConfig {\n  config: IPublicTypeNpmInfo;\n  props?: Record<string, unknown>;\n  handler?: (config: EditorConfig) => EditorConfig;\n}\n\nexport interface FusionTheme {\n  package: string;\n  version: string;\n}\n\nexport interface ThemeConfig {\n  fusion?: FusionTheme;\n}\n\nexport interface PluginsConfig {\n  [key: string]: PluginConfig[];\n}\n\nexport interface PluginConfig {\n  pluginKey: string;\n  type: string;\n  props: {\n    icon?: string;\n    title?: string;\n    width?: number;\n    height?: number;\n    visible?: boolean;\n    disabled?: boolean;\n    marked?: boolean;\n    align?: 'left' | 'right' | 'top' | 'bottom';\n    onClick?: () => void;\n    dialogProps?: Record<string, unknown>;\n    balloonProps?: Record<string, unknown>;\n    panelProps?: Record<string, unknown>;\n    linkProps?: Record<string, unknown>;\n  };\n  config?: IPublicTypeNpmInfo;\n  pluginProps?: Record<string, unknown>;\n}\n\nexport type HooksConfig = HookConfig[];\n\nexport interface HookConfig {\n  message: string;\n  type: 'on' | 'once';\n  handler: (this: IPublicModelEditor, editor: IPublicModelEditor, ...args: any[]) => void;\n}\n\nexport type ShortCutsConfig = ShortCutConfig[];\n\nexport interface ShortCutConfig {\n  keyboard: string;\n  handler: (editor: IPublicModelEditor, ev: Event, keymaster: any) => void;\n}\n\nexport type UtilsConfig = UtilConfig[];\n\nexport interface UtilConfig {\n  name: string;\n  type: 'npm' | 'function';\n  content: IPublicTypeNpmInfo | ((...args: []) => any);\n}\n\nexport type ConstantsConfig = Record<string, unknown>;\n\nexport interface LifeCyclesConfig {\n  init?: (editor: IPublicModelEditor) => any;\n  destroy?: (editor: IPublicModelEditor) => any;\n}\n\nexport type LocaleType = 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP';\n\nexport interface I18nMessages {\n  [key: string]: string;\n}\n\nexport interface I18nConfig {\n  'zh-CN'?: I18nMessages;\n  'zh-TW'?: I18nMessages;\n  'en-US'?: I18nMessages;\n  'ja-JP'?: I18nMessages;\n}\n\nexport type I18nFunction = (key: string, params: any) => string;\n\nexport interface Utils {\n  [key: string]: (...args: any[]) => any;\n}\n\nexport interface PluginProps {\n  editor?: IPublicModelEditor;\n  config: PluginConfig;\n  [key: string]: any;\n}\n\nexport type Plugin = ReactNode & {\n  open?: () => boolean | undefined | Promise<any>;\n  close?: () => boolean | undefined | Promise<any>;\n};\n\nexport type HOCPlugin = ReactNode & {\n  open: () => Promise<any>;\n  close: () => Promise<any>;\n};\n\nexport interface PluginSet {\n  [key: string]: HOCPlugin;\n}\n\nexport type PluginClass = ComponentType<PluginProps> & {\n  init?: (editor: IPublicModelEditor) => void;\n  defaultProps?: {\n    locale?: LocaleType;\n    messages?: I18nMessages;\n  };\n};\n\nexport interface PluginClassSet {\n  [key: string]: PluginClass;\n}\n\nexport interface PluginStatus {\n  disabled?: boolean;\n  visible?: boolean;\n  marked?: boolean;\n  locked?: boolean;\n}\n\nexport interface PluginStatusSet {\n  [key: string]: PluginStatus;\n}"
  },
  {
    "path": "packages/types/src/event/index.ts",
    "content": "import * as Node from './node';\n\nexport interface EventConfig {\n  [Node.Prop.Change]: (options: Node.Prop.ChangeOptions) => any;\n  [Node.Prop.InnerChange]: (options: Node.Prop.ChangeOptions) => any;\n  [Node.Rerender]: (options: Node.RerenderOptions) => void;\n  [eventName: string]: any;\n}\n\nexport * as Node from './node';"
  },
  {
    "path": "packages/types/src/event/node.ts",
    "content": "export * as Prop from './prop';\n\nexport interface RerenderOptions {\n  time: number;\n  componentName?: string;\n  type?: string;\n  nodeCount?: number;\n}\n\nexport const Rerender = 'node.edit.rerender.time';\n"
  },
  {
    "path": "packages/types/src/event/prop.ts",
    "content": "export interface ChangeOptions {\n  key?: string | number;\n  prop?: any;\n  node: Node;\n  newValue: any;\n  oldValue: any;\n}\n\n/**\n * Node Prop 变化事件\n * @Deprecated Please Replace With InnerPropChange\n */\nexport const Change = 'node.prop.change';\n\n/** Node Prop 变化事件 */\nexport const InnerChange = 'node.innerProp.change';"
  },
  {
    "path": "packages/types/src/index.ts",
    "content": "export * from '@alilc/lowcode-datasource-types';\nexport * from './editor';\nexport * from './activity';\nexport * from './code-intermediate';\nexport * from './code-result';\nexport * from './assets';\nexport * as GlobalEvent from './event';\nexport * from './shell';\nexport * from './shell-model-factory';\n// TODO: remove this in future versions\nexport * from './deprecated';\n"
  },
  {
    "path": "packages/types/src/shell/api/canvas.ts",
    "content": "import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model';\nimport { IPublicTypeLocationData, IPublicTypeScrollable } from '../type';\n\n/**\n * canvas - 画布 API\n * @since v1.1.0\n */\nexport interface IPublicApiCanvas {\n\n  /**\n   * 创一个滚动控制器 Scroller，赋予一个视图滚动的基本能力，\n   *\n   * a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling\n   * to some cordination by api scrollTo.\n   *\n   * when a scroller is inited, will need to pass is a scrollable, which has a scrollTarget.\n   * and when scrollTo(options: { left?: number; top?: number }) is called, scroller will\n   * move scrollTarget`s top-left corner to (options.left, options.top) that passed in.\n   * @since v1.1.0\n   */\n  createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller;\n\n  /**\n   * 创建一个 ScrollTarget，与 Scroller 一起发挥作用，详见 createScroller 中的描述\n   *\n   * this works with Scroller, refer to createScroller`s description\n   * @since v1.1.0\n   */\n  createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget;\n\n  /**\n   * 创建一个文档插入位置对象，该对象用来描述一个即将插入的节点在文档中的位置\n   *\n   * create a drop location for document, drop location describes a location in document\n   * @since v1.1.0\n   */\n  createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation;\n\n  /**\n   * 获取拖拽操作对象的实例\n   *\n   * get dragon instance, you can use this to obtain draging related abilities and lifecycle hooks\n   * @since v1.1.0\n   */\n  get dragon(): IPublicModelDragon | null;\n\n  /**\n   * 获取活动追踪器实例\n   *\n   * get activeTracker instance, which is a singleton running in engine.\n   * it tracks document`s current focusing node/node[], and notify it`s subscribers that when\n   * focusing node/node[] changed.\n   * @since v1.1.0\n   */\n  get activeTracker(): IPublicModelActiveTracker | null;\n\n  /**\n   * 是否处于 LiveEditing 状态\n   *\n   * check if canvas is in liveEditing state\n   * @since v1.1.0\n   */\n  get isInLiveEditing(): boolean;\n\n  /**\n   * 获取全局剪贴板实例\n   *\n   * get clipboard instance\n   *\n   * @since v1.1.0\n   */\n  get clipboard(): IPublicModelClipboard;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/command.ts",
    "content": "import { IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '../type';\n\nexport interface IPublicApiCommand {\n\n  /**\n   * 注册一个新命令及其处理函数\n   */\n  registerCommand(command: IPublicTypeCommand): void;\n\n  /**\n   * 注销一个已存在的命令\n   */\n  unregisterCommand(name: string): void;\n\n  /**\n   * 通过名称和给定参数执行一个命令，会校验参数是否符合命令定义\n   */\n  executeCommand(name: string, args?: IPublicTypeCommandHandlerArgs): void;\n\n  /**\n   * 批量执行命令，执行完所有命令后再进行一次重绘，历史记录中只会记录一次\n   */\n  batchExecuteCommand(commands: { name: string; args?: IPublicTypeCommandHandlerArgs }[]): void;\n\n  /**\n   * 列出所有已注册的命令\n   */\n  listCommands(): IPublicTypeListCommand[];\n\n  /**\n   * 注册错误处理回调函数\n   */\n  onCommandError(callback: (name: string, error: Error) => void): void;\n}"
  },
  {
    "path": "packages/types/src/shell/api/common.ts",
    "content": "\nimport { Component, ReactNode } from 'react';\nimport { IPublicTypeI18nData, IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type';\nimport { IPublicEnumTransitionType } from '../enum';\n\nexport interface IPublicApiCommonUtils {\n\n  /**\n   * 是否为合法的 schema 结构\n   * check if data is valid NodeSchema\n   *\n   * @param {*} data\n   * @returns {boolean}\n   */\n  isNodeSchema(data: any): boolean;\n\n  /**\n   * 是否为表单事件类型\n   * check if e is a form event\n   * @param {(KeyboardEvent | MouseEvent)} e\n   * @returns {boolean}\n   */\n  isFormEvent(e: KeyboardEvent | MouseEvent): boolean;\n\n  /**\n   * 从 schema 结构中查找指定 id 节点\n   * get node schema from a larger schema with node id\n   * @param {IPublicTypeNodeSchema} schema\n   * @param {string} nodeId\n   * @returns {(IPublicTypeNodeSchema | undefined)}\n   */\n  getNodeSchemaById(\n      schema: IPublicTypeNodeSchema,\n      nodeId: string,\n    ): IPublicTypeNodeSchema | undefined;\n\n  // TODO: add comments\n  getConvertedExtraKey(key: string): string;\n\n  // TODO: add comments\n  getOriginalExtraKey(key: string): string;\n\n  /**\n   * 批处理事务，用于优化特定场景的性能\n   * excute something in a transaction for performence\n   *\n   * @param {() => void} fn\n   * @param {IPublicEnumTransitionType} type\n   * @since v1.0.16\n   */\n  executeTransaction(fn: () => void, type: IPublicEnumTransitionType): void;\n\n  /**\n   * i18n 相关工具\n   * i18n tools\n   *\n   * @param {(string | object)} instance\n   * @returns {{\n   *     intlNode(id: string, params?: object): ReactNode;\n   *     intl(id: string, params?: object): string;\n   *     getLocale(): string;\n   *     setLocale(locale: string): void;\n   *   }}\n   * @since v1.0.17\n   */\n  createIntl(instance: string | object): {\n    intlNode(id: string, params?: object): ReactNode;\n    intl(id: string, params?: object): string;\n    getLocale(): string;\n    setLocale(locale: string): void;\n  };\n\n  /**\n   * i18n 转换方法\n   */\n  intl(data: IPublicTypeI18nData | string, params?: object): string;\n}\nexport interface IPublicApiCommonSkeletonCabin {\n\n  /**\n   * 编辑器框架 View\n   * get Workbench Component\n   */\n  get Workbench(): Component;\n}\n\nexport interface IPublicApiCommonEditorCabin {\n\n  /**\n   * Title 组件\n   * @experimental unstable API, pay extra caution when trying to use this\n   */\n  get Tip(): React.ComponentClass<{}>;\n\n  /**\n   * Tip 组件\n   * @experimental unstable API, pay extra caution when trying to use this\n   */\n  get Title(): React.ComponentClass<{\n    title: IPublicTypeTitleContent | undefined;\n    match?: boolean;\n    keywords?: string | null;\n  }>;\n}\n\nexport interface IPublicApiCommonDesignerCabin {\n}\n\nexport interface IPublicApiCommon {\n\n  get utils(): IPublicApiCommonUtils;\n\n  /**\n   * @deprecated\n   */\n  get designerCabin(): IPublicApiCommonDesignerCabin;\n\n  /**\n   * @experimental unstable API, pay extra caution when trying to use this\n   */\n  get editorCabin(): IPublicApiCommonEditorCabin;\n\n  get skeletonCabin(): IPublicApiCommonSkeletonCabin;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/commonUI.ts",
    "content": "import React, { ReactElement } from 'react';\nimport { IPublicTypeContextMenuAction, IPublicTypeHelpTipConfig, IPublicTypeTipConfig, IPublicTypeTitleContent } from '../type';\nimport { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next';\nimport { IconProps } from '@alifd/next/types/icon';\n\nexport interface IPublicApiCommonUI {\n  Balloon: typeof Balloon;\n  Breadcrumb: typeof Breadcrumb;\n  Button: typeof Button;\n  Card: typeof Card;\n  Checkbox: typeof Checkbox;\n  DatePicker: typeof DatePicker;\n  Dialog: typeof Dialog;\n  Dropdown: typeof Dropdown;\n  Form: typeof Form;\n  Icon: typeof Icon;\n  Input: typeof Input;\n  Loading: typeof Loading;\n  Message: typeof Message;\n  Overlay: typeof Overlay;\n  Pagination: typeof Pagination;\n  Radio: typeof Radio;\n  Search: typeof Search;\n  Select: typeof Select;\n  SplitButton: typeof SplitButton;\n  Step: typeof Step;\n  Switch: typeof Switch;\n  Tab: typeof Tab;\n  Table: typeof Table;\n  Tree: typeof Tree;\n  TreeSelect: typeof TreeSelect;\n  Upload: typeof Upload;\n  Divider: typeof Divider;\n\n  /**\n   * Title 组件\n   */\n  get Tip(): React.ComponentClass<IPublicTypeTipConfig>;\n\n  /**\n   * HelpTip 组件\n   */\n  get HelpTip(): React.VFC<{\n    help: IPublicTypeHelpTipConfig;\n\n    /**\n     * 方向\n     * @default 'top'\n     */\n    direction: IPublicTypeTipConfig['direction'];\n\n    /**\n     * 大小\n     * @default 'small'\n     */\n    size: IconProps['size'];\n  }>;\n\n  /**\n   * Tip 组件\n   */\n  get Title(): React.ComponentClass<{\n    title: IPublicTypeTitleContent | undefined;\n    match?: boolean;\n    keywords?: string | null;\n  }>;\n\n  get ContextMenu(): ((props: {\n    menus: IPublicTypeContextMenuAction[];\n    children: React.ReactElement[] | React.ReactElement;\n  }) => ReactElement) & {\n    create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void;\n  };\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/event.ts",
    "content": "import { IPublicTypeDisposable } from '../type';\n\nexport interface IPublicApiEvent {\n\n  /**\n   * 监听事件\n   * add monitor to a event\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  on(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;\n\n  /**\n   * 监听事件，会在其他回调函数之前执行\n   * add monitor to a event\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  prependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;\n\n  /**\n   * 取消监听事件\n   * cancel a monitor from a event\n   * @param event 事件名称\n   * @param listener 事件回调\n   */\n  off(event: string, listener: (...args: any[]) => void): void;\n\n  /**\n   * 触发事件\n   * emit a message for a event\n   * @param event 事件名称\n   * @param args 事件参数\n   * @returns\n   */\n  emit(event: string, ...args: any[]): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/hotkey.ts",
    "content": "import { IPublicTypeDisposable, IPublicTypeHotkeyCallback, IPublicTypeHotkeyCallbacks } from '../type';\n\nexport interface IPublicApiHotkey {\n\n  /**\n   * 获取当前快捷键配置\n   *\n   * @experimental\n   * @since v1.1.0\n   */\n  get callbacks(): IPublicTypeHotkeyCallbacks;\n\n  /**\n   * 绑定快捷键\n   * bind hotkey/hotkeys,\n   * @param combos 快捷键，格式如：['command + s'] 、['ctrl + shift + s'] 等\n   * @param callback 回调函数\n   * @param action\n   */\n  bind(\n      combos: string[] | string,\n      callback: IPublicTypeHotkeyCallback,\n      action?: string,\n    ): IPublicTypeDisposable;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/index.ts",
    "content": "export * from './common';\nexport * from './event';\nexport * from './hotkey';\nexport * from './material';\nexport * from './project';\nexport * from './setters';\nexport * from './simulator-host';\nexport * from './skeleton';\nexport * from './plugins';\nexport * from './logger';\nexport * from './canvas';\nexport * from './workspace';\nexport * from './commonUI';\nexport * from './command';"
  },
  {
    "path": "packages/types/src/shell/api/logger.ts",
    "content": "export type LoggerLevel = 'debug' | 'log' | 'info' | 'warn' | 'error';\nexport interface ILoggerOptions {\n  level?: LoggerLevel;\n  bizName?: string;\n}\n\nexport interface IPublicApiLogger {\n\n  /**\n   * debug info\n   */\n  debug(...args: any | any[]): void;\n\n  /**\n   * normal info output\n   */\n  info(...args: any | any[]): void;\n\n  /**\n   * warning info output\n   */\n  warn(...args: any | any[]): void;\n\n  /**\n   * error info output\n   */\n  error(...args: any | any[]): void;\n\n  /**\n   * log info output\n   */\n  log(...args: any | any[]): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/material.ts",
    "content": "import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '../type';\nimport { IPublicModelComponentMeta } from '../model';\nimport { ComponentType } from 'react';\n\nexport interface IPublicApiMaterial {\n\n  /**\n   * 获取组件 map 结构\n   * get map of components\n   */\n  get componentsMap(): { [key: string]: IPublicTypeNpmInfo | ComponentType<any> | object } ;\n\n  /**\n   * 设置「资产包」结构\n   * set data for Assets\n   * @returns void\n   */\n  setAssets(assets: IPublicTypeAssetsJson): Promise<void>;\n\n  /**\n   * 获取「资产包」结构\n   * get AssetsJson data\n   * @returns IPublicTypeAssetsJson\n   */\n  getAssets(): IPublicTypeAssetsJson | undefined;\n\n  /**\n   * 加载增量的「资产包」结构，该增量包会与原有的合并\n   * load Assets incrementally, and will merge this with exiting assets\n   * @param incrementalAssets\n   * @returns\n   */\n  loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): void;\n\n  /**\n   * 注册物料元数据管道函数，在物料信息初始化时执行。\n   * register transducer to process component meta, which will be\n   * excuted during component meta`s initialization\n   * @param transducer\n   * @param level\n   * @param id\n   */\n  registerMetadataTransducer(\n    transducer: IPublicTypeMetadataTransducer,\n    level?: number,\n    id?: string | undefined\n  ): void;\n\n  /**\n   * 获取所有物料元数据管道函数\n   * get all registered metadata transducers\n   * @returns {IPublicTypeMetadataTransducer[]}\n   */\n  getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[];\n\n  /**\n   * 获取指定名称的物料元数据\n   * get component meta by component name\n   * @param componentName\n   * @returns\n   */\n  getComponentMeta(componentName: string): IPublicModelComponentMeta | null;\n\n  /**\n   * test if the given object is a ComponentMeta instance or not\n   * @param obj\n   * @experiemental unstable API, pay extra caution when trying to use it\n   */\n  isComponentMeta(obj: any): boolean;\n\n  /**\n   * 获取所有已注册的物料元数据\n   * get map of all component metas\n   */\n  getComponentMetasMap(): Map<string, IPublicModelComponentMeta>;\n\n  /**\n   * 在设计器辅助层增加一个扩展 action\n   *\n   * add an action button in canvas context menu area\n   * @param action\n   * @example\n   * ```ts\n   * import { plugins } from '@alilc/lowcode-engine';\n   * import { IPublicModelPluginContext } from '@alilc/lowcode-types';\n   *\n   * const removeCopyAction = (ctx: IPublicModelPluginContext) => {\n   *   return {\n   *     async init() {\n   *       const { removeBuiltinComponentAction } = ctx.material;\n   *       removeBuiltinComponentAction('copy');\n   *     }\n   *   }\n   * };\n   * removeCopyAction.pluginName = 'removeCopyAction';\n   * await plugins.register(removeCopyAction);\n   * ```\n   */\n  addBuiltinComponentAction(action: IPublicTypeComponentAction): void;\n\n  /**\n   * 移除设计器辅助层的指定 action\n   * remove a builtin action button from canvas context menu area\n   * @param name\n   */\n  removeBuiltinComponentAction(name: string): void;\n\n  /**\n   * 修改已有的设计器辅助层的指定 action\n   * modify a builtin action button in canvas context menu area\n   * @param actionName\n   * @param handle\n   */\n  modifyBuiltinComponentAction(\n      actionName: string,\n      handle: (action: IPublicTypeComponentAction) => void,\n    ): void;\n\n  /**\n   * 监听 assets 变化的事件\n   * add callback for assets changed event\n   * @param fn\n   */\n  onChangeAssets(fn: () => void): IPublicTypeDisposable;\n\n  /**\n   * 刷新 componentMetasMap，可触发模拟器里的 components 重新构建\n   * @since v1.1.7\n   */\n  refreshComponentMetasMap(): void;\n\n  /**\n   * 添加右键菜单项\n   * @param action\n   */\n  addContextMenuOption(action: IPublicTypeContextMenuAction): void;\n\n  /**\n   * 删除特定右键菜单项\n   * @param name\n   */\n  removeContextMenuOption(name: string): void;\n\n  /**\n   * 调整右键菜单项布局\n   * @param actions\n   */\n  adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/plugins.ts",
    "content": "import { IPublicModelPluginInstance, IPublicTypePlugin } from '../model';\nimport { IPublicTypePreferenceValueType } from '../type';\nimport { IPublicTypePluginRegisterOptions } from '../type/plugin-register-options';\n\nexport interface IPluginPreferenceMananger {\n  // eslint-disable-next-line max-len\n  getPreferenceValue: (\n    key: string,\n    defaultValue?: IPublicTypePreferenceValueType,\n  ) => IPublicTypePreferenceValueType | undefined;\n}\n\nexport type PluginOptionsType = string | number | boolean | object;\n\nexport interface IPublicApiPlugins {\n  /**\n   * 可以通过 plugin api 获取其他插件 export 导出的内容\n   */\n  [key: string]: any;\n\n  register(\n    pluginModel: IPublicTypePlugin,\n    options?: Record<string, PluginOptionsType>,\n    registerOptions?: IPublicTypePluginRegisterOptions,\n  ): Promise<void>;\n\n  /**\n   * 引擎初始化时可以提供全局配置给到各插件，通过这个方法可以获得本插件对应的配置\n   *\n   * use this to get preference config for this plugin when engine.init() called\n   */\n  getPluginPreference(\n      pluginName: string,\n    ): Record<string, IPublicTypePreferenceValueType> | null | undefined;\n\n  /**\n   * 获取指定插件\n   *\n   * get plugin instance by name\n   */\n  get(pluginName: string): IPublicModelPluginInstance | null;\n\n  /**\n   * 获取所有的插件实例\n   *\n   * get all plugin instances\n   */\n  getAll(): IPublicModelPluginInstance[];\n\n  /**\n   * 判断是否有指定插件\n   *\n   * check if plugin with certain name exists\n   */\n  has(pluginName: string): boolean;\n\n  /**\n   * 删除指定插件\n   *\n   * delete plugin instance by name\n   */\n  delete(pluginName: string): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/project.ts",
    "content": "import { IPublicTypeProjectSchema, IPublicTypeDisposable, IPublicTypeRootSchema, IPublicTypePropsTransducer, IPublicTypeAppConfig } from '../type';\nimport { IPublicEnumTransformStage } from '../enum';\nimport { IPublicApiSimulatorHost } from './';\nimport { IPublicModelDocumentModel } from '../model';\n\nexport interface IBaseApiProject<\n  DocumentModel\n> {\n\n  /**\n   * 获取当前的 document\n   * get current document\n   */\n  get currentDocument(): DocumentModel | null;\n\n  /**\n   * 获取当前 project 下所有 documents\n   * get all documents of this project\n   * @returns\n   */\n  get documents(): DocumentModel[];\n\n  /**\n   * 获取模拟器的 host\n   * get simulator host\n   */\n  get simulatorHost(): IPublicApiSimulatorHost | null;\n\n  /**\n   * 打开一个 document\n   * open a document\n   * @param doc\n   * @returns\n   */\n  openDocument(doc?: string | IPublicTypeRootSchema | undefined): DocumentModel | null;\n\n  /**\n   * 创建一个 document\n   * create a document\n   * @param data\n   * @returns\n   */\n  createDocument(data?: IPublicTypeRootSchema): DocumentModel | null;\n\n  /**\n   * 删除一个 document\n   * remove a document\n   * @param doc\n   */\n  removeDocument(doc: DocumentModel): void;\n\n  /**\n   * 根据 fileName 获取 document\n   * get a document by filename\n   * @param fileName\n   * @returns\n   */\n  getDocumentByFileName(fileName: string): DocumentModel | null;\n\n  /**\n   * 根据 id 获取 document\n   * get a document by id\n   * @param id\n   * @returns\n   */\n  getDocumentById(id: string): DocumentModel | null;\n\n  /**\n   * 导出 project\n   * export project to schema\n   * @returns\n   */\n  exportSchema(stage: IPublicEnumTransformStage): IPublicTypeProjectSchema;\n\n  /**\n   * 导入 project schema\n   * import schema to project\n   * @param schema 待导入的 project 数据\n   */\n  importSchema(schema?: IPublicTypeProjectSchema): void;\n\n  /**\n   * 获取当前的 document\n   * get current document\n   * @returns\n   */\n  getCurrentDocument(): DocumentModel | null;\n\n  /**\n   * 增加一个属性的管道处理函数\n   * add a transducer to process prop\n   * @param transducer\n   * @param stage\n   */\n  addPropsTransducer(\n      transducer: IPublicTypePropsTransducer,\n      stage: IPublicEnumTransformStage,\n    ): void;\n\n  /**\n   * 绑定删除文档事件\n   * set callback for event onDocumentRemoved\n   * @param fn\n   * @since v1.0.16\n   */\n  onRemoveDocument(fn: (data: { id: string }) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 project 内的 document 变更事件\n   * set callback for event onDocumentChanged\n   */\n  onChangeDocument(fn: (doc: DocumentModel) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 project 的模拟器 ready 事件\n   * set callback for event onSimulatorHostReady\n   */\n  onSimulatorHostReady(fn: (host: IPublicApiSimulatorHost) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 project 的渲染器 ready 事件\n   * set callback for event onSimulatorRendererReady\n   */\n  onSimulatorRendererReady(fn: () => void): IPublicTypeDisposable;\n\n  /**\n   * 设置多语言语料\n   * 数据格式参考 https://github.com/alibaba/lowcode-engine/blob/main/specs/lowcode-spec.md#2434%E5%9B%BD%E9%99%85%E5%8C%96%E5%A4%9A%E8%AF%AD%E8%A8%80%E7%B1%BB%E5%9E%8Baa\n   *\n   * set I18n data for this project\n   * @param value object\n   * @since v1.0.17\n   */\n  setI18n(value: object): void;\n\n  /**\n   * 设置当前项目配置\n   *\n   * set config data for this project\n   * @param value object\n   * @since v1.1.4\n   */\n  setConfig<T extends keyof IPublicTypeAppConfig>(key: T, value: IPublicTypeAppConfig[T]): void;\n  setConfig(value: IPublicTypeAppConfig): void;\n}\n\nexport interface IPublicApiProject extends IBaseApiProject<IPublicModelDocumentModel> {}\n"
  },
  {
    "path": "packages/types/src/shell/api/setters.ts",
    "content": "import { ReactNode } from 'react';\n\nimport { IPublicTypeRegisteredSetter, IPublicTypeCustomView } from '../type';\n\nexport interface IPublicApiSetters {\n\n  /**\n   * 获取指定 setter\n   * get setter by type\n   * @param type\n   * @returns\n   */\n  getSetter(type: string): IPublicTypeRegisteredSetter | null;\n\n  /**\n   * 获取已注册的所有 settersMap\n   * get map of all registered setters\n   * @returns\n   */\n  getSettersMap(): Map<string, IPublicTypeRegisteredSetter & {\n    type: string;\n  }>;\n\n  /**\n   * 注册一个 setter\n   * register a setter\n   * @param typeOrMaps\n   * @param setter\n   * @returns\n   */\n  registerSetter(\n    typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter },\n    setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter | undefined\n  ): void;\n\n  /**\n   * @deprecated\n   */\n  createSetterContent (setter: any, props: Record<string, any>): ReactNode;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/simulator-host.ts",
    "content": "import { IPublicModelNode, IPublicModelSimulatorRender } from '../model';\n\nexport interface IPublicApiSimulatorHost {\n\n  /**\n   * 获取 contentWindow\n   * @experimental unstable api, pay extra caution when trying to use it\n   */\n  get contentWindow(): Window | undefined;\n\n  /**\n   * 获取 contentDocument\n   * @experimental unstable api, pay extra caution when trying to use it\n   */\n  get contentDocument(): Document | undefined;\n\n  /**\n   * @experimental unstable api, pay extra caution when trying to use it\n   */\n  get renderer(): IPublicModelSimulatorRender | undefined;\n\n  /**\n   * 设置若干用于画布渲染的变量，比如画布大小、locale 等。\n   * set config for simulator host, eg. device locale and so on.\n   * @param key\n   * @param value\n   */\n  set(key: string, value: any): void;\n\n  /**\n   * 获取模拟器中设置的变量，比如画布大小、locale 等。\n   * set config value by key\n   * @param key\n   * @returns\n   */\n  get(key: string): any;\n\n  /**\n   * 滚动到指定节点\n   * scroll to specific node\n   * @param node\n   * @since v1.1.0\n   */\n  scrollToNode(node: IPublicModelNode): void;\n\n  /**\n   * 刷新渲染画布\n   * make simulator render again\n   */\n  rerender(): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/skeleton.ts",
    "content": "import { IPublicModelSkeletonItem } from '../model';\nimport { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '../type';\n\nexport interface IPublicApiSkeleton {\n\n  /**\n   * 增加一个面板实例\n   * add a new panel\n   * @param config\n   * @param extraConfig\n   * @returns\n   */\n  add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IPublicModelSkeletonItem | undefined;\n\n  /**\n   * 移除一个面板实例\n   * remove a panel\n   * @param config\n   * @returns\n   */\n  remove(config: IPublicTypeSkeletonConfig): number | undefined;\n\n  /**\n   * 获取某个区域下的所有面板实例\n   * @param areaName IPublicTypeWidgetConfigArea\n   */\n  getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] | undefined;\n\n  /**\n   * 获取面板实例\n   * @param name 面板名称\n   * @since v1.1.10\n   */\n  getPanel(name: string): IPublicModelSkeletonItem | undefined;\n\n  /**\n   * 展示指定 Panel 实例\n   * show panel by name\n   * @param name\n   */\n  showPanel(name: string): void;\n\n  /**\n   * 隐藏面板\n   * hide panel by name\n   * @param name\n   */\n  hidePanel(name: string): void;\n\n  /**\n   * 展示指定 Widget 实例\n   * show widget by name\n   * @param name\n   */\n  showWidget(name: string): void;\n\n  /**\n   * 将 widget 启用\n   * enable widget by name\n   * @param name\n   */\n  enableWidget(name: string): void;\n\n  /**\n   * 隐藏指定 widget 实例\n   * hide widget by name\n   * @param name\n   */\n  hideWidget(name: string): void;\n\n  /**\n   * 将 widget 禁用掉，禁用后，所有鼠标事件都会被禁止掉。\n   * disable widget，and make it not responding any click event.\n   * @param name\n   */\n  disableWidget(name: string): void;\n\n  /**\n   * 显示某个 Area\n   * show area\n   * @param areaName name of area\n   */\n  showArea(areaName: string): void;\n\n  /**\n   * 隐藏某个 Area\n   * hide area\n   * @param areaName name of area\n   */\n  hideArea(areaName: string): void;\n\n  /**\n   * 监听 Panel 实例显示事件\n   * set callback for panel shown event\n   * @param listener\n   * @returns\n   */\n  onShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n\n  /**\n   * 监听 Panel 实例隐藏事件\n   * set callback for panel hidden event\n   * @param listener\n   * @returns\n   */\n  onHidePanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n\n  /**\n   * 监听 Widget 实例 Disable 事件\n   * @param listener\n   */\n  onDisableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n\n  /**\n   * 监听 Widget 实例 Enable 事件\n   * @param listener\n   */\n  onEnableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n\n  /**\n   * 监听 Widget 显示事件\n   * set callback for widget shown event\n   * @param listener\n   * @returns\n   */\n  onShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n\n  /**\n   * 监听 Widget 隐藏事件\n   * set callback for widget hidden event\n   * @param listener\n   * @returns\n   */\n  onHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;\n\n  /**\n   * 注册一个面板的配置转换器（transducer）。\n   * Registers a configuration transducer for a panel.\n   * @param {IPublicTypeConfigTransducer} transducer\n   *   - 要注册的转换器函数。该函数接受一个配置对象（类型为 IPublicTypeSkeletonConfig）作为输入，并返回修改后的配置对象。\n   *   - The transducer function to be registered. This function takes a configuration object (of type IPublicTypeSkeletonConfig) as input and returns a modified configuration object.\n   *\n   * @param {number} level\n   *   - 转换器的优先级。优先级较高的转换器会先执行。\n   *   - The priority level of the transducer. Transducers with higher priority levels are executed first.\n   *\n   * @param {string} [id]\n   *   - （可选）转换器的唯一标识符。用于在需要时引用或操作特定的转换器。\n   *   - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed.\n   */\n  registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/api/workspace.ts",
    "content": "import { IPublicModelWindow } from '../model';\nimport { IPublicApiPlugins, IPublicApiSkeleton, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';\n\nexport interface IPublicApiWorkspace<\n  Plugins = IPublicApiPlugins,\n  Skeleton = IPublicApiSkeleton,\n  ModelWindow = IPublicModelWindow,\n  Resource = IPublicModelResource,\n> {\n\n  /** 是否启用 workspace 模式 */\n  isActive: boolean;\n\n  /** 当前设计器窗口 */\n  window: ModelWindow | null;\n\n  plugins: Plugins;\n\n  skeleton: Skeleton;\n\n  /** 当前设计器的编辑窗口 */\n  windows: ModelWindow[];\n\n  /** 获取资源树列表 */\n  get resourceList(): IPublicModelResource[];\n\n  /** 设置资源树列表 */\n  setResourceList(resourceList: IPublicResourceList): void;\n\n  /** 资源树列表更新事件 */\n  onResourceListChange(fn: (resourceList: IPublicResourceList) => void): IPublicTypeDisposable;\n\n  /** 注册资源 */\n  registerResourceType(resourceTypeModel: IPublicTypeResourceType): void;\n\n  /**\n   * 打开视图窗口\n   * @deprecated\n   */\n  openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>;\n\n  /** 打开视图窗口 */\n  openEditorWindow(resource: Resource, sleep?: boolean): Promise<void>;\n\n  /** 通过视图 id 打开窗口 */\n  openEditorWindowById(id: string): void;\n\n  /**\n   * 移除视图窗口\n   * @deprecated\n   */\n  removeEditorWindow(resourceName: string, id: string): void;\n\n  /**\n   * 移除视图窗口\n   */\n  removeEditorWindow(resource: Resource): void;\n\n  /** 通过视图 id 移除窗口 */\n  removeEditorWindowById(id: string): void;\n\n  /** 窗口新增/删除的事件 */\n  onChangeWindows(fn: () => void): IPublicTypeDisposable;\n\n  /** active 窗口变更事件 */\n  onChangeActiveWindow(fn: () => void): IPublicTypeDisposable;\n\n  /**\n   * active 视图变更事件\n   * @since v1.1.7\n   */\n  onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable;\n\n  /**\n   * window 下的所有视图 renderer ready 事件\n   * @since v1.1.7\n   */\n  onWindowRendererReady(fn: () => void): IPublicTypeDisposable;\n}"
  },
  {
    "path": "packages/types/src/shell/enum/context-menu.ts",
    "content": "export enum IPublicEnumContextMenuType {\n  SEPARATOR = 'separator',\n  // 'menuItem'\n  MENU_ITEM = 'menuItem',\n  // 'nodeTree'\n  NODE_TREE = 'nodeTree',\n}"
  },
  {
    "path": "packages/types/src/shell/enum/drag-object-type.ts",
    "content": "// eslint-disable-next-line no-shadow\nexport enum IPublicEnumDragObjectType {\n  // eslint-disable-next-line no-shadow\n  Node = 'node',\n  NodeData = 'nodedata',\n}\n\n/**\n * @deprecated use IPublicEnumDragObjectType instead\n */\nexport enum DragObjectType {\n  Node = IPublicEnumDragObjectType.Node,\n  NodeData = IPublicEnumDragObjectType.NodeData,\n}\n"
  },
  {
    "path": "packages/types/src/shell/enum/event-names.ts",
    "content": "/**\n * 所有公开可用的事件名定义\n * All public event names\n * names should be like 'namespace.modelName.whatHappened'\n *\n */\n// eslint-disable-next-line no-shadow\nexport enum IPublicEnumEventNames {\n}"
  },
  {
    "path": "packages/types/src/shell/enum/index.ts",
    "content": "export * from './event-names';\nexport * from './transition-type';\nexport * from './transform-stage';\nexport * from './drag-object-type';\nexport * from './prop-value-changed-type';\nexport * from './plugin-register-level';\nexport * from './context-menu';"
  },
  {
    "path": "packages/types/src/shell/enum/plugin-register-level.ts",
    "content": "export enum IPublicEnumPluginRegisterLevel {\n  Default = 'default',\n  Workspace = 'workspace',\n  Resource = 'resource',\n  EditorView = 'editorView',\n}"
  },
  {
    "path": "packages/types/src/shell/enum/prop-value-changed-type.ts",
    "content": "// eslint-disable-next-line no-shadow\nexport enum IPublicEnumPropValueChangedType {\n  /**\n   * normal set value\n   */\n  SET_VALUE = 'SET_VALUE',\n  /**\n   * value changed caused by sub-prop value change\n   */\n  SUB_VALUE_CHANGE = 'SUB_VALUE_CHANGE'\n}\n\n/**\n * @deprecated please use IPublicEnumPropValueChangedType\n */\nexport enum PROP_VALUE_CHANGED_TYPE {\n  /**\n   * normal set value\n   */\n  SET_VALUE = 'SET_VALUE',\n  /**\n   * value changed caused by sub-prop value change\n   */\n  SUB_VALUE_CHANGE = 'SUB_VALUE_CHANGE'\n}\n"
  },
  {
    "path": "packages/types/src/shell/enum/transform-stage.ts",
    "content": "export enum IPublicEnumTransformStage {\n  Render = 'render',\n  Serilize = 'serilize',\n  Save = 'save',\n  Clone = 'clone',\n  Init = 'init',\n  Upgrade = 'upgrade',\n}\n/**\n * @deprecated use IPublicEnumTransformStage instead\n */\nexport enum TransformStage {\n  Render = 'render',\n  Serilize = 'serilize',\n  Save = 'save',\n  Clone = 'clone',\n  Init = 'init',\n  Upgrade = 'upgrade',\n}\n"
  },
  {
    "path": "packages/types/src/shell/enum/transition-type.ts",
    "content": "// eslint-disable-next-line no-shadow\nexport enum IPublicEnumTransitionType {\n  /** 节点更新后重绘处理 */\n  REPAINT\n}\n\n/**\n * @deprecated use IPublicEnumTransitionType instead\n */\nexport enum TransitionType {\n  /** 节点更新后重绘处理 */\n  REPAINT\n}"
  },
  {
    "path": "packages/types/src/shell/index.ts",
    "content": "\nexport * from './type';\nexport * from './api';\nexport * from './model';\nexport * from './enum';"
  },
  {
    "path": "packages/types/src/shell/model/active-tracker.ts",
    "content": "import { IPublicTypeActiveTarget } from '../type';\nimport { IPublicModelNode } from './node';\n\nexport interface IPublicModelActiveTracker {\n\n  /**\n   * @since 1.1.7\n   */\n  target: IPublicTypeActiveTarget | null;\n\n  onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void;\n\n  track(node: IPublicModelNode): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/clipboard.ts",
    "content": "\nexport interface IPublicModelClipboard {\n\n  /**\n   * 给剪贴板赋值\n   * set data to clipboard\n   *\n   * @param {*} data\n   * @since v1.1.0\n   */\n  setData(data: any): void;\n\n  /**\n   * 设置剪贴板数据设置的回调\n   * set callback for clipboard provide paste data\n   *\n   * @param {KeyboardEvent} keyboardEvent\n   * @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb\n   * @since v1.1.0\n   */\n  waitPasteData(\n      keyboardEvent: KeyboardEvent,\n      cb: (data: any, clipboardEvent: ClipboardEvent) => void,\n    ): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/component-meta.ts",
    "content": "import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeIconType, IPublicTypeTransformedComponentMetadata, IPublicTypeI18nData, IPublicTypeNpmInfo, IPublicTypeAdvanced, IPublicTypeFieldConfig, IPublicTypeComponentAction } from '../type';\nimport { ReactElement } from 'react';\nimport { IPublicModelNode } from './node';\n\nexport interface IPublicModelComponentMeta<\n  Node = IPublicModelNode\n> {\n\n  /**\n   * 组件名\n   * component name\n   */\n  get componentName(): string;\n\n  /**\n   * 是否是「容器型」组件\n   * is container node or not\n   */\n  get isContainer(): boolean;\n\n  /**\n   * 是否是最小渲染单元。\n   * 当组件需要重新渲染时：\n   *  若为最小渲染单元，则只渲染当前组件，\n   *  若不为最小渲染单元，则寻找到上层最近的最小渲染单元进行重新渲染，直至根节点。\n   *\n   * check if this is a mininal render unit.\n   * when a rerender is needed for a component:\n   *  case 'it`s a mininal render unit':  only render itself.\n   *  case 'it`s not a mininal render unit': find a mininal render unit to render in\n   *  its ancesters until root node is reached.\n   */\n  get isMinimalRenderUnit(): boolean;\n\n  /**\n   * 是否为「模态框」组件\n   * check if this is a modal component or not.\n   */\n  get isModal(): boolean;\n\n  /**\n   * 获取用于设置面板显示用的配置\n   * get configs for Settings Panel\n   */\n  get configure(): IPublicTypeFieldConfig[];\n\n  /**\n   * 标题\n   * title for this component\n   */\n  get title(): string | IPublicTypeI18nData | ReactElement;\n\n  /**\n   * 图标\n   * icon config for this component\n   */\n  get icon(): IPublicTypeIconType;\n\n  /**\n   * 组件 npm 信息\n   * npm informations\n   */\n  get npm(): IPublicTypeNpmInfo;\n\n  /**\n   * 当前组件的可用 Action\n   * available actions\n   */\n  get availableActions(): IPublicTypeComponentAction[];\n\n  /**\n   * 组件元数据中高级配置部分\n   * configure.advanced\n   * @since v1.1.0\n   */\n  get advanced(): IPublicTypeAdvanced;\n\n  /**\n   * 设置 npm 信息\n   * set method for npm inforamtion\n   * @param npm\n   */\n  setNpm(npm: IPublicTypeNpmInfo): void;\n\n  /**\n   * 获取元数据\n   * get component metadata\n   */\n  getMetadata(): IPublicTypeTransformedComponentMetadata;\n\n  /**\n   * 检测当前对应节点是否可被放置在父节点中\n   * check if the current node could be placed in parent node\n   * @param my 当前节点\n   * @param parent 父节点\n   */\n  checkNestingUp(my: Node | IPublicTypeNodeData, parent: any): boolean;\n\n  /**\n   * 检测目标节点是否可被放置在父节点中\n   * check if the target node(s) could be placed in current node\n   * @param my 当前节点\n   * @param parent 父节点\n   */\n  checkNestingDown(\n      my: Node | IPublicTypeNodeData,\n      target: IPublicTypeNodeSchema | Node | IPublicTypeNodeSchema[],\n    ): boolean;\n\n  /**\n   * 刷新元数据，会触发元数据的重新解析和刷新\n   * refresh metadata\n   */\n  refreshMetadata(): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/detecting.ts",
    "content": "import { IPublicModelNode } from './';\nimport { IPublicTypeDisposable } from '../type';\n\nexport interface IPublicModelDetecting<Node = IPublicModelNode> {\n\n  /**\n   * 是否启用\n   * check if current detecting is enabled\n   * @since v1.1.0\n   */\n  get enable(): boolean;\n\n  /**\n   * 当前 hover 的节点\n   * get current hovering node\n   * @since v1.0.16\n   */\n  get current(): Node | null;\n\n  /**\n   * hover 指定节点\n   * capture node with nodeId\n   * @param id 节点 id\n   */\n  capture(id: string): void;\n\n  /**\n   * hover 离开指定节点\n   * release node with nodeId\n   * @param id 节点 id\n   */\n  release(id: string): void;\n\n  /**\n   * 清空 hover 态\n   * clear all hover state\n   */\n  leave(): void;\n\n  /**\n   * hover 节点变化事件\n   * set callback which will be called when hovering object changed.\n   * @since v1.1.0\n   */\n  onDetectingChange(fn: (node: Node | null) => void): IPublicTypeDisposable;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/document-model.ts",
    "content": "import { IPublicTypeRootSchema, IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject, IPublicTypePropChangeOptions, IPublicTypeDisposable } from '../type';\nimport { IPublicEnumTransformStage } from '../enum';\nimport { IPublicApiProject } from '../api';\nimport { IPublicModelDropLocation, IPublicModelDetecting, IPublicModelNode, IPublicModelSelection, IPublicModelHistory, IPublicModelModalNodesManager } from './';\nimport { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicTypeOnChangeOptions } from '@alilc/lowcode-types';\n\nexport interface IPublicModelDocumentModel<\n  Selection = IPublicModelSelection,\n  History = IPublicModelHistory,\n  Node = IPublicModelNode,\n  DropLocation = IPublicModelDropLocation,\n  ModalNodesManager = IPublicModelModalNodesManager,\n  Project = IPublicApiProject\n> {\n\n  /**\n     * 节点选中区模型实例\n     * instance of selection\n     */\n  selection: Selection;\n\n  /**\n   * 画布节点 hover 区模型实例\n   * instance of detecting\n   */\n  detecting: IPublicModelDetecting;\n\n  /**\n   * 操作历史模型实例\n   * instance of history\n   */\n  history: History;\n\n  /**\n   * id\n   */\n  get id(): string;\n\n  set id(id);\n\n  /**\n   * 获取当前文档所属的 project\n   * get project which this documentModel belongs to\n   * @returns\n   */\n  get project(): Project;\n\n  /**\n   * 获取文档的根节点\n   * root node of this documentModel\n   * @returns\n   */\n  get root(): Node | null;\n\n  get focusNode(): Node | null;\n\n  set focusNode(node: Node | null);\n\n  /**\n   * 获取文档下所有节点\n   * @returns\n   */\n  get nodesMap(): Map<string, Node>;\n\n  /**\n   * 模态节点管理\n   * get instance of modalNodesManager\n   */\n  get modalNodesManager(): ModalNodesManager | null;\n\n  /**\n   * 根据 nodeId 返回 Node 实例\n   * get node by nodeId\n   * @param nodeId\n   * @returns\n   */\n  getNodeById(nodeId: string): Node | null;\n\n  /**\n   * 导入 schema\n   * import schema data\n   * @param schema\n   */\n  importSchema(schema: IPublicTypeRootSchema): void;\n\n  /**\n   * 导出 schema\n   * export schema\n   * @param stage\n   * @returns\n   */\n  exportSchema(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined;\n\n  /**\n   * 插入节点\n   * insert a node\n   */\n  insertNode(\n    parent: Node,\n    thing: Node | IPublicTypeNodeData,\n    at?: number | null | undefined,\n    copy?: boolean | undefined\n  ): Node | null;\n\n  /**\n   * 创建一个节点\n   * create a node\n   * @param data\n   * @returns\n   */\n  createNode<T = Node>(data: IPublicTypeNodeSchema): T | null;\n\n  /**\n   * 移除指定节点/节点id\n   * remove a node by node instance or nodeId\n   * @param idOrNode\n   */\n  removeNode(idOrNode: string | Node): void;\n\n  /**\n   * componentsMap of documentModel\n   * @param extraComps\n   * @returns\n   */\n  getComponentsMap(extraComps?: string[]): any;\n\n  /**\n   * 检查拖拽放置的目标节点是否可以放置该拖拽对象\n   * check if dragOjbect can be put in this dragTarget\n   * @param dropTarget 拖拽放置的目标节点\n   * @param dragObject 拖拽的对象\n   * @returns boolean 是否可以放置\n   * @since v1.0.16\n   */\n  checkNesting(\n    dropTarget: Node,\n    dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject\n  ): boolean;\n\n  /**\n   * 当前 document 新增节点事件\n   * set callback for event on node is created for a document\n   */\n  onAddNode(fn: (node: Node) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 document 新增节点事件，此时节点已经挂载到 document 上\n   * set callback for event on node is mounted to canvas\n   */\n  onMountNode(fn: (payload: { node: Node }) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 document 删除节点事件\n   * set callback for event on node is removed\n   */\n  onRemoveNode(fn: (node: Node) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 document 的 hover 变更事件\n   *\n   * set callback for event on detecting changed\n   */\n  onChangeDetecting(fn: (node: Node) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 document 的选中变更事件\n   * set callback for event on selection changed\n   */\n  onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 document 的节点显隐状态变更事件\n   * set callback for event on visibility changed for certain node\n   * @param fn\n   */\n  onChangeNodeVisible(fn: (node: Node, visible: boolean) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 document 的节点 children 变更事件\n   * @param fn\n   */\n  onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<Node>) => void): IPublicTypeDisposable;\n\n  /**\n   * 当前 document 节点属性修改事件\n   * @param fn\n   */\n  onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions<Node>) => void): IPublicTypeDisposable;\n\n  /**\n   * import schema event\n   * @param fn\n   * @since v1.0.15\n   */\n  onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable;\n\n  /**\n   * 判断是否当前节点处于被探测状态\n   * check is node being detected\n   * @param node\n   * @since v1.1.0\n   */\n  isDetectingNode(node: Node): boolean;\n\n  /**\n   * 获取当前的 DropLocation 信息\n   * get current drop location\n   * @since v1.1.0\n   */\n  get dropLocation(): DropLocation | null;\n\n  /**\n   * 设置当前的 DropLocation 信息\n   * set current drop location\n   * @since v1.1.0\n   */\n  set dropLocation(loc: DropLocation | null);\n\n  /**\n   * 设置聚焦节点变化的回调\n   * triggered focused node is set mannually from plugin\n   * @param fn\n   * @since v1.1.0\n   */\n  onFocusNodeChanged(\n    fn: (doc: IPublicModelDocumentModel, focusNode: Node) => void,\n  ): IPublicTypeDisposable;\n\n  /**\n   * 设置 DropLocation 变化的回调\n   * triggered when drop location changed\n   * @param fn\n   * @since v1.1.0\n   */\n  onDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/drag-object.ts",
    "content": "import { IPublicEnumDragObjectType } from '../enum';\nimport { IPublicTypeNodeSchema } from '../type';\nimport { IPublicModelNode } from './node';\n\nexport class IPublicModelDragObject {\n  type: IPublicEnumDragObjectType.Node | IPublicEnumDragObjectType.NodeData;\n\n  data: IPublicTypeNodeSchema | IPublicTypeNodeSchema[] | null;\n\n  nodes: (IPublicModelNode | null)[] | null;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/dragon.ts",
    "content": "/* eslint-disable max-len */\nimport { IPublicTypeDisposable, IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type';\nimport { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './';\n\nexport interface IPublicModelDragon<\n  Node = IPublicModelNode,\n  LocateEvent = IPublicModelLocateEvent\n> {\n\n  /**\n   * 是否正在拖动\n   * is dragging or not\n   */\n  get dragging(): boolean;\n\n  /**\n   * 绑定 dragstart 事件\n   * bind a callback function which will be called on dragging start\n   * @param func\n   * @returns\n   */\n  onDragstart(func: (e: LocateEvent) => any): IPublicTypeDisposable;\n\n  /**\n   * 绑定 drag 事件\n   * bind a callback function which will be called on dragging\n   * @param func\n   * @returns\n   */\n  onDrag(func: (e: LocateEvent) => any): IPublicTypeDisposable;\n\n  /**\n   * 绑定 dragend 事件\n   * bind a callback function which will be called on dragging end\n   * @param func\n   * @returns\n   */\n  onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): IPublicTypeDisposable;\n\n  /**\n   * 设置拖拽监听的区域 shell，以及自定义拖拽转换函数 boost\n   * set a html element as shell to dragon as monitoring target, and\n   * set boost function which is used to transform a MouseEvent to type\n   * IPublicTypeDragNodeDataObject.\n   * @param shell 拖拽监听的区域\n   * @param boost 拖拽转换函数\n   */\n  from(shell: Element, boost: (e: MouseEvent) => IPublicTypeDragNodeDataObject | null): any;\n\n  /**\n   * 发射拖拽对象\n   * boost your dragObject for dragging(flying)\n   *\n   * @param dragObject 拖拽对象\n   * @param boostEvent 拖拽初始时事件\n   */\n  boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node): void;\n\n  /**\n   * 添加投放感应区\n   * add sensor area\n   */\n  addSensor(sensor: any): void;\n\n  /**\n   * 移除投放感应\n   * remove sensor area\n   */\n  removeSensor(sensor: any): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/drop-location.ts",
    "content": "import { IPublicTypeLocationDetail } from '../type';\nimport { IPublicModelLocateEvent, IPublicModelNode } from './';\n\nexport interface IPublicModelDropLocation {\n\n  /**\n   * 拖拽位置目标\n   * get target of dropLocation\n   */\n  get target(): IPublicModelNode | null;\n\n  /**\n   * 拖拽放置位置详情\n   * get detail of dropLocation\n   */\n  get detail(): IPublicTypeLocationDetail;\n\n  /**\n   * 拖拽放置位置对应的事件\n   * get event of dropLocation\n   */\n  get event(): IPublicModelLocateEvent;\n\n  /**\n   * 获取一份当前对象的克隆\n   * get a clone object of current dropLocation\n   */\n  clone(event: IPublicModelLocateEvent): IPublicModelDropLocation;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/editor-view.ts",
    "content": "import { IPublicModelPluginContext } from './plugin-context';\n\nexport interface IPublicModelEditorView extends IPublicModelPluginContext {\n  viewName: string;\n\n  viewType: 'editor' | 'webview';\n}"
  },
  {
    "path": "packages/types/src/shell/model/editor.ts",
    "content": "/* eslint-disable max-len */\nimport { EventEmitter } from 'events';\nimport StrictEventEmitter from 'strict-event-emitter-types';\nimport * as GlobalEvent from '../../event';\nimport { IPublicApiEvent } from '../api';\nimport { IPublicTypeEditorValueKey, IPublicTypeEditorGetOptions, IPublicTypeEditorGetResult, IPublicTypeEditorRegisterOptions, IPublicTypeAssetsJson } from '../type';\n\nexport interface IPublicModelEditor extends StrictEventEmitter<EventEmitter, GlobalEvent.EventConfig> {\n  get: <T = undefined, KeyOrType = any>(\n    keyOrType: KeyOrType,\n    opt?: IPublicTypeEditorGetOptions\n  ) => IPublicTypeEditorGetResult<T, KeyOrType> | undefined;\n\n  has: (keyOrType: IPublicTypeEditorValueKey) => boolean;\n\n  set: (key: IPublicTypeEditorValueKey, data: any) => void | Promise<void>;\n\n  /**\n   * 获取 keyOrType 一次\n   */\n  onceGot: <T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>(keyOrType: KeyOrType) => Promise<IPublicTypeEditorGetResult<T, KeyOrType>>;\n\n  /**\n   * 获取 keyOrType 多次\n   */\n  onGot: <T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>(\n    keyOrType: KeyOrType,\n    fn: (data: IPublicTypeEditorGetResult<T, KeyOrType>) => void\n  ) => () => void;\n\n  /**\n   * 监听 keyOrType 变化\n   */\n  onChange: <T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>(\n    keyOrType: KeyOrType,\n    fn: (data: IPublicTypeEditorGetResult<T, KeyOrType>) => void\n  ) => () => void;\n\n  register: (data: any, key?: IPublicTypeEditorValueKey, options?: IPublicTypeEditorRegisterOptions) => void;\n\n  get eventBus(): IPublicApiEvent;\n\n  setAssets(assets: IPublicTypeAssetsJson): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/engine-config.ts",
    "content": "import { IPublicTypeDisposable } from '../type';\nimport { IPublicModelPreference } from './';\n\nexport interface IPublicModelEngineConfig {\n\n  /**\n   * 判断指定 key 是否有值\n   * check if config has certain key configed\n   * @param key\n   * @returns\n   */\n  has(key: string): boolean;\n\n  /**\n   * 获取指定 key 的值\n   * get value by key\n   * @param key\n   * @param defaultValue\n   * @returns\n   */\n  get(key: string, defaultValue?: any): any;\n\n  /**\n   * 设置指定 key 的值\n   * set value for certain key\n   * @param key\n   * @param value\n   */\n  set(key: string, value: any): void;\n\n  /**\n   * 批量设值，set 的对象版本\n   * set multiple config key-values\n   * @param config\n   */\n  setConfig(config: { [key: string]: any }): void;\n\n  /**\n   * 获取指定 key 的值，若此时还未赋值，则等待，若已有值，则直接返回值\n   *  注：此函数返回 Promise 实例，只会执行（fullfill）一次\n   * wait until value of certain key is set, will only be\n   * triggered once.\n   * @param key\n   * @returns\n   */\n  onceGot(key: string): Promise<any>;\n\n  /**\n   * 获取指定 key 的值，函数回调模式，若多次被赋值，回调会被多次调用\n   * set callback for event of value set for some key\n   * this will be called each time the value is set\n   * @param key\n   * @param fn\n   * @returns\n   */\n  onGot(key: string, fn: (data: any) => void): IPublicTypeDisposable;\n\n  /**\n   * 获取全局 Preference, 用于管理全局浏览器侧用户 Preference，如 Panel 是否钉住\n   * get global user preference manager, which can be use to store\n   * user`s preference in user localstorage, such as a panel is pinned or not.\n   * @returns {IPublicModelPreference}\n   * @since v1.1.0\n   */\n  getPreference(): IPublicModelPreference;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/exclusive-group.ts",
    "content": "import { IPublicModelNode, IPublicTypeTitleContent } from '..';\n\nexport interface IPublicModelExclusiveGroup<\n  Node = IPublicModelNode,\n> {\n  readonly id: string | undefined;\n  readonly title: IPublicTypeTitleContent | undefined;\n  get firstNode(): Node | null;\n  setVisible(node: Node): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/history.ts",
    "content": "import { IPublicTypeDisposable } from '../type';\n\nexport interface IPublicModelHistory {\n\n  /**\n   * 历史记录跳转到指定位置\n   * go to a specific history\n   * @param cursor\n   */\n  go(cursor: number): void;\n\n  /**\n   * 历史记录后退\n   * go backward in history\n   */\n  back(): void;\n\n  /**\n   * 历史记录前进\n   * go forward in history\n   */\n  forward(): void;\n\n  /**\n   * 保存当前状态\n   * do save current change as a record in history\n   */\n  savePoint(): void;\n\n  /**\n   * 当前是否是「保存点」，即是否有状态变更但未保存\n   * check if there is unsaved change for history\n   */\n  isSavePoint(): boolean;\n\n  /**\n   * 获取 state，判断当前是否为「可回退」、「可前进」的状态\n   * get flags in number which indicat current change state\n   *\n   *  |    1     |     1    |    1     |\n   *  | -------- | -------- | -------- |\n   *  | modified | redoable | undoable |\n   * eg.\n   *  7 means : modified && redoable && undoable\n   *  5 means : modified && undoable\n   */\n  getState(): number;\n\n  /**\n   * 监听 state 变更事件\n   * monitor on stateChange event\n   * @param func\n   */\n  onChangeState(func: () => any): IPublicTypeDisposable;\n\n  /**\n   * 监听历史记录游标位置变更事件\n   * monitor on cursorChange event\n   * @param func\n   */\n  onChangeCursor(func: () => any): IPublicTypeDisposable;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/index.ts",
    "content": "export * from './component-meta';\nexport * from './detecting';\nexport * from './document-model';\nexport * from './drag-object';\nexport * from './dragon';\nexport * from './drop-location';\nexport * from './history';\nexport * from './locate-event';\nexport * from './modal-nodes-manager';\nexport * from './node-children';\nexport * from './node';\nexport * from './prop';\nexport * from './props';\nexport * from './selection';\nexport * from './setting-prop-entry';\nexport * from './setting-top-entry';\nexport * from '../type/plugin';\nexport * from './window';\nexport * from './scroll-target';\nexport * from './scroller';\nexport * from './active-tracker';\nexport * from './exclusive-group';\nexport * from './plugin-context';\nexport * from './setting-target';\nexport * from './engine-config';\nexport * from './editor';\nexport * from './preference';\nexport * from './plugin-instance';\nexport * from './sensor';\nexport * from './resource';\nexport * from './clipboard';\nexport * from './setting-field';\nexport * from './editor-view';\nexport * from './skeleton-item';\nexport * from './simulator-render';\n"
  },
  {
    "path": "packages/types/src/shell/model/locate-event.ts",
    "content": "import { IPublicModelDocumentModel, IPublicModelDragObject } from './';\n\nexport interface IPublicModelLocateEvent {\n\n  get type(): string;\n\n  /**\n   * 浏览器窗口坐标系\n   */\n  readonly globalX: number;\n  readonly globalY: number;\n\n  /**\n   * 原始事件\n   */\n  readonly originalEvent: MouseEvent | DragEvent;\n\n  /**\n   * 浏览器事件响应目标\n   */\n  target?: Element | null;\n\n  canvasX?: number;\n\n  canvasY?: number;\n\n  /**\n   * 事件订正标识，初始构造时，从发起端构造，缺少 canvasX,canvasY, 需要经过订正才有\n   */\n  fixed?: true;\n\n  /**\n   * 激活或目标文档\n   */\n  documentModel?: IPublicModelDocumentModel | null;\n\n  get dragObject(): IPublicModelDragObject | null;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/modal-nodes-manager.ts",
    "content": "import { IPublicModelNode } from './';\n\nexport interface IPublicModelModalNodesManager<Node = IPublicModelNode> {\n\n  /**\n   * 设置模态节点，触发内部事件\n   * set modal nodes, trigger internal events\n   */\n  setNodes(): void;\n\n  /**\n   * 获取模态节点（们）\n   * get modal nodes\n   */\n  getModalNodes(): Node[];\n\n  /**\n   * 获取当前可见的模态节点\n   * get current visible modal node\n   */\n  getVisibleModalNode(): Node | null;\n\n  /**\n   * 隐藏模态节点（们）\n   * hide modal nodes\n   */\n  hideModalNodes(): void;\n\n  /**\n   * 设置指定节点为可见态\n   * set specfic model node as visible\n   * @param node Node\n   */\n  setVisible(node: Node): void;\n\n  /**\n   * 设置指定节点为不可见态\n   * set specfic model node as invisible\n   * @param node Node\n   */\n  setInvisible(node: Node): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/node-children.ts",
    "content": "import { IPublicTypeNodeSchema, IPublicTypeNodeData } from '../type';\nimport { IPublicEnumTransformStage } from '../enum';\nimport { IPublicModelNode } from './';\n\nexport interface IPublicModelNodeChildren<\n  Node = IPublicModelNode\n> {\n\n  /**\n   * 返回当前 children 实例所属的节点实例\n   * get owner node of this nodeChildren\n   */\n  get owner(): Node | null;\n\n  /**\n   * children 内的节点实例数\n   * get count of child nodes\n   */\n  get size(): number;\n\n  /**\n   * @deprecated please use isEmptyNode\n   * 是否为空\n   * @returns\n   */\n  get isEmpty(): boolean;\n\n  /**\n   * 是否为空\n   *\n   * @returns\n   */\n  get isEmptyNode(): boolean;\n\n  /**\n   * @deprecated please use notEmptyNode\n   * judge if it is not empty\n   */\n  get notEmpty(): boolean;\n\n  /**\n   * judge if it is not empty\n   */\n  get notEmptyNode(): boolean;\n\n  /**\n   * 删除指定节点\n   *\n   * delete the node\n   * @param node\n   */\n  delete(node: Node): boolean;\n\n  /**\n   * 插入一个节点\n   *\n   * insert a node at specific position\n   * @param node 待插入节点\n   * @param at 插入下标\n   * @returns\n   */\n  insert(node: Node, at?: number | null): void;\n\n  /**\n   * 返回指定节点的下标\n   *\n   * get index of node in current children\n   * @param node\n   * @returns\n   */\n  indexOf(node: Node): number;\n\n  /**\n   * 类似数组 splice 操作\n   *\n   * provide the same function with {Array.prototype.splice}\n   * @param start\n   * @param deleteCount\n   * @param node\n   */\n  splice(start: number, deleteCount: number, node?: Node): any;\n\n  /**\n   * 返回指定下标的节点\n   *\n   * get node with index\n   * @param index\n   * @returns\n   */\n  get(index: number): Node | null;\n\n  /**\n   * 是否包含指定节点\n   *\n   * check if node exists in current children\n   * @param node\n   * @returns\n   */\n  has(node: Node): boolean;\n\n  /**\n   * 类似数组的 forEach\n   *\n   * provide the same function with {Array.prototype.forEach}\n   * @param fn\n   */\n  forEach(fn: (node: Node, index: number) => void): void;\n\n  /**\n   * 类似数组的 reverse\n   *\n   * provide the same function with {Array.prototype.reverse}\n   */\n  reverse(): Node[];\n\n  /**\n   * 类似数组的 map\n   *\n   * provide the same function with {Array.prototype.map}\n   * @param fn\n   */\n  map<T = any>(fn: (node: Node, index: number) => T): T[] | null;\n\n  /**\n   * 类似数组的 every\n   * provide the same function with {Array.prototype.every}\n   * @param fn\n   */\n  every(fn: (node: Node, index: number) => boolean): boolean;\n\n  /**\n   * 类似数组的 some\n   * provide the same function with {Array.prototype.some}\n   * @param fn\n   */\n  some(fn: (node: Node, index: number) => boolean): boolean;\n\n  /**\n   * 类似数组的 filter\n   * provide the same function with {Array.prototype.filter}\n   * @param fn\n   */\n  filter(fn: (node: Node, index: number) => boolean): any;\n\n  /**\n   * 类似数组的 find\n   * provide the same function with {Array.prototype.find}\n   * @param fn\n   */\n  find(fn: (node: Node, index: number) => boolean): Node | null | undefined;\n\n  /**\n   * 类似数组的 reduce\n   *\n   * provide the same function with {Array.prototype.reduce}\n   * @param fn\n   */\n  reduce(fn: (acc: any, cur: Node) => any, initialValue: any): void;\n\n  /**\n   * 导入 schema\n   *\n   * import schema\n   * @param data\n   */\n  importSchema(data?: IPublicTypeNodeData | IPublicTypeNodeData[]): void;\n\n  /**\n   * 导出 schema\n   *\n   * export schema\n   * @param stage\n   */\n  exportSchema(stage: IPublicEnumTransformStage): IPublicTypeNodeSchema;\n\n  /**\n   * 执行新增、删除、排序等操作\n   *\n   * excute remove/add/sort operations\n   * @param remover\n   * @param adder\n   * @param sorter\n   */\n  mergeChildren(\n    remover: (node: Node, idx: number) => boolean,\n    adder: (children: Node[]) => IPublicTypeNodeData[] | null,\n    sorter: (firstNode: Node, secondNode: Node) => number\n  ): any;\n\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/node.ts",
    "content": "import { ReactElement } from 'react';\nimport { IPublicTypeNodeSchema, IPublicTypeIconType, IPublicTypeI18nData, IPublicTypeCompositeValue, IPublicTypePropsMap, IPublicTypePropsList } from '../type';\nimport { IPublicEnumTransformStage } from '../enum';\nimport { IPublicModelNodeChildren, IPublicModelComponentMeta, IPublicModelProp, IPublicModelProps, IPublicModelSettingTopEntry, IPublicModelDocumentModel, IPublicModelExclusiveGroup } from './';\n\nexport interface IBaseModelNode<\n  Document = IPublicModelDocumentModel,\n  Node = IPublicModelNode,\n  NodeChildren = IPublicModelNodeChildren,\n  ComponentMeta = IPublicModelComponentMeta,\n  SettingTopEntry = IPublicModelSettingTopEntry,\n  Props = IPublicModelProps,\n  Prop = IPublicModelProp,\n  ExclusiveGroup = IPublicModelExclusiveGroup\n> {\n\n  /**\n   * 节点 id\n   * node id\n   */\n  id: string;\n\n  /**\n   * 节点标题\n   * title of node\n   */\n  get title(): string | IPublicTypeI18nData | ReactElement;\n\n  /**\n   * @deprecated please use isContainerNode\n   */\n  get isContainer(): boolean;\n\n  /**\n   * 是否为「容器型」节点\n   * check if node is a container type node\n   * @since v1.1.0\n   */\n  get isContainerNode(): boolean;\n\n  /**\n   * @deprecated please use isRootNode\n   */\n  get isRoot(): boolean;\n\n  /**\n   * 是否为根节点\n   * check if node is root in the tree\n   * @since v1.1.0\n   */\n  get isRootNode(): boolean;\n\n  /**\n   * @deprecated please use isEmptyNode\n   */\n  get isEmpty(): boolean;\n\n  /**\n   * 是否为空节点（无 children 或者 children 为空）\n   * check if current node is empty, which means no children or children is empty\n   * @since v1.1.0\n   */\n  get isEmptyNode(): boolean;\n\n  /**\n   * @deprecated please use isPageNode\n   * 是否为 Page 节点\n   */\n  get isPage(): boolean;\n\n  /**\n   * 是否为 Page 节点\n   * check if node is Page\n   * @since v1.1.0\n   */\n  get isPageNode(): boolean;\n\n  /**\n   * @deprecated please use isComponentNode\n   */\n  get isComponent(): boolean;\n\n  /**\n   * 是否为 Component 节点\n   * check if node is Component\n   * @since v1.1.0\n   */\n  get isComponentNode(): boolean;\n\n  /**\n   * @deprecated please use isModalNode\n   */\n  get isModal(): boolean;\n\n  /**\n   * 是否为「模态框」节点\n   * check if node is Modal\n   * @since v1.1.0\n   */\n  get isModalNode(): boolean;\n\n  /**\n   * @deprecated please use isSlotNode\n   */\n  get isSlot(): boolean;\n\n  /**\n   * 是否为插槽节点\n   * check if node is a Slot\n   * @since v1.1.0\n   */\n  get isSlotNode(): boolean;\n\n  /**\n   * @deprecated please use isParentalNode\n   */\n  get isParental(): boolean;\n\n  /**\n   * 是否为父类/分支节点\n   * check if node a parental node\n   * @since v1.1.0\n   */\n  get isParentalNode(): boolean;\n\n  /**\n   * @deprecated please use isLeafNode\n   */\n  get isLeaf(): boolean;\n\n  /**\n   * 是否为叶子节点\n   * check if node is a leaf node in tree\n   * @since v1.1.0\n   */\n  get isLeafNode(): boolean;\n\n  /**\n   * 获取当前节点的锁定状态\n   * check if current node is locked\n   * @since v1.0.16\n   */\n  get isLocked(): boolean;\n\n  /**\n   * @deprecated please use isRGLContainerNode\n   */\n  set isRGLContainer(flag: boolean);\n\n  /**\n   * @deprecated please use isRGLContainerNode\n   * @returns Boolean\n   */\n  get isRGLContainer();\n\n  /**\n   * 设置为磁贴布局节点\n   * @since v1.1.0\n   */\n  set isRGLContainerNode(flag: boolean);\n\n  /**\n   * 获取磁贴布局节点设置状态\n   * @returns Boolean\n   * @since v1.1.0\n   */\n  get isRGLContainerNode();\n\n  /**\n   * 下标\n   * index\n   */\n  get index(): number | undefined;\n\n  /**\n   * 图标\n   * get icon of this node\n   */\n  get icon(): IPublicTypeIconType;\n\n  /**\n   * 节点所在树的层级深度，根节点深度为 0\n   * depth level of this node, value of root node is 0\n   */\n  get zLevel(): number;\n\n  /**\n   * 节点 componentName\n   * componentName\n   */\n  get componentName(): string;\n\n  /**\n   * 节点的物料元数据\n   * get component meta of this node\n   */\n  get componentMeta(): ComponentMeta | null;\n\n  /**\n   * 获取节点所属的文档模型对象\n   * get documentModel of this node\n   */\n  get document(): Document | null;\n\n  /**\n   * 获取当前节点的前一个兄弟节点\n   * get previous sibling of this node\n   */\n  get prevSibling(): Node | null | undefined;\n\n  /**\n   * 获取当前节点的后一个兄弟节点\n   * get next sibling of this node\n   */\n  get nextSibling(): Node | null | undefined;\n\n  /**\n   * 获取当前节点的父亲节点\n   * get parent of this node\n   */\n  get parent(): Node | null;\n\n  /**\n   * 获取当前节点的孩子节点模型\n   * get children of this node\n   */\n  get children(): NodeChildren | null;\n\n  /**\n   * 节点上挂载的插槽节点们\n   * get slots of this node\n   */\n  get slots(): Node[];\n\n  /**\n   * 当前节点为插槽节点时，返回节点对应的属性实例\n   * return coresponding prop when this node is a slot node\n   */\n  get slotFor(): Prop | null | undefined;\n\n  /**\n   * 返回节点的属性集\n   * get props\n   */\n  get props(): Props | null;\n\n  /**\n   * 返回节点的属性集\n   * get props data\n   */\n  get propsData(): IPublicTypePropsMap | IPublicTypePropsList | null;\n\n  /**\n   * get conditionGroup\n   */\n  get conditionGroup(): ExclusiveGroup | null;\n\n  /**\n   * 获取符合搭建协议 - 节点 schema 结构\n   * get schema of this node\n   * @since v1.1.0\n   */\n  get schema(): IPublicTypeNodeSchema;\n\n  /**\n   * 获取对应的 setting entry\n   * get setting entry of this node\n   * @since v1.1.0\n   */\n  get settingEntry(): SettingTopEntry;\n\n  /**\n   * 返回节点的尺寸、位置信息\n   * get rect information for this node\n   */\n  getRect(): DOMRect | null;\n\n  /**\n   * 是否有挂载插槽节点\n   * check if current node has slots\n   */\n  hasSlots(): boolean;\n\n  /**\n   * 是否设定了渲染条件\n   * check if current node has condition value set\n   */\n  hasCondition(): boolean;\n\n  /**\n   * 是否设定了循环数据\n   * check if loop is set for this node\n   */\n  hasLoop(): boolean;\n\n  /**\n   * 获取指定 path 的属性模型实例\n   * get prop by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param createIfNone 如果不存在，是否新建，默认为 true\n   */\n  getProp(path: string | number, createIfNone?: boolean): Prop | null;\n\n  /**\n   * 获取指定 path 的属性模型实例值\n   * get prop value by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   */\n  getPropValue(path: string): any;\n\n  /**\n   * 获取指定 path 的属性模型实例，\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   *\n   * get extra prop by path, an extra prop means a prop not exists in the `props`\n   * but as siblint of the `props`\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param createIfNone 当没有属性的时候，是否创建一个属性\n   */\n  getExtraProp(path: string, createIfNone?: boolean): Prop | null;\n\n  /**\n   * 获取指定 path 的属性模型实例，\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   *\n   * get extra prop value by path, an extra prop means a prop not exists in the `props`\n   * but as siblint of the `props`\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @returns\n   */\n  getExtraPropValue(path: string): any;\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * set value for prop with path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   */\n  setPropValue(path: string | number, value: IPublicTypeCompositeValue): void;\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * set value for extra prop with path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   */\n  setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void;\n\n  /**\n   * 导入节点数据\n   * import node schema\n   * @param data\n   */\n  importSchema(data: IPublicTypeNodeSchema): void;\n\n  /**\n   * 导出节点数据\n   * export schema from this node\n   * @param stage\n   * @param options\n   */\n  exportSchema(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema;\n\n  /**\n   * 在指定位置之前插入一个节点\n   * insert a node befor current node\n   * @param node\n   * @param ref\n   * @param useMutator\n   */\n  insertBefore(\n      node: Node,\n      ref?: Node | undefined,\n      useMutator?: boolean,\n    ): void;\n\n  /**\n   * 在指定位置之后插入一个节点\n   * insert a node after this node\n   * @param node\n   * @param ref\n   * @param useMutator\n   */\n  insertAfter(\n      node: Node,\n      ref?: Node | undefined,\n      useMutator?: boolean,\n    ): void;\n\n  /**\n   * 替换指定节点\n   * replace a child node with data provided\n   * @param node 待替换的子节点\n   * @param data 用作替换的节点对象或者节点描述\n   * @returns\n   */\n  replaceChild(node: Node, data: any): Node | null;\n\n  /**\n   * 将当前节点替换成指定节点描述\n   * replace current node with a new node schema\n   * @param schema\n   */\n  replaceWith(schema: IPublicTypeNodeSchema): any;\n\n  /**\n   * 选中当前节点实例\n   * select current node\n   */\n  select(): void;\n\n  /**\n   * 设置悬停态\n   * set hover value for current node\n   * @param flag\n   */\n  hover(flag: boolean): void;\n\n  /**\n   * 设置节点锁定状态\n   * set lock value for current node\n   * @param flag\n   * @since v1.0.16\n   */\n  lock(flag?: boolean): void;\n\n  /**\n   * 删除当前节点实例\n   * remove current node\n   */\n  remove(): void;\n\n  /**\n   * 执行新增、删除、排序等操作\n   * excute remove/add/sort operations on node`s children\n   *\n   * @since v1.1.0\n   */\n  mergeChildren(\n    remover: (node: Node, idx: number) => boolean,\n    adder: (children: Node[]) => any,\n    sorter: (firstNode: Node, secondNode: Node) => number\n  ): any;\n\n  /**\n   * 当前节点是否包含某子节点\n   * check if current node contains another node as a child\n   * @param node\n   * @since v1.1.0\n   */\n  contains(node: Node): boolean;\n\n  /**\n   * 是否可执行某 action\n   * check if current node can perform certain aciton with actionName\n   * @param actionName action 名字\n   * @since v1.1.0\n   */\n  canPerformAction(actionName: string): boolean;\n\n  /**\n   * 当前节点是否可见\n   * check if current node is visible\n   * @since v1.1.0\n   */\n  get visible(): boolean;\n\n  /**\n   * 设置当前节点是否可见\n   * set visible value for current node\n   * @since v1.1.0\n   */\n  set visible(value: boolean);\n\n  /**\n   * 获取该节点的 ConditionalVisible 值\n   * check if current node ConditionalVisible\n   * @since v1.1.0\n   */\n  isConditionalVisible(): boolean | undefined;\n\n  /**\n   * 设置该节点的 ConditionalVisible 为 true\n   * make this node as conditionalVisible === true\n   * @since v1.1.0\n   */\n  setConditionalVisible(): void;\n\n  /**\n   * 获取节点实例对应的 dom 节点\n   */\n  getDOMNode(): HTMLElement;\n\n  /**\n   * 获取磁贴相关信息\n   */\n  getRGL(): {\n    isContainerNode: boolean;\n    isEmptyNode: boolean;\n    isRGLContainerNode: boolean;\n    isRGLNode: boolean;\n    isRGL: boolean;\n    rglNode: Node | null;\n  };\n}\n\nexport interface IPublicModelNode extends IBaseModelNode<IPublicModelDocumentModel, IPublicModelNode> {}"
  },
  {
    "path": "packages/types/src/shell/model/plugin-context.ts",
    "content": "import {\n  IPublicApiSkeleton,\n  IPublicApiHotkey,\n  IPublicApiSetters,\n  IPublicApiMaterial,\n  IPublicApiEvent,\n  IPublicApiProject,\n  IPublicApiCommon,\n  IPublicApiLogger,\n  IPublicApiCanvas,\n  IPluginPreferenceMananger,\n  IPublicApiPlugins,\n  IPublicApiWorkspace,\n  IPublicApiCommonUI,\n  IPublicApiCommand,\n} from '../api';\nimport { IPublicEnumPluginRegisterLevel } from '../enum';\nimport { IPublicModelEngineConfig, IPublicModelWindow } from './';\n\nexport interface IPublicModelPluginContext {\n\n  /**\n   * 可通过该对象读取插件初始化配置\n   * by using this, init options can be accessed from inside plugin\n   */\n  preference: IPluginPreferenceMananger;\n\n  /**\n   * skeleton API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/skeleton\n   */\n  get skeleton(): IPublicApiSkeleton;\n\n  /**\n   * hotkey API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/hotkey\n   */\n  get hotkey(): IPublicApiHotkey;\n\n  /**\n   * setter API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/setters\n   */\n  get setters(): IPublicApiSetters;\n\n  /**\n   * config API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/config\n   */\n  get config(): IPublicModelEngineConfig;\n\n  /**\n   * material API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/material\n   */\n  get material(): IPublicApiMaterial;\n\n  /**\n   * event API\n   * this event works globally, can be used between plugins and engine.\n   * @tutorial https://lowcode-engine.cn/site/docs/api/event\n   */\n  get event(): IPublicApiEvent;\n\n  /**\n   * project API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/project\n   */\n  get project(): IPublicApiProject;\n\n  /**\n   * common API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/common\n   */\n  get common(): IPublicApiCommon;\n\n  /**\n   * plugins API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/plugins\n   */\n  get plugins(): IPublicApiPlugins;\n\n  /**\n   * logger API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/logger\n   */\n  get logger(): IPublicApiLogger;\n\n  /**\n   * this event works within current plugin, on an emit locally.\n   * @tutorial https://lowcode-engine.cn/site/docs/api/event\n   */\n  get pluginEvent(): IPublicApiEvent;\n\n  /**\n   * canvas API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/canvas\n   */\n  get canvas(): IPublicApiCanvas;\n\n  /**\n   * workspace API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/workspace\n   */\n  get workspace(): IPublicApiWorkspace;\n\n  /**\n   * commonUI API\n   * @tutorial https://lowcode-engine.cn/site/docs/api/commonUI\n   */\n  get commonUI(): IPublicApiCommonUI;\n\n  get command(): IPublicApiCommand;\n\n  /**\n   * 插件注册层级\n   * @since v1.1.7\n   */\n  get registerLevel(): IPublicEnumPluginRegisterLevel;\n\n  get isPluginRegisteredInWorkspace(): boolean;\n\n  get editorWindow(): IPublicModelWindow;\n}\n\n/**\n * @deprecated please use IPublicModelPluginContext instead\n */\nexport interface ILowCodePluginContext extends IPublicModelPluginContext {\n\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/plugin-instance.ts",
    "content": "import { IPublicTypePluginMeta } from '../type/plugin-meta';\n\nexport interface IPublicModelPluginInstance {\n\n  /**\n   * 是否 disable\n   * current plugin instance is disabled or not\n   */\n  disabled: boolean;\n\n  /**\n   * 插件名称\n   * plugin name\n   */\n  get pluginName(): string;\n\n  /**\n   * 依赖信息，依赖的其他插件\n   * depenency info\n   */\n  get dep(): string[];\n\n  /**\n   * 插件配置元数据\n   * meta info of this plugin\n   */\n  get meta(): IPublicTypePluginMeta;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/preference.ts",
    "content": "\nexport interface IPublicModelPreference {\n\n  /**\n   * set value from local storage by module and key\n   */\n  set(key: string, value: any, module?: string): void;\n\n  /**\n   * get value from local storage by module and key\n   */\n  get(key: string, module: string): any;\n\n  /**\n   * check if local storage contain certain key\n   */\n  contains(key: string, module: string): boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/prop.ts",
    "content": "import { IPublicEnumTransformStage } from '../enum';\nimport { IPublicTypeCompositeValue } from '../type';\nimport { IPublicModelNode } from './';\n\nexport interface IPublicModelProp<\n  Node = IPublicModelNode\n> {\n\n  /**\n   * id\n   */\n  get id(): string;\n\n  /**\n   * key 值\n   * get key of prop\n   */\n  get key(): string | number | undefined;\n\n  /**\n   * 返回当前 prop 的路径\n   * get path of current prop\n   */\n  get path(): string[];\n\n  /**\n   * 返回所属的节点实例\n   * get node instance, which this prop belongs to\n   */\n  get node(): Node | null;\n\n  /**\n   * 当本 prop 代表一个 Slot 时，返回对应的 slotNode\n   * return the slot node (only if the current prop represents a slot)\n   * @since v1.1.0\n   */\n  get slotNode(): Node | undefined | null;\n\n  /**\n   * 是否是 Prop , 固定返回 true\n   * check if it is a prop or not, and of course always return true\n   * @experimental\n   */\n  get isProp(): boolean;\n\n  /**\n   * 设置值\n   * set value for this prop\n   * @param val\n   */\n  setValue(val: IPublicTypeCompositeValue): void;\n\n  /**\n   * 获取值\n   * get value of this prop\n   */\n  getValue(): any;\n\n  /**\n   * 移除值\n   * remove value of this prop\n   * @since v1.0.16\n   */\n  remove(): void;\n\n  /**\n   * 导出值\n   * export schema\n   * @param stage\n   */\n  exportSchema(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/props.ts",
    "content": "import { IPublicTypeCompositeValue } from '../type';\nimport { IPublicModelNode, IPublicModelProp } from './';\n\nexport interface IBaseModelProps<\n  Prop\n> {\n\n  /**\n   * id\n   */\n  get id(): string;\n\n  /**\n   * 返回当前 props 的路径\n   * return path of current props\n   */\n  get path(): string[];\n\n  /**\n   * 返回所属的 node 实例\n   */\n  get node(): IPublicModelNode | null;\n\n  /**\n   * 获取指定 path 的属性模型实例\n   * get prop by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   */\n  getProp(path: string): Prop | null;\n\n  /**\n   * 获取指定 path 的属性模型实例值\n   * get value of prop by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   */\n  getPropValue(path: string): any;\n\n  /**\n   * 获取指定 path 的属性模型实例，\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   * get extra prop by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   */\n  getExtraProp(path: string): Prop | null;\n\n  /**\n   * 获取指定 path 的属性模型实例值\n   *  注：导出时，不同于普通属性，该属性并不挂载在 props 之下，而是与 props 同级\n   * get value of extra prop by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   */\n  getExtraPropValue(path: string): any;\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * set value of prop by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   */\n  setPropValue(path: string, value: IPublicTypeCompositeValue): void;\n\n  /**\n   * 设置指定 path 的属性模型实例值\n   * set value of extra prop by path\n   * @param path 属性路径，支持 a / a.b / a.0 等格式\n   * @param value 值\n   */\n  setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void;\n\n  /**\n   * 当前 props 是否包含某 prop\n   * check if the specified key is existing or not.\n   * @param key\n   * @since v1.1.0\n   */\n  has(key: string): boolean;\n\n  /**\n   * 添加一个 prop\n   * add a key with given value\n   * @param value\n   * @param key\n   * @since v1.1.0\n   */\n  add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any;\n\n}\n\nexport interface IPublicModelProps extends IBaseModelProps<IPublicModelProp> {};"
  },
  {
    "path": "packages/types/src/shell/model/resource.ts",
    "content": "import { ReactElement } from 'react';\n\nexport interface IBaseModelResource<\n  Resource\n> {\n  get title(): string | undefined;\n\n  get id(): string | undefined;\n\n  get icon(): ReactElement | undefined;\n\n  get options(): Record<string, any>;\n\n  get name(): string | undefined;\n\n  get type(): string | undefined;\n\n  get category(): string | undefined;\n\n  get children(): Resource[];\n\n  get viewName(): string | undefined;\n\n  get description(): string | undefined;\n\n  get config(): {\n    [key: string]: any;\n  } | undefined;\n}\n\nexport type IPublicModelResource = IBaseModelResource<IPublicModelResource>;\n"
  },
  {
    "path": "packages/types/src/shell/model/scroll-target.ts",
    "content": "\nexport interface IPublicModelScrollTarget {\n  get left(): number;\n  get top(): number;\n  scrollTo(options: { left?: number; top?: number }): void;\n  scrollToXY(x: number, y: number): void;\n  get scrollHeight(): number;\n  get scrollWidth(): number;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/scroller.ts",
    "content": "export interface IPublicModelScroller {\n\n  scrollTo(options: { left?: number; top?: number }): void;\n\n  cancel(): void;\n\n  scrolling(point: { globalX: number; globalY: number }): void;\n}"
  },
  {
    "path": "packages/types/src/shell/model/selection.ts",
    "content": "import { IPublicModelNode } from './';\nimport { IPublicTypeDisposable } from '../type';\n\nexport interface IPublicModelSelection<\n  Node = IPublicModelNode\n> {\n\n  /**\n   * 返回选中的节点 id\n   * get ids of selected nodes\n   */\n  get selected(): string[];\n\n  /**\n   * 返回选中的节点（如多个节点只返回第一个）\n   * return selected Node instance，return the first one if multiple nodes are selected\n   * @since v1.1.0\n   */\n  get node(): Node | null;\n\n  /**\n   * 选中指定节点（覆盖方式）\n   * select node with id, this will override current selection\n   * @param id\n   */\n  select(id: string): void;\n\n  /**\n   * 批量选中指定节点们\n   * select node with ids, this will override current selection\n   *\n   * @param ids\n   */\n  selectAll(ids: string[]): void;\n\n  /**\n   * 移除选中的指定节点\n   * remove node from selection with node id\n   * @param id\n   */\n  remove(id: string): void;\n\n  /**\n   * 清除所有选中节点\n   * clear current selection\n   */\n  clear(): void;\n\n  /**\n   * 判断是否选中了指定节点\n   * check if node with specific id is selected\n   * @param id\n   */\n  has(id: string): boolean;\n\n  /**\n   * 选中指定节点（增量方式）\n   * add node with specific id to selection\n   * @param id\n   */\n  add(id: string): void;\n\n  /**\n   * 获取选中的节点实例\n   * get selected nodes\n   */\n  getNodes(): Node[];\n\n  /**\n   * 获取选区的顶层节点\n   * get seleted top nodes\n   * for example:\n   *  getNodes() returns [A, subA, B], then\n   *  getTopNodes() will return [A, B], subA will be removed\n   * @since v1.0.16\n   */\n  getTopNodes(includeRoot?: boolean): Node[];\n\n  /**\n   * 注册 selection 变化事件回调\n   * set callback which will be called when selection is changed\n   * @since v1.1.0\n   */\n  onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/sensor.ts",
    "content": "import { IPublicTypeNodeInstance } from '../type/node-instance';\nimport {\n  IPublicModelLocateEvent,\n  IPublicModelDropLocation,\n  IPublicTypeComponentInstance,\n  IPublicModelNode,\n} from '..';\n\n/**\n * 拖拽敏感板\n */\nexport interface IPublicModelSensor<\n  Node = IPublicModelNode\n> {\n\n  /**\n   * 是否可响应，比如面板被隐藏，可设置该值 false\n   */\n  readonly sensorAvailable: boolean;\n\n  /**\n   * 给事件打补丁\n   */\n  fixEvent(e: IPublicModelLocateEvent): IPublicModelLocateEvent;\n\n  /**\n   * 定位并激活\n   */\n  locate(e: IPublicModelLocateEvent): IPublicModelDropLocation | undefined | null;\n\n  /**\n   * 是否进入敏感板区域\n   */\n  isEnter(e: IPublicModelLocateEvent): boolean;\n\n  /**\n   * 取消激活\n   */\n  deactiveSensor(): void;\n\n  /**\n   * 获取节点实例\n   */\n  getNodeInstanceFromElement?: (e: Element | null) => IPublicTypeNodeInstance<IPublicTypeComponentInstance, Node> | null;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/setting-field.ts",
    "content": "import { IPublicTypeCustomView, IPublicTypeCompositeValue, IPublicTypeSetterType, IPublicTypeSetValueOptions, IPublicTypeFieldConfig, IPublicTypeFieldExtraProps, IPublicTypeDisposable } from '../type';\nimport { IPublicModelNode, IPublicModelComponentMeta, IPublicModelSettingTopEntry } from './';\n\nexport interface IBaseModelSettingField<\n  SettingTopEntry,\n  SettingField,\n  ComponentMeta,\n  Node\n> {\n\n  /**\n   * 获取设置属性的父设置属性\n   */\n  readonly parent: SettingTopEntry | SettingField;\n\n  /**\n   * 获取设置属性的 isGroup\n   */\n  get isGroup(): boolean;\n\n  /**\n   * 获取设置属性的 id\n   */\n  get id(): string;\n\n  /**\n   * 获取设置属性的 name\n   */\n  get name(): string | number | undefined;\n\n  /**\n   * 获取设置属性的 key\n   */\n  get key(): string | number | undefined;\n\n  /**\n   * 获取设置属性的 path\n   */\n  get path(): (string | number)[];\n\n  /**\n   * 获取设置属性的 title\n   */\n  get title(): string;\n\n  /**\n   * 获取设置属性的 setter\n   */\n  get setter(): IPublicTypeSetterType | null;\n\n  /**\n   * 获取设置属性的 expanded\n   */\n  get expanded(): boolean;\n\n  /**\n   * 获取设置属性的 extraProps\n   */\n  get extraProps(): IPublicTypeFieldExtraProps;\n\n  get props(): SettingTopEntry;\n\n  /**\n   * 获取设置属性对应的节点实例\n   */\n  get node(): Node | null;\n\n  /**\n   * 获取顶级设置属性\n   */\n  get top(): SettingTopEntry;\n\n  /**\n   * 是否是 SettingField 实例\n   */\n  get isSettingField(): boolean;\n\n  /**\n   * componentMeta\n   */\n  get componentMeta(): ComponentMeta | null;\n\n  /**\n   * 获取设置属性的 items\n   */\n  get items(): Array<SettingField | IPublicTypeCustomView>;\n\n  /**\n   * 设置 key 值\n   * @param key\n   */\n  setKey(key: string | number): void;\n\n  /**\n   * 设置值\n   * @param val 值\n   */\n  setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void;\n\n  /**\n   * 设置子级属性值\n   * @param propName 子属性名\n   * @param value 值\n   */\n  setPropValue(propName: string | number, value: any): void;\n\n  /**\n   * 清空指定属性值\n   * @param propName\n   */\n  clearPropValue(propName: string | number): void;\n\n  /**\n   * 获取配置的默认值\n   * @returns\n   */\n  getDefaultValue(): any;\n\n  /**\n   * 获取值\n   * @returns\n   */\n  getValue(): any;\n\n  /**\n   * 获取子级属性值\n   * @param propName 子属性名\n   * @returns\n   */\n  getPropValue(propName: string | number): any;\n\n  /**\n   * 获取顶层附属属性值\n   */\n  getExtraPropValue(propName: string): any;\n\n  /**\n   * 设置顶层附属属性值\n   */\n  setExtraPropValue(propName: string, value: any): void;\n\n  /**\n   * 获取设置属性集\n   * @returns\n   */\n  getProps(): SettingTopEntry;\n\n  /**\n   * 是否绑定了变量\n   * @returns\n   */\n  isUseVariable(): boolean;\n\n  /**\n   * 设置绑定变量\n   * @param flag\n   */\n  setUseVariable(flag: boolean): void;\n\n  /**\n   * 创建一个设置 field 实例\n   * @param config\n   * @returns\n   */\n  createField(config: IPublicTypeFieldConfig): SettingField;\n\n  /**\n   * 获取值，当为变量时，返回 mock\n   * @returns\n   */\n  getMockOrValue(): any;\n\n  /**\n   * 销毁当前 field 实例\n   */\n  purge(): void;\n\n  /**\n   * 移除当前 field 实例\n   */\n  remove(): void;\n\n  /**\n   * 设置 autorun\n   * @param action\n   * @returns\n   */\n  onEffect(action: () => void): IPublicTypeDisposable;\n}\n\nexport interface IPublicModelSettingField extends IBaseModelSettingField<\n  IPublicModelSettingTopEntry,\n  IPublicModelSettingField,\n  IPublicModelComponentMeta,\n  IPublicModelNode\n> {\n\n}"
  },
  {
    "path": "packages/types/src/shell/model/setting-prop-entry.ts",
    "content": "import { IPublicModelSettingField } from './';\n\n/**\n * @deprecated please use IPublicModelSettingField\n */\nexport type IPublicModelSettingPropEntry  = IPublicModelSettingField\n"
  },
  {
    "path": "packages/types/src/shell/model/setting-target.ts",
    "content": "import { IPublicModelSettingField } from './';\n\n/**\n * @deprecated please use IPublicModelSettingField\n */\nexport type IPublicModelSettingTarget = IPublicModelSettingField;\n"
  },
  {
    "path": "packages/types/src/shell/model/setting-top-entry.ts",
    "content": "import { IPublicModelNode, IPublicModelSettingField } from './';\n\nexport interface IPublicModelSettingTopEntry<\n  Node = IPublicModelNode,\n  SettingField = IPublicModelSettingField\n> {\n\n  /**\n   * 返回所属的节点实例\n   */\n  get node(): Node | null;\n\n  /**\n   * 获取子级属性对象\n   * @param propName\n   * @returns\n   */\n  get(propName: string | number): SettingField | null;\n\n  /**\n   * 获取指定 propName 的值\n   * @param propName\n   * @returns\n   */\n  getPropValue(propName: string | number): any;\n\n  /**\n   * 设置指定 propName 的值\n   * @param propName\n   * @param value\n   */\n  setPropValue(propName: string | number, value: any): void;\n\n  /**\n   * 清除指定 propName 的值\n   * @param propName\n   */\n  clearPropValue(propName: string | number): void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/simulator-render.ts",
    "content": "export interface IPublicModelSimulatorRender {\n\n  /**\n   * 画布组件列表\n   */\n  components: {\n    [key: string]: any;\n  };\n\n  /**\n   * 触发画布重新渲染\n   */\n  rerender: () => void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/model/skeleton-item.ts",
    "content": "/**\n * @since 1.1.7\n */\nexport interface IPublicModelSkeletonItem {\n  name: string;\n\n  visible: boolean;\n\n  disable(): void;\n\n  enable(): void;\n\n  hide(): void;\n\n  show(): void;\n\n  /**\n   * @since v1.1.10\n   */\n  toggle(): void;\n}"
  },
  {
    "path": "packages/types/src/shell/model/window.ts",
    "content": "import { ReactElement } from 'react';\nimport { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type';\nimport { IPublicModelResource } from './resource';\nimport { IPublicModelEditorView } from './editor-view';\n\nexport interface IPublicModelWindow<\n  Resource = IPublicModelResource\n> {\n\n  /** 窗口 id */\n  id: string;\n\n  /** 窗口标题 */\n  title?: string;\n\n  /** 窗口 icon */\n  icon?: ReactElement;\n\n  /** 窗口资源类型 */\n  resource?: Resource;\n\n  /**\n   * 窗口当前视图\n   * @since v1.1.7\n   */\n  currentEditorView: IPublicModelEditorView | null;\n\n  /**\n   * 窗口全部视图实例\n   * @since v1.1.7\n   */\n  editorViews: IPublicModelEditorView[];\n\n  /** 当前窗口导入 schema */\n  importSchema(schema: IPublicTypeNodeSchema): void;\n\n  /** 修改当前窗口视图类型 */\n  changeViewType(viewName: string): void;\n\n  /** 调用当前窗口视图保存钩子 */\n  save(): Promise<any>;\n\n  /** 窗口视图变更事件 */\n  onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable;\n\n  /**\n   * 窗口视图保存事件\n   * @since 1.1.7\n   */\n  onSave(fn: () => void): IPublicTypeDisposable;\n}"
  },
  {
    "path": "packages/types/src/shell/type/action-content-object.ts",
    "content": "import { IPublicModelNode } from '../model';\nimport { IPublicTypeIconType, TipContent } from './';\n\n/**\n * 动作描述\n */\nexport interface IPublicTypeActionContentObject {\n\n  /**\n   * 图标\n   */\n  icon?: IPublicTypeIconType;\n\n  /**\n   * 描述\n   */\n  title?: TipContent;\n\n  /**\n   * 执行动作\n   */\n  action?: (currentNode: IPublicModelNode) => void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/active-target.ts",
    "content": "import { IPublicModelNode } from '../model';\nimport { IPublicTypeLocationDetail, IPublicTypeComponentInstance } from './';\n\nexport interface IPublicTypeActiveTarget {\n  node: IPublicModelNode;\n  detail?: IPublicTypeLocationDetail;\n  instance?: IPublicTypeComponentInstance;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/advanced.ts",
    "content": "import { ComponentType, ReactElement } from 'react';\nimport { IPublicTypeNodeData, IPublicTypeSnippet, IPublicTypeInitialItem, IPublicTypeFilterItem, IPublicTypeAutorunItem, IPublicTypeCallbacks, IPublicTypeLiveTextEditingConfig } from './';\nimport { IPublicModelNode, IPublicModelSettingField } from '../model';\n\n/**\n * 高级特性配置\n */\nexport interface IPublicTypeAdvanced {\n\n  /**\n   * 配置 callbacks 可捕获引擎抛出的一些事件，例如 onNodeAdd、onResize 等\n   * callbacks/hooks which can be used to do\n   * things on some special ocations like onNodeAdd or onResize\n   */\n  callbacks?: IPublicTypeCallbacks;\n\n  /**\n   * 拖入容器时，自动带入 children 列表\n   */\n  initialChildren?: IPublicTypeNodeData[] | ((target: IPublicModelNode) => IPublicTypeNodeData[]);\n\n  /**\n   * 样式 及 位置，handle 上必须有明确的标识以便事件路由判断，或者主动设置事件独占模式\n   * NWSE 是交给引擎计算放置位置，ReactElement 必须自己控制初始位置\n   *\n   * 用于配置设计器中组件 resize 操作工具的样式和内容\n   * - hover 时控制柄高亮\n   * - mousedown 时请求独占\n   * - dragstart 请求通用 resizing 控制 请求 hud 显示\n   * - drag 时 计算并设置效果，更新控制柄位置\n   */\n  getResizingHandlers?: (\n    currentNode: any\n  ) => (Array<{\n    type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW';\n    content?: ReactElement;\n    propTarget?: string;\n    appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always';\n  }> |\n    ReactElement[]);\n\n  /**\n   * @deprecated 用于动态初始化拖拽到设计器里的组件的 prop 的值\n   */\n  initials?: IPublicTypeInitialItem[];\n\n  /**\n   * @deprecated 使用组件 metadata 上的 snippets 字段即可\n   */\n  snippets?: IPublicTypeSnippet[];\n\n  /**\n   * 是否绝对布局容器，还未进入协议\n   * @experimental not in spec yet\n   */\n  isAbsoluteLayoutContainer?: boolean;\n\n  /**\n   * hide bem tools when selected\n   * @experimental not in spec yet\n   */\n  hideSelectTools?: boolean;\n\n  /**\n   * Live Text Editing：如果 children 内容是纯文本，支持双击直接编辑\n   * @experimental not in spec yet\n   */\n  liveTextEditing?: IPublicTypeLiveTextEditingConfig[];\n\n  /**\n   * TODO: 补充文档\n   * @experimental not in spec yet\n   */\n  view?: ComponentType<any>;\n\n  /**\n   * @legacy capability for vision\n   * @deprecated\n   */\n  isTopFixed?: boolean;\n\n  /**\n   * TODO: 补充文档 或 删除\n   * @deprecated not used anywhere, dont know what is it for\n   */\n  context?: { [contextInfoName: string]: any };\n\n  /**\n   * @legacy capability for vision\n   * @deprecated\n   */\n  filters?: IPublicTypeFilterItem[];\n\n  /**\n   * @legacy capability for vision\n   * @deprecated\n   */\n  autoruns?: IPublicTypeAutorunItem[];\n\n  /**\n   * @legacy capability for vision\n   * @deprecated\n   */\n  transducers?: any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/app-config.ts",
    "content": "export interface IPublicTypeAppConfig {\n  sdkVersion?: string;\n  historyMode?: string;\n  targetRootID?: string;\n  layout?: IPublicTypeLayout;\n  theme?: IPublicTypeTheme;\n}\n\ninterface IPublicTypeTheme {\n  package: string;\n  version: string;\n  primary: string;\n}\n\ninterface IPublicTypeLayout {\n  componentName?: string;\n  props?: Record<string, any>;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/assets-json.ts",
    "content": "import { IPublicTypeComponentSort, IPublicTypePackage, IPublicTypeRemoteComponentDescription, IPublicTypeComponentDescription } from './';\n\n/**\n * 资产包协议\n */\n\nexport interface IPublicTypeAssetsJson {\n  /**\n   * 资产包协议版本号\n   */\n  version: string;\n  /**\n   * 大包列表，external 与 package 的概念相似，融合在一起\n   */\n  packages?: IPublicTypePackage[];\n  /**\n   * 所有组件的描述协议列表所有组件的列表\n   */\n  components: Array<IPublicTypeComponentDescription | IPublicTypeRemoteComponentDescription>;\n  /**\n   * 组件分类列表，用来描述物料面板\n   * @deprecated 最新版物料面板已不需要此描述\n   */\n  componentList?: any[];\n  /**\n   * 业务组件分类列表，用来描述物料面板\n   * @deprecated 最新版物料面板已不需要此描述\n   */\n  bizComponentList?: any[];\n  /**\n   * 用于描述组件面板中的 tab 和 category\n   */\n  sort?: IPublicTypeComponentSort;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/block-schema.ts",
    "content": "import { IPublicTypeContainerSchema } from './';\n\n/**\n * 区块容器\n * @see https://lowcode-engine.cn/lowcode\n */\n\nexport interface IPublicTypeBlockSchema extends IPublicTypeContainerSchema {\n  componentName: 'Block';\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/command.ts",
    "content": "import { IPublicTypePropType } from './prop-types';\n\n// 定义命令处理函数的参数类型\nexport interface IPublicTypeCommandHandlerArgs {\n  [key: string]: any;\n}\n\n// 定义命令参数的接口\nexport interface IPublicTypeCommandParameter {\n\n  /**\n   * 参数名称\n   */\n  name: string;\n\n  /**\n   * 参数类型或详细类型描述\n   */\n  propType: string | IPublicTypePropType;\n\n  /**\n   * 参数描述\n   */\n  description: string;\n\n  /**\n   * 参数默认值（可选）\n   */\n  defaultValue?: any;\n}\n\n// 定义单个命令的接口\nexport interface IPublicTypeCommand {\n\n  /**\n   * 命令名称\n   * 命名规则：commandName\n   * 使用规则：commandScope:commandName (commandScope 在插件 meta 中定义，用于区分不同插件的命令)\n   */\n  name: string;\n\n  /**\n   * 命令参数\n   */\n  parameters?: IPublicTypeCommandParameter[];\n\n  /**\n   * 命令描述\n   */\n  description?: string;\n\n  /**\n   * 命令处理函数\n   */\n  handler: (args: any) => void;\n}\n\nexport interface IPublicTypeListCommand extends Pick<IPublicTypeCommand, 'name' | 'description' | 'parameters'> {\n}"
  },
  {
    "path": "packages/types/src/shell/type/component-action.ts",
    "content": "import { ReactNode } from 'react';\nimport { IPublicTypeActionContentObject } from './';\n\n/**\n * @todo 工具条动作\n */\n\nexport interface IPublicTypeComponentAction {\n\n  /**\n   * behaviorName\n   */\n  name: string;\n\n  /**\n   * 菜单名称\n   */\n  content: string | ReactNode | IPublicTypeActionContentObject;\n\n  /**\n   * 子集\n   */\n  items?: IPublicTypeComponentAction[];\n\n  /**\n   * 显示与否\n   * always: 无法禁用\n   */\n  condition?: boolean | ((currentNode: any) => boolean) | 'always';\n\n  /**\n   * 显示在工具条上\n   */\n  important?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/component-description.ts",
    "content": "import { IPublicTypeComponentMetadata, IPublicTypeReference } from './';\n\n/**\n * 本地物料描述\n */\n\nexport interface IPublicTypeComponentDescription extends IPublicTypeComponentMetadata {\n  /**\n   * @todo 待补充文档 @jinchan\n   */\n  keywords: string[];\n  /**\n   * 替代 npm 字段的升级版本\n   */\n  reference?: IPublicTypeReference;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/component-instance.ts",
    "content": "\nimport { Component as ReactComponent } from 'react';\n/**\n * 组件实例定义\n */\nexport type IPublicTypeComponentInstance = Element | ReactComponent<any> | object;"
  },
  {
    "path": "packages/types/src/shell/type/component-metadata.ts",
    "content": "import { IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeFieldConfig, IPublicTypeI18nData, IPublicTypeComponentSchema, IPublicTypeTitleContent, IPublicTypePropConfig, IPublicTypeConfigure, IPublicTypeAdvanced, IPublicTypeSnippet } from './';\n\n/**\n * 组件 meta 配置\n */\n\nexport interface IPublicTypeComponentMetadata {\n\n  /** 其他扩展协议 */\n  [key: string]: any;\n\n  /**\n   * 组件名\n   */\n  componentName: string;\n\n  /**\n   * unique id\n   */\n  uri?: string;\n\n  /**\n   * title or description\n   */\n  title?: IPublicTypeTitleContent;\n\n  /**\n   * svg icon for component\n   */\n  icon?: IPublicTypeIconType;\n\n  /**\n   * 组件标签\n   */\n  tags?: string[];\n\n  /**\n   * 组件描述\n   */\n  description?: string;\n\n  /**\n   * 组件文档链接\n   */\n  docUrl?: string;\n\n  /**\n   * 组件快照\n   */\n  screenshot?: string;\n\n  /**\n   * 组件研发模式\n   */\n  devMode?: 'proCode' | 'lowCode';\n\n  /**\n   * npm 源引入完整描述对象\n   */\n  npm?: IPublicTypeNpmInfo;\n\n  /**\n   * 组件属性信息\n   */\n  props?: IPublicTypePropConfig[];\n\n  /**\n   * 编辑体验增强\n   */\n  configure?: IPublicTypeFieldConfig[] | IPublicTypeConfigure;\n\n  /**\n   * @deprecated, use advanced instead\n   */\n  experimental?: IPublicTypeAdvanced;\n\n  /**\n   * @todo 待补充文档\n   */\n  schema?: IPublicTypeComponentSchema;\n\n  /**\n   * 可用片段\n   */\n  snippets?: IPublicTypeSnippet[];\n\n  /**\n   * 一级分组\n   */\n  group?: string | IPublicTypeI18nData;\n\n  /**\n   * 二级分组\n   */\n  category?: string | IPublicTypeI18nData;\n\n  /**\n   * 组件优先级排序\n   */\n  priority?: number;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/component-schema.ts",
    "content": "import { IPublicTypeContainerSchema } from './';\n\n/**\n * 低代码业务组件容器\n * @see https://lowcode-engine.cn/lowcode\n */\n\nexport interface IPublicTypeComponentSchema extends IPublicTypeContainerSchema {\n  componentName: 'Component';\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/component-sort.ts",
    "content": "/**\n * 用于描述组件面板中的 tab 和 category\n */\n\nexport interface IPublicTypeComponentSort {\n  /**\n   * 用于描述组件面板的 tab 项及其排序，例如：[\"精选组件\", \"原子组件\"]\n   */\n  groupList?: string[];\n  /**\n   * 组件面板中同一个 tab 下的不同区间用 category 区分，category 的排序依照 categoryList 顺序排列；\n   */\n  categoryList?: string[];\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/composite-value.ts",
    "content": "import { IPublicTypeJSONValue, IPublicTypeJSExpression, IPublicTypeJSFunction, IPublicTypeJSSlot, IPublicTypeCompositeArray, IPublicTypeCompositeObject } from './';\n\n/**\n * 复合类型\n */\nexport type IPublicTypeCompositeValue = IPublicTypeJSONValue |\n  IPublicTypeJSExpression |\n  IPublicTypeJSFunction |\n  IPublicTypeJSSlot |\n  IPublicTypeCompositeArray |\n  IPublicTypeCompositeObject;\n"
  },
  {
    "path": "packages/types/src/shell/type/config-transducer.ts",
    "content": "import { IPublicTypeSkeletonConfig } from '.';\n\nexport interface IPublicTypeConfigTransducer {\n  (prev: IPublicTypeSkeletonConfig): IPublicTypeSkeletonConfig;\n\n  level?: number;\n\n  id?: string;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/configure.ts",
    "content": "import { IPublicTypeComponentConfigure, ConfigureSupport, IPublicTypeFieldConfig, IPublicTypeAdvanced } from './';\n\n/**\n * 编辑体验配置\n */\nexport interface IPublicTypeConfigure {\n\n  /**\n   * 属性面板配置\n   */\n  props?: IPublicTypeFieldConfig[];\n\n  /**\n   * 组件能力配置\n   */\n  component?: IPublicTypeComponentConfigure;\n\n  /**\n   * 通用扩展面板支持性配置\n   */\n  supports?: ConfigureSupport;\n\n  /**\n   * 高级特性配置\n   */\n  advanced?: IPublicTypeAdvanced;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/container-schema.ts",
    "content": "import { InterpretDataSource as DataSource } from '@alilc/lowcode-datasource-types';\nimport {\n  IPublicTypeJSExpression,\n  IPublicTypeJSFunction,\n  IPublicTypeCompositeObject,\n  IPublicTypeCompositeValue,\n  IPublicTypeNodeSchema,\n} from './';\n\n/**\n * 容器结构描述\n */\nexport interface IPublicTypeContainerSchema extends IPublicTypeNodeSchema {\n  /**\n   * 'Block' | 'Page' | 'Component';\n   */\n  componentName: string;\n  /**\n   * 文件名称\n   */\n  fileName: string;\n  /**\n   * @todo 待文档定义\n   */\n  meta?: Record<string, unknown>;\n  /**\n   * 容器初始数据\n   */\n  state?: {\n    [key: string]: IPublicTypeCompositeValue;\n  };\n  /**\n   * 自定义方法设置\n   */\n  methods?: {\n    [key: string]: IPublicTypeJSExpression | IPublicTypeJSFunction;\n  };\n  /**\n   * 生命周期对象\n   */\n  lifeCycles?: {\n    // @todo 生命周期对象建议改为闭合集合\n    [key: string]: IPublicTypeJSExpression | IPublicTypeJSFunction;\n  };\n  /**\n   * 样式文件\n   */\n  css?: string;\n  /**\n   * 异步数据源配置\n   */\n  dataSource?: DataSource;\n  /**\n   * 低代码业务组件默认属性\n   */\n  defaultProps?: IPublicTypeCompositeObject;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/context-menu.ts",
    "content": "import { IPublicEnumContextMenuType } from '../enum';\nimport { IPublicModelNode } from '../model';\nimport { IPublicTypeI18nData } from './i8n-data';\nimport { IPublicTypeHelpTipConfig } from './widget-base-config';\n\nexport interface IPublicTypeContextMenuItem extends Omit<IPublicTypeContextMenuAction, 'condition' | 'disabled' | 'items'> {\n  disabled?: boolean;\n\n  items?: Omit<IPublicTypeContextMenuItem, 'items'>[];\n}\n\nexport interface IPublicTypeContextMenuAction {\n\n  /**\n   * 动作的唯一标识符\n   * Unique identifier for the action\n   */\n  name: string;\n\n  /**\n   * 显示的标题，可以是字符串或国际化数据\n   * Display title, can be a string or internationalized data\n   */\n  title?: string | IPublicTypeI18nData;\n\n  /**\n   * 菜单项类型\n   * Menu item type\n   * @see IPublicEnumContextMenuType\n   * @default IPublicEnumContextMenuType.MENU_ITEM\n   */\n  type?: IPublicEnumContextMenuType;\n\n  /**\n   * 点击时执行的动作，可选\n   * Action to execute on click, optional\n   */\n  action?: (nodes?: IPublicModelNode[], event?: MouseEvent) => void;\n\n  /**\n   * 子菜单项或生成子节点的函数，可选，仅支持两级\n   * Sub-menu items or function to generate child node, optional\n   */\n  items?: Omit<IPublicTypeContextMenuAction, 'items'>[] | ((nodes?: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]);\n\n  /**\n   * 显示条件函数\n   * Function to determine display condition\n   */\n  condition?: (nodes?: IPublicModelNode[]) => boolean;\n\n  /**\n   * 禁用条件函数，可选\n   * Function to determine disabled condition, optional\n   */\n  disabled?: (nodes?: IPublicModelNode[]) => boolean;\n\n  /**\n   * 帮助提示，可选\n   */\n  help?: IPublicTypeHelpTipConfig;\n}\n\n"
  },
  {
    "path": "packages/types/src/shell/type/custom-view.ts",
    "content": "import { ComponentType, ReactElement } from 'react';\n\nexport type IPublicTypeCustomView = ReactElement | ComponentType<any>;\n"
  },
  {
    "path": "packages/types/src/shell/type/disposable.ts",
    "content": "export interface IPublicTypeDisposable {\n  (): void;\n}"
  },
  {
    "path": "packages/types/src/shell/type/dom-text.ts",
    "content": "export type IPublicTypeDOMText = string;\n"
  },
  {
    "path": "packages/types/src/shell/type/drag-any-object.ts",
    "content": "\nexport interface IPublicTypeDragAnyObject {\n  type: string;\n  [key: string]: any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/drag-node-data-object.ts",
    "content": "import { IPublicTypeNodeSchema } from './';\nimport { IPublicEnumDragObjectType } from '../enum';\n\nexport interface IPublicTypeDragNodeDataObject {\n  type: IPublicEnumDragObjectType.NodeData;\n  data: IPublicTypeNodeSchema | IPublicTypeNodeSchema[];\n  thumbnail?: string;\n  description?: string;\n  [extra: string]: any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/drag-node-object.ts",
    "content": "import { IPublicModelNode } from '..';\nimport { IPublicEnumDragObjectType } from '../enum';\n\nexport interface IPublicTypeDragNodeObject<Node = IPublicModelNode> {\n  type: IPublicEnumDragObjectType.Node;\n  nodes: Node[];\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/drag-object.ts",
    "content": "import { IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject, IPublicTypeDragAnyObject } from './';\n\n// eslint-disable-next-line max-len\nexport type IPublicTypeDragObject = IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject | IPublicTypeDragAnyObject;\n"
  },
  {
    "path": "packages/types/src/shell/type/dynamic-props.ts",
    "content": "import { IPublicModelSettingField } from '../model';\n\nexport type IPublicTypeDynamicProps = (target: IPublicModelSettingField) => Record<string, unknown>;\n"
  },
  {
    "path": "packages/types/src/shell/type/dynamic-setter.ts",
    "content": "import { IPublicModelSettingPropEntry, IPublicTypeCustomView } from '..';\nimport { IPublicTypeSetterConfig } from './setter-config';\n\nexport type IPublicTypeDynamicSetter = (target: IPublicModelSettingPropEntry) => (string | IPublicTypeSetterConfig | IPublicTypeCustomView);\n"
  },
  {
    "path": "packages/types/src/shell/type/editor-get-options.ts",
    "content": "\nexport interface IPublicTypeEditorGetOptions {\n  forceNew?: boolean;\n  sourceCls?: new (...args: any[]) => any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/editor-get-result.ts",
    "content": "\nexport type IPublicTypeEditorGetResult<T, ClsType> = T extends undefined ? ClsType extends {\n  prototype: infer R;\n} ? R : any : T;\n"
  },
  {
    "path": "packages/types/src/shell/type/editor-register-options.ts",
    "content": "/**\n * duck-typed power-di\n *\n * @see https://www.npmjs.com/package/power-di\n */\nexport interface IPublicTypeEditorRegisterOptions {\n\n  /**\n   * default: true\n   */\n  singleton?: boolean;\n\n  /**\n   * if data a class, auto new a instance.\n   * if data a function, auto run(lazy).\n   *  default: true\n   */\n  autoNew?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/editor-value-key.ts",
    "content": "\nexport type IPublicTypeEditorValueKey = (new (...args: any[]) => any) | symbol | string;\n"
  },
  {
    "path": "packages/types/src/shell/type/editor-view-config.ts",
    "content": "export interface IPublicEditorViewConfig {\n\n  /** 视图初始化钩子 */\n  init?: () => Promise<void>;\n\n  /** 资源保存时，会调用视图的钩子 */\n  save?: () => Promise<void>;\n\n  /** viewType 类型为 'webview' 时渲染的地址 */\n  url?: () => Promise<string>;\n}"
  },
  {
    "path": "packages/types/src/shell/type/editor-view.ts",
    "content": "import { IPublicEditorViewConfig } from './editor-view-config';\n\nexport interface IPublicTypeEditorView {\n\n  /** 资源名字 */\n  viewName: string;\n\n  /** 资源类型 */\n  viewType?: 'editor' | 'webview';\n\n  (ctx: any, options: any): IPublicEditorViewConfig;\n}"
  },
  {
    "path": "packages/types/src/shell/type/engine-options.ts",
    "content": "import { RequestHandlersMap } from '@alilc/lowcode-datasource-types';\nimport { ComponentType } from 'react';\n\nexport interface IPublicTypeEngineOptions {\n\n  /**\n   * 是否开启 condition 的能力，默认在设计器中不管 condition 是啥都正常展示\n   * when this is true, node that configured as conditional not renderring\n   * will not display in canvas.\n   * @default false\n   */\n  enableCondition?: boolean;\n\n  /**\n   * TODO: designMode 无法映射到文档渲染模块\n   *\n   * 设计模式，live 模式将会实时展示变量值，默认值：'design'\n   *\n   * @default 'design'\n   * @experimental\n   */\n  designMode?: 'design' | 'live';\n\n  /**\n   * 设备类型，默认值：'default'\n   * @default 'default'\n   */\n  device?: 'default' | 'mobile' | string;\n\n  /**\n   * 指定初始化的 deviceClassName，挂载到画布的顶层节点上\n   */\n  deviceClassName?: string;\n\n  /**\n   * 语言，默认值：'zh-CN'\n   * @default 'zh-CN'\n   */\n  locale?: string;\n\n  /**\n   * 渲染器类型，默认值：'react'\n   */\n  renderEnv?: 'react' | string;\n\n  /**\n   * 设备类型映射器，处理设计器与渲染器中 device 的映射\n   */\n  deviceMapper?: {\n    transform: (originalDevice: string) => string;\n  };\n\n  /**\n   * 开启严格插件模式，默认值：STRICT_PLUGIN_MODE_DEFAULT , 严格模式下，插件将无法通过 engineOptions 传递自定义配置项\n   * enable strict plugin mode, default value: false\n   * under strict mode, customed engineOption is not accepted.\n   */\n  enableStrictPluginMode?: boolean;\n\n  /**\n   * 开启拖拽组件时，即将被放入的容器是否有视觉反馈，默认值：false\n   */\n  enableReactiveContainer?: boolean;\n\n  /**\n   * 关闭画布自动渲染，在资产包多重异步加载的场景有效，默认值：false\n   */\n  disableAutoRender?: boolean;\n\n  /**\n   * 关闭拖拽组件时的虚线响应，性能考虑，默认值：false\n   */\n  disableDetecting?: boolean;\n\n  /**\n   * 定制画布中点击被忽略的 selectors，默认值：undefined\n   */\n  customizeIgnoreSelectors?: (defaultIgnoreSelectors: string[], e: MouseEvent) => string[];\n\n  /**\n   * 禁止默认的设置面板，默认值：false\n   */\n  disableDefaultSettingPanel?: boolean;\n\n  /**\n   * 禁止默认的设置器，默认值：false\n   */\n  disableDefaultSetters?: boolean;\n\n  /**\n   * 打开画布的锁定操作，默认值：false\n   */\n  enableCanvasLock?: boolean;\n\n  /**\n   * 容器锁定后，容器本身是否可以设置属性，仅当画布锁定特性开启时生效，默认值为：false\n   */\n  enableLockedNodeSetting?: boolean;\n\n  /**\n   * 当选中节点切换时，是否停留在相同的设置 tab 上，默认值：false\n   */\n  stayOnTheSameSettingTab?: boolean;\n\n  /**\n   * 是否在只有一个 item 的时候隐藏设置 tabs，默认值：false\n   */\n  hideSettingsTabsWhenOnlyOneItem?: boolean;\n\n  /**\n   * 自定义 loading 组件\n   */\n  loadingComponent?: ComponentType;\n\n  /**\n   * 设置所有属性支持变量配置，默认值：false\n   */\n  supportVariableGlobally?: boolean;\n\n  /**\n   * 设置 simulator 相关的 url，默认值：undefined\n   */\n  simulatorUrl?: string[];\n\n  /**\n   * Vision-polyfill settings\n   * @deprecated this exists for some legacy reasons\n   */\n  visionSettings?: {\n    // 是否禁用降级 reducer，默认值：false\n    disableCompatibleReducer?: boolean;\n    // 是否开启在 render 阶段开启 filter reducer，默认值：false\n    enableFilterReducerInRenderStage?: boolean;\n  };\n\n  /**\n   * 与 react-renderer 的 appHelper 一致，https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper\n   */\n  appHelper?: {\n\n    /** 全局公共函数 */\n    utils?: Record<string, any>;\n\n    /** 全局常量 */\n    constants?: Record<string, any>;\n  };\n\n  /**\n   * 数据源引擎的请求处理器映射\n   */\n  requestHandlersMap?: RequestHandlersMap;\n\n  /**\n   * @default true\n   * JSExpression 是否只支持使用 this 来访问上下文变量，假如需要兼容原来的 'state.xxx'，则设置为 false\n   */\n  thisRequiredInJSE?: boolean;\n\n  /**\n   * @default false\n   * 当开启组件未找到严格模式时，渲染模块不会默认给一个容器组件\n   */\n  enableStrictNotFoundMode?: boolean;\n\n  /**\n   * 配置指定节点为根组件\n   */\n  focusNodeSelector?: (rootNode: Node) => Node;\n\n  /**\n   * 开启应用级设计模式\n   */\n  enableWorkspaceMode?: boolean;\n\n  /**\n   * @default true\n   * 应用级设计模式下，自动打开第一个窗口\n   */\n  enableAutoOpenFirstWindow?: boolean;\n\n  /**\n   * @default false\n   * 开启右键菜单能力\n   */\n  enableContextMenu?: boolean;\n\n  /**\n   * @default false\n   * 隐藏设计器辅助层\n   */\n  hideComponentAction?: boolean;\n}\n\n/**\n * @deprecated use IPublicTypeEngineOptions instead\n */\nexport interface EngineOptions {\n\n}"
  },
  {
    "path": "packages/types/src/shell/type/field-config.ts",
    "content": "import { IPublicTypeTitleContent, IPublicTypeSetterType, IPublicTypeFieldExtraProps, IPublicTypeDynamicSetter } from './';\n\n/**\n * 属性面板配置\n */\nexport interface IPublicTypeFieldConfig extends IPublicTypeFieldExtraProps {\n\n  /**\n   * 面板配置隶属于单个 field 还是分组\n   */\n  type?: 'field' | 'group';\n\n  /**\n   * the name of this setting field, which used in quickEditor\n   */\n  name?: string | number;\n\n  /**\n   * the field title\n   * @default sameas .name\n   */\n  title?: IPublicTypeTitleContent;\n\n  /**\n   * 单个属性的 setter 配置\n   *\n   * the field body contains when .type = 'field'\n   */\n  setter?: IPublicTypeSetterType | IPublicTypeDynamicSetter;\n\n  /**\n   * the setting items which group body contains when .type = 'group'\n   */\n  items?: IPublicTypeFieldConfig[];\n\n  /**\n   * extra props for field\n   * 其他配置属性（不做流通要求）\n   */\n  extraProps?: IPublicTypeFieldExtraProps;\n\n  /**\n   * @deprecated\n   */\n  description?: IPublicTypeTitleContent;\n\n  /**\n   * @deprecated\n   */\n  isExtends?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/field-extra-props.ts",
    "content": "import { IPublicModelSettingField } from '../model';\nimport { IPublicTypeLiveTextEditingConfig } from './';\n\n/**\n * extra props for field\n */\nexport interface IPublicTypeFieldExtraProps {\n\n  /**\n   * 是否必填参数\n   */\n  isRequired?: boolean;\n\n  /**\n   * default value of target prop for setter use\n   */\n  defaultValue?: any;\n\n  /**\n   * get value for field\n   */\n  getValue?: (target: IPublicModelSettingField, fieldValue: any) => any;\n\n  /**\n   * set value for field\n   */\n  setValue?: (target: IPublicModelSettingField, value: any) => void;\n\n  /**\n   * the field conditional show, is not set always true\n   * @default undefined\n   */\n  condition?: (target: IPublicModelSettingField) => boolean;\n\n  /**\n   * 配置当前 prop 是否忽略默认值处理逻辑，如果返回值是 true 引擎不会处理默认值\n   * @returns boolean\n   */\n  ignoreDefaultValue?: (target: IPublicModelSettingField) => boolean;\n\n  /**\n   * autorun when something change\n   */\n  autorun?: (target: IPublicModelSettingField) => void;\n\n  /**\n   * default collapsed when display accordion\n   */\n  defaultCollapsed?: boolean;\n\n  /**\n   * important field\n   */\n  important?: boolean;\n\n  /**\n   * internal use\n   */\n  forceInline?: number;\n\n  /**\n   * 是否支持变量配置\n   */\n  supportVariable?: boolean;\n\n  /**\n   * compatiable vision display\n   */\n  display?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry';\n\n  // @todo 这个 omit 是否合理？\n  /**\n   * @todo 待补充文档\n   */\n  liveTextEditing?: Omit<IPublicTypeLiveTextEditingConfig, 'propTarget'>;\n\n  /**\n   * onChange 事件\n   */\n  onChange?: (value: any, field: IPublicModelSettingField) => void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/hotkey-callback-config.ts",
    "content": "import { IPublicTypeHotkeyCallback } from './';\n\nexport interface IPublicTypeHotkeyCallbackConfig {\n  callback: IPublicTypeHotkeyCallback;\n  modifiers: string[];\n  action: string;\n  seq?: string;\n  level?: number;\n  combo?: string;\n}"
  },
  {
    "path": "packages/types/src/shell/type/hotkey-callback.ts",
    "content": "\nexport type IPublicTypeHotkeyCallback = (e: KeyboardEvent, combo?: string) => any | false;\n"
  },
  {
    "path": "packages/types/src/shell/type/hotkey-callbacks.ts",
    "content": "import { IPublicTypeHotkeyCallbackConfig } from './';\n\nexport interface IPublicTypeHotkeyCallbacks {\n  [key: string]: IPublicTypeHotkeyCallbackConfig[];\n}"
  },
  {
    "path": "packages/types/src/shell/type/i18n-map.ts",
    "content": "\nexport interface IPublicTypeI18nMap {\n  [lang: string]: { [key: string]: string };\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/i8n-data.ts",
    "content": "import { ReactNode } from 'react';\n\nexport interface IPublicTypeI18nData {\n  type: 'i18n';\n  intl?: ReactNode;\n  [key: string]: any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/icon-config.ts",
    "content": "\nexport interface IPublicTypeIconConfig {\n  type: string;\n  size?: number | 'small' | 'xxs' | 'xs' | 'medium' | 'large' | 'xl' | 'xxl' | 'xxxl' | 'inherit';\n  className?: string;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/icon-type.ts",
    "content": "import { ReactElement, ComponentType } from 'react';\nimport { IPublicTypeIconConfig } from './';\n\nexport type IPublicTypeIconType = string | ReactElement | ComponentType<any> | IPublicTypeIconConfig;\n"
  },
  {
    "path": "packages/types/src/shell/type/index.ts",
    "content": "// this folder contains all interfaces/types working as type definition\n//   - some exists as type TypeName\n//   - some althought exists as interfaces , but there won`t be any class implements them.\n// all of above cases will with prefix IPublicType, eg. IPublicTypeSomeName\nexport * from './location';\nexport * from './active-target';\nexport * from './component-instance';\nexport * from './node-schema';\nexport * from './disposable';\nexport * from './assets-json';\nexport * from './metadata-transducer';\nexport * from './component-action';\nexport * from './preference-value-type';\nexport * from './project-schema';\nexport * from './block-schema';\nexport * from './component-schema';\nexport * from './container-schema';\nexport * from './page-schema';\nexport * from './root-schema';\nexport * from './props-transducer';\nexport * from './registered-setter';\nexport * from './custom-view';\nexport * from './widget-base-config';\nexport * from './node-data';\nexport * from './icon-type';\nexport * from './transformed-component-metadata';\nexport * from './i8n-data';\nexport * from './npm-info';\nexport * from './drag-node-data-object';\nexport * from './drag-node-object';\nexport * from './prop-change-options';\nexport * from './drag-any-object';\nexport * from './drag-object';\nexport * from './composite-value';\nexport * from './props-map';\nexport * from './props-list';\nexport * from './plugin-config';\nexport * from './plugin-declaration-property';\nexport * from './plugin-declaration';\nexport * from './plugin-meta';\nexport * from './plugin-creater';\nexport * from './plugin';\nexport * from './setter-type';\nexport * from './set-value-options';\nexport * from './field-config';\nexport * from './field-extra-props';\nexport * from './component-sort';\nexport * from './component-metadata';\nexport * from './reference';\nexport * from './component-description';\nexport * from './remote-component-description';\nexport * from './package';\nexport * from './action-content-object';\nexport * from './title-config';\nexport * from './title-content';\nexport * from './prop-config';\nexport * from './prop-types';\nexport * from './snippet';\nexport * from './advanced';\nexport * from './configure';\nexport * from './value-type';\nexport * from './tip-content';\nexport * from './metadata';\nexport * from './dynamic-setter';\nexport * from './icon-config';\nexport * from './dom-text';\nexport * from './i18n-map';\nexport * from './app-config';\nexport * from './npm';\nexport * from './dynamic-props';\nexport * from './setter-config';\nexport * from './tip-config';\nexport * from './widget-config-area';\nexport * from './hotkey-callback';\nexport * from './plugin-register-options';\nexport * from './resource-list';\nexport * from './engine-options';\nexport * from './on-change-options';\nexport * from './slot-schema';\nexport * from './node-data-type';\nexport * from './node-instance';\nexport * from './editor-value-key';\nexport * from './editor-get-options';\nexport * from './editor-get-result';\nexport * from './editor-register-options';\nexport * from './editor-view';\nexport * from './resource-type';\nexport * from './resource-type-config';\nexport * from './editor-view-config';\nexport * from './hotkey-callback-config';\nexport * from './hotkey-callbacks';\nexport * from './scrollable';\nexport * from './simulator-renderer';\nexport * from './config-transducer';\nexport * from './context-menu';\nexport * from './command';"
  },
  {
    "path": "packages/types/src/shell/type/location.ts",
    "content": "import { IPublicModelNode, IPublicModelLocateEvent } from '../model';\n\n// eslint-disable-next-line no-shadow\nexport enum IPublicTypeLocationDetailType {\n  Children = 'Children',\n  Prop = 'Prop',\n}\n\n/**\n * @deprecated please use IPublicTypeLocationDetailType\n */\nexport enum LocationDetailType {\n  Children = 'Children',\n  Prop = 'Prop',\n}\n\nexport type IPublicTypeRect = DOMRect & {\n  elements?: Array<Element | Text>;\n  computed?: boolean;\n};\n\nexport interface IPublicTypeLocationChildrenDetail {\n  type: IPublicTypeLocationDetailType.Children;\n  index?: number | null;\n\n  /**\n   * 是否有效位置\n   */\n  valid?: boolean;\n  edge?: DOMRect;\n  near?: {\n    node: IPublicModelNode;\n    pos: 'before' | 'after' | 'replace';\n    rect?: IPublicTypeRect;\n    align?: 'V' | 'H';\n  };\n  focus?: { type: 'slots' } | { type: 'node'; node: IPublicModelNode };\n}\n\nexport interface IPublicTypeLocationPropDetail {\n  // cover 形态，高亮 domNode，如果 domNode 为空，取 container 的值\n  type: IPublicTypeLocationDetailType.Prop;\n  name: string;\n  domNode?: HTMLElement;\n}\n\nexport type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { [key: string]: any; type: string };\n\nexport interface IPublicTypeLocationData<\n  Node = IPublicModelNode\n> {\n  target: Node; // shadowNode | ConditionFlow | ElementNode | RootNode\n  detail: IPublicTypeLocationDetail;\n  source: string;\n  event: IPublicModelLocateEvent;\n}"
  },
  {
    "path": "packages/types/src/shell/type/metadata-transducer.ts",
    "content": "import { IPublicTypeTransformedComponentMetadata } from './';\n\n\nexport interface IPublicTypeMetadataTransducer {\n  (prev: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata;\n  /**\n   * 0 - 9   system\n   * 10 - 99 builtin-plugin\n   * 100 -   app & plugin\n   */\n  level?: number;\n  /**\n   * use to replace TODO\n   */\n  id?: string;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/metadata.ts",
    "content": "import { MouseEvent } from 'react';\nimport { IPublicTypePropType, IPublicTypeComponentAction } from './';\nimport { IPublicModelNode, IPublicModelSettingField } from '../model';\n\n/**\n * 嵌套控制函数\n */\nexport type IPublicTypeNestingFilter = (testNode: any, currentNode: any) => boolean;\n\n/**\n * 嵌套控制\n * 防止错误的节点嵌套，比如 a 嵌套 a, FormField 只能在 Form 容器下，Column 只能在 Table 下等\n */\nexport interface IPublicTypeNestingRule {\n\n  /**\n   * 子级白名单\n   */\n  childWhitelist?: string[] | string | RegExp | IPublicTypeNestingFilter;\n\n  /**\n   * 父级白名单\n   */\n  parentWhitelist?: string[] | string | RegExp | IPublicTypeNestingFilter;\n\n  /**\n   * 后裔白名单\n   */\n  descendantWhitelist?: string[] | string | RegExp | IPublicTypeNestingFilter;\n\n  /**\n   * 后裔黑名单\n   */\n  descendantBlacklist?: string[] | string | RegExp | IPublicTypeNestingFilter;\n\n  /**\n   * 祖先白名单 可用来做区域高亮\n   */\n  ancestorWhitelist?: string[] | string | RegExp | IPublicTypeNestingFilter;\n}\n\n/**\n * 组件能力配置\n */\nexport interface IPublicTypeComponentConfigure {\n\n  /**\n   * 是否容器组件\n   */\n  isContainer?: boolean;\n\n  /**\n   * 组件是否带浮层，浮层组件拖入设计器时会遮挡画布区域，此时应当辅助一些交互以防止阻挡\n   */\n  isModal?: boolean;\n\n  /**\n   * 是否存在渲染的根节点\n   */\n  isNullNode?: boolean;\n\n  /**\n   * 组件树描述信息\n   */\n  descriptor?: string;\n\n  /**\n   * 嵌套控制：防止错误的节点嵌套\n   * 比如 a 嵌套 a, FormField 只能在 Form 容器下，Column 只能在 Table 下等\n   */\n  nestingRule?: IPublicTypeNestingRule;\n\n  /**\n   * 是否是最小渲染单元\n   * 最小渲染单元下的组件渲染和更新都从单元的根节点开始渲染和更新。如果嵌套了多层最小渲染单元，渲染会从最外层的最小渲染单元开始渲染。\n   */\n  isMinimalRenderUnit?: boolean;\n\n  /**\n   * 组件选中框的 cssSelector\n   */\n  rootSelector?: string;\n\n  /**\n   * 禁用的行为，可以为 `'copy'`, `'move'`, `'remove'` 或它们组成的数组\n   */\n  disableBehaviors?: string[] | string;\n\n  /**\n   * 用于详细配置上述操作项的内容\n   */\n  actions?: IPublicTypeComponentAction[];\n}\n\nexport interface IPublicTypeInitialItem {\n  name: string;\n  initial: (target: IPublicModelSettingField, currentValue: any) => any;\n}\nexport interface IPublicTypeFilterItem {\n  name: string;\n  filter: (target: IPublicModelSettingField | null, currentValue: any) => any;\n}\nexport interface IPublicTypeAutorunItem {\n  name: string;\n  autorun: (target: IPublicModelSettingField | null) => any;\n}\n\n// thinkof Array\n/**\n * Live Text Editing（如果 children 内容是纯文本，支持双击直接编辑）的可配置项目\n */\nexport interface IPublicTypeLiveTextEditingConfig {\n\n  /**\n   * @todo 待补充文档\n   */\n  propTarget: string;\n\n  /**\n   * @todo 待补充文档\n   */\n  selector?: string;\n\n  /**\n   * 编辑模式 纯文本 | 段落编辑 | 文章编辑（默认纯文本，无跟随工具条）\n   * @default 'plaintext'\n   */\n  mode?: 'plaintext' | 'paragraph' | 'article';\n\n  /**\n   * 从 contentEditable 获取内容并设置到属性\n   */\n  onSaveContent?: (content: string, prop: any) => any;\n}\n\nexport type ConfigureSupportEvent = string | ConfigureSupportEventConfig;\n\nexport interface ConfigureSupportEventConfig {\n  name: string;\n  propType?: IPublicTypePropType;\n  description?: string;\n  template?: string;\n}\n\n/**\n * 通用扩展面板支持性配置\n */\nexport interface ConfigureSupport {\n\n  /**\n   * 支持事件列表\n   */\n  events?: ConfigureSupportEvent[];\n\n  /**\n   * 支持 className 设置\n   */\n  className?: boolean;\n\n  /**\n   * 支持样式设置\n   */\n  style?: boolean;\n\n  /**\n   * 支持生命周期设置\n   */\n  lifecycles?: any[];\n\n  // general?: boolean;\n  /**\n   * 支持循环设置\n   */\n  loop?: boolean;\n\n  /**\n   * 支持条件式渲染设置\n   */\n  condition?: boolean;\n}\n\n/**\n * handleResizing\n */\n\n/**\n * 配置 callbacks 可捕获引擎抛出的一些事件，例如 onNodeAdd、onResize 等\n */\nexport interface IPublicTypeCallbacks {\n  // hooks\n  onMouseDownHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any;\n  onDblClickHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any;\n  onClickHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any;\n  // onLocateHook?: (e: any, currentNode: any) => any;\n  // onAcceptHook?: (currentNode: any, locationData: any) => any;\n  onMoveHook?: (currentNode: IPublicModelNode) => boolean;\n  // thinkof 限制性拖拽\n  onHoverHook?: (currentNode: IPublicModelNode) => boolean;\n\n  /** 选中 hook，如果返回值是 false，可以控制组件不可被选中 */\n  onSelectHook?: (currentNode: IPublicModelNode) => boolean;\n  onChildMoveHook?: (childNode: IPublicModelNode, currentNode: IPublicModelNode) => boolean;\n\n  // events\n  onNodeRemove?: (removedNode: IPublicModelNode | null, currentNode: IPublicModelNode | null) => void;\n  onNodeAdd?: (addedNode: IPublicModelNode | null, currentNode: IPublicModelNode | null) => void;\n  onSubtreeModified?: (currentNode: IPublicModelNode, options: any) => void;\n  onResize?: (\n    e: MouseEvent & {\n      trigger: string;\n      deltaX?: number;\n      deltaY?: number;\n    },\n    currentNode: any,\n  ) => void;\n  onResizeStart?: (\n    e: MouseEvent & {\n      trigger: string;\n      deltaX?: number;\n      deltaY?: number;\n    },\n    currentNode: any,\n  ) => void;\n  onResizeEnd?: (\n    e: MouseEvent & {\n      trigger: string;\n      deltaX?: number;\n      deltaY?: number;\n    },\n    currentNode: IPublicModelNode,\n  ) => void;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/node-data-type.ts",
    "content": "import { IPublicTypeNodeData } from './node-data';\n\nexport type IPublicTypeNodeDataType = IPublicTypeNodeData | IPublicTypeNodeData[];\n"
  },
  {
    "path": "packages/types/src/shell/type/node-data.ts",
    "content": "import { IPublicTypeJSExpression, IPublicTypeNodeSchema, IPublicTypeDOMText, IPublicTypeI18nData } from './';\n\nexport type IPublicTypeNodeData = IPublicTypeNodeSchema | IPublicTypeJSExpression | IPublicTypeDOMText | IPublicTypeI18nData;\n"
  },
  {
    "path": "packages/types/src/shell/type/node-instance.ts",
    "content": "import { IPublicTypeComponentInstance, IPublicModelNode } from '..';\n\nexport interface IPublicTypeNodeInstance<\n  T = IPublicTypeComponentInstance,\n  Node = IPublicModelNode\n> {\n  docId: string;\n  nodeId: string;\n  instance: T;\n  node?: Node | null;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/node-schema.ts",
    "content": "import { IPublicTypeCompositeValue, IPublicTypePropsMap, IPublicTypeNodeData } from './';\n\n// 转换成一个 .jsx 文件内 React Class 类 render 函数返回的 jsx 代码\n/**\n * 搭建基础协议 - 单个组件树节点描述\n */\nexport interface IPublicTypeNodeSchema {\n\n  id?: string;\n\n  /**\n   * 组件名称 必填、首字母大写\n   */\n  componentName: string;\n\n  /**\n   * 组件属性对象\n   */\n  props?: {\n    children?: IPublicTypeNodeData | IPublicTypeNodeData[];\n  } & IPublicTypePropsMap; // | PropsList;\n\n  /**\n   * 渲染条件\n   */\n  condition?: IPublicTypeCompositeValue;\n\n  /**\n   * 循环数据\n   */\n  loop?: IPublicTypeCompositeValue;\n\n  /**\n   * 循环迭代对象、索引名称 [\"item\", \"index\"]\n   */\n  loopArgs?: [string, string];\n\n  /**\n   * 子节点\n   */\n  children?: IPublicTypeNodeData | IPublicTypeNodeData[];\n\n  /**\n   * 是否锁定\n   */\n  isLocked?: boolean;\n\n  // @todo\n  // ------- future support -----\n  conditionGroup?: string;\n  title?: string;\n  ignore?: boolean;\n  locked?: boolean;\n  hidden?: boolean;\n  isTopFixed?: boolean;\n\n  /** @experimental 编辑态内部使用 */\n  __ctx?: any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/npm-info.ts",
    "content": "/**\n * npm 源引入完整描述对象\n */\nexport interface IPublicTypeNpmInfo {\n  /**\n   * 源码组件名称\n   */\n  componentName?: string;\n  /**\n   * 源码组件库名\n   */\n  package: string;\n  /**\n   * 源码组件版本号\n   */\n  version?: string;\n  /**\n   * 是否解构\n   */\n  destructuring?: boolean;\n  /**\n   * 源码组件名称\n   */\n  exportName?: string;\n  /**\n   * 子组件名\n   */\n  subName?: string;\n  /**\n   * 组件路径\n   */\n  main?: string;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/npm.ts",
    "content": "import { IPublicTypeNpmInfo } from './npm-info';\n\nexport interface IPublicTypeLowCodeComponent {\n  /**\n   * 研发模式\n   */\n  devMode: 'lowCode';\n  /**\n   * 组件名称\n   */\n  componentName: string;\n}\n\nexport type IPublicTypeProCodeComponent = IPublicTypeNpmInfo;\nexport type IPublicTypeComponentMap = IPublicTypeProCodeComponent | IPublicTypeLowCodeComponent;\nexport type IPublicTypeComponentsMap = IPublicTypeComponentMap[];\n"
  },
  {
    "path": "packages/types/src/shell/type/on-change-options.ts",
    "content": "import { IPublicModelNode } from '..';\n\nexport interface IPublicTypeOnChangeOptions<\n  Node = IPublicModelNode\n> {\n  type: string;\n  node: Node;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/package.ts",
    "content": "import { EitherOr } from '../../utils';\nimport { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from './';\n\n/**\n * 定义组件大包及 external 资源的信息\n * 应该被编辑器默认加载\n */\nexport type IPublicTypePackage = EitherOr<{\n  /**\n   * npm 包名\n   */\n  package: string;\n  /**\n   * 包唯一标识\n   */\n  id: string;\n  /**\n   * 包版本号\n   */\n  version: string;\n  /**\n   * 组件渲染态视图打包后的 CDN url 列表，包含 js 和 css\n   */\n  urls?: string[] | any;\n  /**\n   * 组件编辑态视图打包后的 CDN url 列表，包含 js 和 css\n   */\n  editUrls?: string[] | any;\n  /**\n   * 作为全局变量引用时的名称，和webpack output.library字段含义一样，用来定义全局变量名\n   */\n  library: string;\n  /**\n   * @experimental\n   *\n   * TODO: 需推进提案 @度城\n   */\n  async?: boolean;\n  /**\n   * 标识当前 package 从其他 package 的导出方式\n   */\n  exportMode?: 'functionCall';\n  /**\n   * 标识当前 package 是从 window 上的哪个属性导出来的\n   */\n  exportSourceLibrary?: any;\n  /**\n   * 组件描述导出名字，可以通过 window[exportName] 获取到组件描述的 Object 内容；\n   */\n  exportName?: string;\n  /**\n   * 低代码组件 schema 内容\n   */\n  schema?: IPublicTypeProjectSchema<IPublicTypeComponentSchema>;\n}, 'package', 'id'>;\n"
  },
  {
    "path": "packages/types/src/shell/type/page-schema.ts",
    "content": "import { IPublicTypeContainerSchema } from './';\n\n/**\n * 页面容器\n * @see https://lowcode-engine.cn/lowcode\n */\nexport interface IPublicTypePageSchema extends IPublicTypeContainerSchema {\n  componentName: 'Page';\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/plugin-config.ts",
    "content": "export interface IPublicTypePluginConfig {\n  init(): Promise<void> | void;\n  destroy?(): Promise<void> | void;\n  exports?(): any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/plugin-creater.ts",
    "content": "import { IPublicTypePluginConfig } from './';\nimport { IPublicModelPluginContext } from '../model';\n\n// eslint-disable-next-line max-len\nexport type IPublicTypePluginCreater = (ctx: IPublicModelPluginContext, options: any) => IPublicTypePluginConfig;\n"
  },
  {
    "path": "packages/types/src/shell/type/plugin-declaration-property.ts",
    "content": "import { IPublicTypePreferenceValueType } from './';\n\nexport interface IPublicTypePluginDeclarationProperty {\n  // shape like 'name' or 'group.name' or 'group.subGroup.name'\n  key: string;\n  // must have either one of description & markdownDescription\n  description: string;\n  // value in 'number', 'string', 'boolean'\n  type: string;\n  // default value\n  // NOTE! this is only used in configuration UI, won`t affect runtime\n  default?: IPublicTypePreferenceValueType;\n  // only works when type === 'string', default value false\n  useMultipleLineTextInput?: boolean;\n  // enum values, only works when type === 'string'\n  enum?: any[];\n  // descriptions for enum values\n  enumDescriptions?: string[];\n  // message that describing deprecation of this property\n  deprecationMessage?: string;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/plugin-declaration.ts",
    "content": "import { IPublicTypePluginDeclarationProperty } from './';\n\n/**\n * declaration of plugin`s preference\n * when strictPluginMode === true， only declared preference can be obtained from inside plugin.\n */\nexport interface IPublicTypePluginDeclaration {\n  // this will be displayed on configuration UI, can be plugin name\n  title: string;\n  properties: IPublicTypePluginDeclarationProperty[];\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/plugin-meta.ts",
    "content": "import { IPublicTypePluginDeclaration } from './';\n\nexport interface IPublicTypePluginMeta {\n\n  /**\n   * define dependencies which the plugin depends on\n   */\n  dependencies?: string[];\n\n  /**\n   * specify which engine version is compatible with the plugin\n   */\n  engines?: {\n\n    /** e.g. '^1.0.0' */\n    lowcodeEngine?: string;\n  };\n  preferenceDeclaration?: IPublicTypePluginDeclaration;\n\n  /**\n   * use 'common' as event prefix when eventPrefix is not set.\n   * strongly recommend using pluginName as eventPrefix\n   *\n   * eg.\n   *   case 1, when eventPrefix is not specified\n   *        event.emit('someEventName') is actually sending event with name 'common:someEventName'\n   *\n   *   case 2, when eventPrefix is 'myEvent'\n   *        event.emit('someEventName') is actually sending event with name 'myEvent:someEventName'\n   */\n  eventPrefix?: string;\n\n  /**\n   * 如果要使用 command 注册命令，需要在插件 meta 中定义 commandScope\n   */\n  commandScope?: string;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/plugin-register-options.ts",
    "content": "\nexport interface IPublicTypePluginRegisterOptions {\n  /**\n   * Will enable plugin registered with auto-initialization immediately\n   * other than plugin-manager init all plugins at certain time.\n   * It is helpful when plugin register is later than plugin-manager initialization.\n   */\n  autoInit?: boolean;\n  /**\n   * allow overriding existing plugin with same name when override === true\n   */\n  override?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/plugin.ts",
    "content": "/* eslint-disable max-len */\nimport { IPublicTypePluginMeta, IPublicTypePluginCreater } from './';\n\nexport interface IPublicTypePlugin extends IPublicTypePluginCreater {\n  pluginName: string;\n  meta?: IPublicTypePluginMeta;\n}"
  },
  {
    "path": "packages/types/src/shell/type/preference-value-type.ts",
    "content": "\nexport type IPublicTypePreferenceValueType = string | number | boolean;\n"
  },
  {
    "path": "packages/types/src/shell/type/project-schema.ts",
    "content": "import { InterpretDataSource as DataSource } from '@alilc/lowcode-datasource-types';\nimport { IPublicTypeJSONObject, IPublicTypeRootSchema, IPublicTypeI18nMap, IPublicTypeAppConfig, IPublicTypeComponentsMap, IPublicTypeJSExpression, IPublicTypeJSFunction, IPublicTypeNpmInfo } from './';\n\nexport interface IPublicTypeInternalUtils {\n  name: string;\n  type: 'function';\n  content: IPublicTypeJSFunction | IPublicTypeJSExpression;\n}\n\nexport interface IPublicTypeExternalUtils {\n  name: string;\n  type: 'npm' | 'tnpm';\n  content: IPublicTypeNpmInfo;\n}\n\nexport type IPublicTypeUtilItem = IPublicTypeInternalUtils | IPublicTypeExternalUtils;\nexport type IPublicTypeUtilsMap = IPublicTypeUtilItem[];\n/**\n * 应用描述\n */\n\nexport interface IPublicTypeProjectSchema<T = IPublicTypeRootSchema> {\n  id?: string;\n  /**\n   * 当前应用协议版本号\n   */\n  version: string;\n  /**\n   * 当前应用所有组件映射关系\n   */\n  componentsMap: IPublicTypeComponentsMap;\n  /**\n   * 描述应用所有页面、低代码组件的组件树\n   * 低代码业务组件树描述\n   * 是长度固定为 1 的数组，即数组内仅包含根容器的描述（低代码业务组件容器类型）\n   */\n  componentsTree: T[];\n  /**\n   * 国际化语料\n   */\n  i18n?: IPublicTypeI18nMap;\n  /**\n   * 应用范围内的全局自定义函数或第三方工具类扩展\n   */\n  utils?: IPublicTypeUtilsMap;\n  /**\n   * 应用范围内的全局常量\n   */\n  constants?: IPublicTypeJSONObject;\n  /**\n   * 应用范围内的全局样式\n   */\n  css?: string;\n  /**\n   * 当前应用的公共数据源\n   */\n  dataSource?: DataSource;\n  /**\n   * 当前应用配置信息\n   *\n   * TODO: 需要在后续版本中移除 `Record<string, unknown>` 类型签名\n   */\n  config?: IPublicTypeAppConfig & Record<string, unknown>;\n  /**\n   * 当前应用元数据信息\n   */\n  meta?: Record<string, any>;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/prop-change-options.ts",
    "content": "import {\n  IPublicModelNode,\n  IPublicModelProp,\n} from '../model';\n\nexport interface IPublicTypePropChangeOptions<\n  Node = IPublicModelNode\n> {\n  key?: string | number;\n  prop?: IPublicModelProp;\n  node: Node;\n  newValue: any;\n  oldValue: any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/prop-config.ts",
    "content": "import { IPublicTypePropType } from './';\n\n/**\n * 组件属性信息\n */\nexport interface IPublicTypePropConfig {\n  /**\n   * 属性名称\n   */\n  name: string;\n  /**\n   * 属性类型\n   */\n  propType: IPublicTypePropType;\n  /**\n   * 属性描述\n   */\n  description?: string;\n  /**\n   * 属性默认值\n   */\n  defaultValue?: any;\n  /**\n   * @deprecated 已被弃用\n   */\n  setter?: any;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/prop-types.ts",
    "content": "/* eslint-disable max-len */\nimport { IPublicTypePropConfig } from './';\n\nexport type IPublicTypePropType = IPublicTypeBasicType | IPublicTypeRequiredType | IPublicTypeComplexType;\nexport type IPublicTypeBasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any';\nexport type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact | IPublicTypeInstanceOf;\n\nexport interface IPublicTypeRequiredType {\n  type: IPublicTypeBasicType;\n  isRequired?: boolean;\n}\n\nexport interface IPublicTypeOneOf {\n  type: 'oneOf';\n  value: string[];\n  isRequired?: boolean;\n}\nexport interface IPublicTypeOneOfType {\n  type: 'oneOfType';\n  value: IPublicTypePropType[];\n  isRequired?: boolean;\n}\nexport interface IPublicTypeArrayOf {\n  type: 'arrayOf';\n  value: IPublicTypePropType;\n  isRequired?: boolean;\n}\nexport interface IPublicTypeObjectOf {\n  type: 'objectOf';\n  value: IPublicTypePropType;\n  isRequired?: boolean;\n}\nexport interface IPublicTypeShape {\n  type: 'shape';\n  value: IPublicTypePropConfig[];\n  isRequired?: boolean;\n}\nexport interface IPublicTypeExact {\n  type: 'exact';\n  value: IPublicTypePropConfig[];\n  isRequired?: boolean;\n}\n\nexport interface IPublicTypeInstanceOf {\n  type: 'instanceOf';\n  value: IPublicTypePropConfig;\n  isRequired?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/props-list.ts",
    "content": "import { IPublicTypeCompositeValue } from './';\n\nexport type IPublicTypePropsList = Array<{\n  spread?: boolean;\n  name?: string;\n  value: IPublicTypeCompositeValue;\n}>;\n"
  },
  {
    "path": "packages/types/src/shell/type/props-map.ts",
    "content": "import { IPublicTypeCompositeObject, IPublicTypeNodeData } from './';\n\nexport type IPublicTypePropsMap = IPublicTypeCompositeObject<IPublicTypeNodeData | IPublicTypeNodeData[]>;\n"
  },
  {
    "path": "packages/types/src/shell/type/props-transducer.ts",
    "content": "import { IPublicEnumTransformStage } from '../enum';\nimport { IPublicModelNode } from '../model';\nimport { IPublicTypeCompositeObject } from './';\n\nexport type IPublicTypePropsTransducer = (\n  props: IPublicTypeCompositeObject,\n  node: IPublicModelNode,\n  ctx?: {\n    stage: IPublicEnumTransformStage;\n  },\n) => IPublicTypeCompositeObject;\n"
  },
  {
    "path": "packages/types/src/shell/type/reference.ts",
    "content": "import { EitherOr } from '../../utils';\n\n/**\n * 资源引用信息，Npm 的升级版本，\n */\nexport type IPublicTypeReference = EitherOr<{\n  /**\n   * 引用资源的 id 标识\n   */\n  id: string;\n  /**\n   * 引用资源的包名\n   */\n  package: string;\n  /**\n   * 引用资源的导出对象中的属性值名称\n   */\n  exportName: string;\n  /**\n   * 引用 exportName 上的子对象\n   */\n  subName: string;\n  /**\n   * 引用的资源主入口\n   */\n  main?: string;\n  /**\n   * 是否从引用资源的导出对象中获取属性值\n   */\n  destructuring?: boolean;\n  /**\n   * 资源版本号\n   */\n  version: string;\n}, 'package', 'id'>;\n"
  },
  {
    "path": "packages/types/src/shell/type/registered-setter.ts",
    "content": "import { IPublicModelSettingField } from '../model';\nimport { IPublicTypeCustomView, IPublicTypeTitleContent } from './';\n\nexport interface IPublicTypeRegisteredSetter {\n  component: IPublicTypeCustomView;\n  defaultProps?: object;\n  title?: IPublicTypeTitleContent;\n\n  /**\n   * for MixedSetter to check this setter if available\n   */\n  condition?: (field: IPublicModelSettingField) => boolean;\n\n  /**\n   * for MixedSetter to manual change to this setter\n   */\n  initialValue?: any | ((field: IPublicModelSettingField) => any);\n  recommend?: boolean;\n  // 标识是否为动态 setter，默认为 true\n  isDynamic?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/remote-component-description.ts",
    "content": "import { Asset } from '../../assets';\nimport { IPublicTypeComponentMetadata, IPublicTypeReference } from './';\n\n/**\n * 远程物料描述\n */\nexport interface IPublicTypeRemoteComponentDescription extends IPublicTypeComponentMetadata {\n\n  /**\n   * 组件描述导出名字，可以通过 window[exportName] 获取到组件描述的 Object 内容；\n   */\n  exportName?: string;\n\n  /**\n   * 组件描述的资源链接；\n   */\n  url?: Asset;\n\n  /**\n   * 组件 (库) 的 npm 信息；\n   */\n  package?: {\n    npm?: string;\n  };\n\n  /**\n   * 替代 npm 字段的升级版本\n   */\n  reference?: IPublicTypeReference;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/resource-list.ts",
    "content": "import { ReactElement } from 'react';\n\nexport interface IPublicResourceData {\n\n  /** 资源名字 */\n  resourceName: string;\n\n  /** 资源扩展配置 */\n  config?: {\n    [key: string]: any;\n  };\n\n  /** 资源标题 */\n  title?: string;\n\n  /** 资源 Id */\n  id?: string;\n\n  /** 分类 */\n  category?: string;\n\n  /** 资源视图 */\n  viewName?: string;\n\n  /** 资源 icon */\n  icon?: ReactElement;\n\n  /** 资源其他配置，资源初始化时的第二个参数 */\n  options: {\n    [key: string]: any;\n  };\n\n  /** 资源子元素 */\n  children?: IPublicResourceData[];\n}\n\nexport type IPublicResourceList = IPublicResourceData[];"
  },
  {
    "path": "packages/types/src/shell/type/resource-type-config.ts",
    "content": "import React from 'react';\nimport { IPublicTypeEditorView } from './editor-view';\n\nexport interface IPublicResourceTypeConfig {\n\n  /** 资源描述 */\n  description?: string;\n\n  /** 资源 icon 标识 */\n  icon?: React.ReactElement | React.FunctionComponent | React.ComponentClass;\n\n  /**\n   * 默认视图类型\n   * @deprecated\n   */\n  defaultViewType?: string;\n\n  /** 默认视图类型 */\n  defaultViewName: string;\n\n  /** 资源视图 */\n  editorViews: IPublicTypeEditorView[];\n\n  init?: () => void;\n\n  /** save 钩子 */\n  save?: (schema: {\n    [viewName: string]: any;\n  }) => Promise<void>;\n\n  /** import 钩子 */\n  import?: (schema: any) => Promise<{\n    [viewName: string]: any;\n  }>;\n\n  /** 默认标题 */\n  defaultTitle?: string;\n\n  /** resourceType 类型为 'webview' 时渲染的地址 */\n  url?: () => Promise<string>;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/resource-type.ts",
    "content": "import { IPublicModelPluginContext } from '../model';\nimport { IPublicResourceTypeConfig } from './resource-type-config';\n\nexport interface IPublicTypeResourceType {\n  resourceName: string;\n\n  resourceType: 'editor' | 'webview' | string;\n\n  (ctx: IPublicModelPluginContext, options: Object): IPublicResourceTypeConfig;\n}"
  },
  {
    "path": "packages/types/src/shell/type/root-schema.ts",
    "content": "import { IPublicTypePageSchema, IPublicTypeComponentSchema, IPublicTypeBlockSchema } from './';\n\n/**\n * @todo\n */\n// eslint-disable-next-line max-len\nexport type IPublicTypeRootSchema = IPublicTypePageSchema | IPublicTypeComponentSchema | IPublicTypeBlockSchema;\n"
  },
  {
    "path": "packages/types/src/shell/type/scrollable.ts",
    "content": "import { IPublicModelScrollTarget } from '../model';\n\nexport interface IPublicTypeScrollable {\n  scrollTarget?: IPublicModelScrollTarget | Element;\n  bounds?: DOMRect | null;\n  scale?: number;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/set-value-options.ts",
    "content": "import { IPublicEnumPropValueChangedType } from '../enum';\n\nexport interface IPublicTypeSetValueOptions {\n  disableMutator?: boolean;\n  type?: IPublicEnumPropValueChangedType;\n  fromSetHotValue?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/setter-config.ts",
    "content": "import { IPublicTypeCustomView, IPublicTypeCompositeValue, IPublicTypeTitleContent, IPublicModelSettingField } from '..';\nimport { IPublicTypeDynamicProps } from './dynamic-props';\n\n/**\n * 设置器配置\n */\nexport interface IPublicTypeSetterConfig {\n\n  // if *string* passed must be a registered Setter Name\n  /**\n   * 配置设置器用哪一个 setter\n   */\n  componentName: string | IPublicTypeCustomView;\n\n  /**\n   * 传递给 setter 的属性\n   *\n   * the props pass to Setter Component\n   */\n  props?: Record<string, unknown> | IPublicTypeDynamicProps;\n\n  /**\n   * @deprecated\n   */\n  children?: any;\n\n  /**\n   * 是否必填？\n   *\n   * ArraySetter 里有个快捷预览，可以在不打开面板的情况下直接编辑\n   */\n  isRequired?: boolean;\n\n  /**\n   * Setter 的初始值\n   *\n   * @todo initialValue 可能要和 defaultValue 二选一\n   */\n  initialValue?: any | ((target: IPublicModelSettingField) => any);\n\n  defaultValue?: any;\n\n  // for MixedSetter\n  /**\n   * 给 MixedSetter 时切换 Setter 展示用的\n   */\n  title?: IPublicTypeTitleContent;\n\n  // for MixedSetter check this is available\n  /**\n   * 给 MixedSetter 用于判断优先选中哪个\n   */\n  condition?: (target: IPublicModelSettingField) => boolean;\n\n  /**\n   * 给 MixedSetter，切换值时声明类型\n   *\n   * @todo 物料协议推进\n   */\n  valueType?: IPublicTypeCompositeValue[];\n\n  // 标识是否为动态 setter，默认为 true\n  isDynamic?: boolean;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/setter-type.ts",
    "content": "import { IPublicTypeCustomView, IPublicTypeSetterConfig } from './';\n\n// if *string* passed must be a registered Setter Name, future support blockSchema\n\n// eslint-disable-next-line max-len\nexport type IPublicTypeSetterType = IPublicTypeSetterConfig | IPublicTypeSetterConfig[] | string | IPublicTypeCustomView;\n"
  },
  {
    "path": "packages/types/src/shell/type/simulator-renderer.ts",
    "content": "import { Asset } from '../../assets';\nimport {\n  IPublicTypeNodeInstance,\n  IPublicTypeProjectSchema,\n  IPublicTypeComponentSchema,\n} from './';\n\nexport interface IPublicTypeSimulatorRenderer<Component, ComponentInstance> {\n  readonly isSimulatorRenderer: true;\n  autoRepaintNode?: boolean;\n  components: Record<string, Component>;\n  rerender: () => void;\n  createComponent(\n    schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>,\n  ): Component | null;\n  getComponent(componentName: string): Component;\n  getClosestNodeInstance(\n    from: ComponentInstance,\n    nodeId?: string,\n  ): IPublicTypeNodeInstance<ComponentInstance> | null;\n  findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null;\n  getClientRects(element: Element | Text): DOMRect[];\n  setNativeSelection(enableFlag: boolean): void;\n  setDraggingState(state: boolean): void;\n  setCopyState(state: boolean): void;\n  loadAsyncLibrary(asyncMap: { [index: string]: any }): void;\n  clearState(): void;\n  stopAutoRepaintNode(): void;\n  enableAutoRepaintNode(): void;\n  run(): void;\n  load(asset: Asset): Promise<any>;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/slot-schema.ts",
    "content": "import { IPublicTypeNodeData } from './node-data';\nimport { IPublicTypeNodeSchema } from './node-schema';\n\n/**\n * Slot schema 描述\n */\nexport interface IPublicTypeSlotSchema extends IPublicTypeNodeSchema {\n  componentName: 'Slot';\n  name?: string;\n  title?: string;\n  params?: string[];\n  props?: {\n    slotTitle?: string;\n    slotName?: string;\n    slotParams?: string[];\n  };\n  children?: IPublicTypeNodeData[] | IPublicTypeNodeData;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/snippet.ts",
    "content": "import { IPublicTypeNodeSchema } from './';\n\n/**\n * 可用片段\n *\n * 内容为组件不同状态下的低代码 schema (可以有多个)，用户从组件面板拖入组件到设计器时会向页面 schema 中插入 snippets 中定义的组件低代码 schema\n */\nexport interface IPublicTypeSnippet {\n  /**\n   * 组件分类 title\n   */\n  title?: string;\n  /**\n   * snippet 截图\n   */\n  screenshot?: string;\n  /**\n   * snippet 打标\n   *\n   * @deprecated 暂未使用\n   */\n  label?: string;\n  /**\n   * 待插入的 schema\n   */\n  schema?: IPublicTypeNodeSchema;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/tip-config.ts",
    "content": "import { IPublicTypeI18nData } from '..';\nimport { ReactNode } from 'react';\n\nexport interface IPublicTypeTipConfig {\n\n  /**\n   * className\n   */\n  className?: string;\n\n  /**\n   * tip 的内容\n   */\n  children?: IPublicTypeI18nData | ReactNode;\n  theme?: string;\n\n  /**\n   * tip 的方向\n   */\n  direction?: 'top' | 'bottom' | 'left' | 'right';\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/tip-content.ts",
    "content": "import { IPublicTypeI18nData } from '..';\nimport { ReactNode } from 'react';\nimport { IPublicTypeTipConfig } from './tip-config';\n\nexport type TipContent = string | IPublicTypeI18nData | ReactNode | IPublicTypeTipConfig;\n"
  },
  {
    "path": "packages/types/src/shell/type/title-config.ts",
    "content": "import { ReactNode } from 'react';\nimport { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, TipContent } from './';\n\nexport interface IPublicTypeTitleProps {\n\n  /**\n   * 标题内容\n   */\n  title: IPublicTypeTitleContent;\n\n  /**\n   * className\n   */\n  className?: string;\n\n  /**\n   * 点击事件\n   */\n  onClick?: () => void;\n  match?: boolean;\n  keywords?: string;\n}\n\n/**\n * 描述 props 的 setter title\n */\nexport interface IPublicTypeTitleConfig {\n\n  /**\n   * 文字描述\n   */\n  label?: IPublicTypeI18nData | ReactNode;\n\n  /**\n   * hover 后的展现内容\n   */\n  tip?: TipContent;\n\n  /**\n   * 文档链接，暂未实现\n   */\n  docUrl?: string;\n\n  /**\n   * 图标\n   */\n  icon?: IPublicTypeIconType;\n\n  /**\n   * CSS 类\n   */\n  className?: string;\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/title-content.ts",
    "content": "import { ReactElement, ReactNode } from 'react';\nimport { IPublicTypeI18nData, IPublicTypeTitleConfig } from './';\n\n// eslint-disable-next-line max-len\nexport type IPublicTypeTitleContent = string | IPublicTypeI18nData | ReactElement | ReactNode | IPublicTypeTitleConfig;"
  },
  {
    "path": "packages/types/src/shell/type/transformed-component-metadata.ts",
    "content": "import { IPublicTypeComponentMetadata, IPublicTypeFieldConfig, IPublicTypeConfigure } from './';\n\n/**\n * @todo 待补充文档\n */\nexport interface IPublicTypeTransformedComponentMetadata extends IPublicTypeComponentMetadata {\n  configure: IPublicTypeConfigure & { combined?: IPublicTypeFieldConfig[] };\n}\n"
  },
  {
    "path": "packages/types/src/shell/type/value-type.ts",
    "content": "import { IPublicTypeNodeData, IPublicTypeCompositeValue, IPublicTypeNodeSchema } from './';\n\n/**\n * 变量表达式\n *\n * 表达式内通过 this 对象获取上下文\n */\nexport interface IPublicTypeJSExpression {\n  type: 'JSExpression';\n\n  /**\n   * 表达式字符串\n   */\n  value: string;\n\n  /**\n   * 模拟值\n   *\n   * @todo 待标准描述\n   */\n  mock?: any;\n\n  /**\n   * 源码\n   *\n   * @todo 待标准描述\n   */\n  compiled?: string;\n}\n\n/**\n * 事件函数类型\n * @see https://lowcode-engine.cn/lowcode\n *\n * 保留与原组件属性、生命周期 ( React / 小程序) 一致的输入参数，并给所有事件函数 binding 统一一致的上下文（当前组件所在容器结构的 this 对象）\n */\nexport interface IPublicTypeJSFunction {\n  type: 'JSFunction';\n\n  /**\n   * 函数定义，或直接函数表达式\n   */\n  value: string;\n\n  /**\n   * 源码\n   *\n   * @todo 待标准描述\n   */\n  compiled?: string;\n\n  /**\n   * 模拟值\n   *\n   * @todo 待标准描述\n   */\n  mock?: any;\n\n  /**\n   * 额外扩展属性，如 extType、events\n   *\n   * @todo 待标准描述\n   */\n  [key: string]: any;\n}\n\n/**\n * Slot 函数类型\n *\n * 通常用于描述组件的某一个属性为 ReactNode 或 Function return ReactNode 的场景。\n */\nexport interface IPublicTypeJSSlot {\n\n  /**\n   * type\n   */\n  type: 'JSSlot';\n\n  /**\n   * @todo 待标准描述\n   */\n  title?: string;\n\n  /**\n   * @todo 待标准描述\n   */\n  id?: string;\n\n  /**\n   * 组件的某一个属性为 Function return ReactNode 时，函数的入参\n   *\n   * 其子节点可以通过 this[参数名] 来获取对应的参数。\n   */\n  params?: string[];\n\n  /**\n   * 具体的值。\n   */\n  value?: IPublicTypeNodeData[] | IPublicTypeNodeData;\n\n  /**\n   * @todo 待标准描述\n   */\n  name?: string;\n}\n\n/**\n * @deprecated\n *\n * @todo 待文档描述\n */\nexport interface IPublicTypeJSBlock {\n  type: 'JSBlock';\n  value: IPublicTypeNodeSchema;\n}\n\n/**\n * JSON 基本类型\n */\nexport type IPublicTypeJSONValue =\n  | boolean\n  | string\n  | number\n  | null\n  | undefined\n  | IPublicTypeJSONArray\n  | IPublicTypeJSONObject;\nexport type IPublicTypeJSONArray = IPublicTypeJSONValue[];\nexport interface IPublicTypeJSONObject {\n  [key: string]: IPublicTypeJSONValue;\n}\n\nexport type IPublicTypeCompositeArray = IPublicTypeCompositeValue[];\nexport interface IPublicTypeCompositeObject<T = IPublicTypeCompositeValue> {\n  [key: string]: IPublicTypeCompositeValue | T;\n}"
  },
  {
    "path": "packages/types/src/shell/type/widget-base-config.ts",
    "content": "import { ReactElement, ComponentType } from 'react';\nimport { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './';\n\nexport type IPublicTypeHelpTipConfig = string | { url?: string; content?: string | ReactElement };\n\nexport interface IPublicTypePanelConfigProps extends IPublicTypePanelDockPanelProps {\n  title?: IPublicTypeTitleContent;\n  icon?: any; // 冗余字段\n  description?: string | IPublicTypeI18nData;\n  help?: IPublicTypeHelpTipConfig; // 显示问号帮助\n  hiddenWhenInit?: boolean; //  when this is true, by default will be hidden\n  condition?: (widget: any) => any;\n  onInit?: (widget: any) => any;\n  onDestroy?: () => any;\n  shortcut?: string; // 只有在特定位置，可触发 toggle show\n  enableDrag?: boolean; // 是否开启通过 drag 调整 宽度\n  keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态\n}\n\nexport interface IPublicTypePanelConfig extends IPublicTypeWidgetBaseConfig {\n  type: 'Panel';\n  content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; // as children\n  props?: IPublicTypePanelConfigProps;\n}\n\nexport interface IPublicTypeWidgetBaseConfig {\n  [extra: string]: any;\n  type: string;\n  name: string;\n\n  /**\n   * 停靠位置：\n   * - 当 type 为 'Panel' 时自动为 'leftFloatArea'；\n   * - 当 type 为 'Widget' 时自动为 'mainArea'；\n   * - 其他时候自动为 'leftArea'；\n   */\n  area?: IPublicTypeWidgetConfigArea;\n  props?: Record<string, any>;\n  content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[];\n  contentProps?: Record<string, any>;\n\n  /**\n   * 优先级，值越小，优先级越高，优先级高的会排在前面\n   */\n  index?: number;\n}\n\nexport interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig {\n  type: 'PanelDock';\n\n  panelProps?: IPublicTypePanelDockPanelProps;\n\n  props?: IPublicTypePanelDockProps;\n\n  /** 面板 name, 当没有 props.title 时, 会使用 name 作为标题 */\n  name: string;\n}\n\nexport interface IPublicTypePanelDockProps {\n  [key: string]: any;\n\n  size?: 'small' | 'medium' | 'large';\n\n  className?: string;\n\n  /** 详细描述，hover 时在标题上方显示的 tips 内容 */\n  description?: TipContent;\n\n  onClick?: () => void;\n\n  /**\n   * 面板标题前的 icon\n   */\n  icon?: IPublicTypeIconType;\n\n  /**\n   * 面板标题\n   */\n  title?: IPublicTypeTitleContent;\n}\n\nexport interface IPublicTypePanelDockPanelProps {\n  [key: string]: any;\n\n  /** 是否隐藏面板顶部条 */\n  hideTitleBar?: boolean;\n\n  width?: number;\n\n  height?: number;\n\n  maxWidth?: number;\n\n  maxHeight?: number;\n\n  area?: IPublicTypeWidgetConfigArea;\n}\n\nexport type IPublicTypeSkeletonConfig = IPublicTypePanelDockConfig | IPublicTypeWidgetBaseConfig;"
  },
  {
    "path": "packages/types/src/shell/type/widget-config-area.ts",
    "content": "/**\n * 所有可能的停靠位置\n */\nexport type IPublicTypeWidgetConfigArea = 'leftArea' | 'left' | 'rightArea' |\n  'right' | 'topArea' | 'subTopArea' | 'top' |\n  'toolbar' | 'mainArea' | 'main' |\n  'center' | 'centerArea' | 'bottomArea' |\n  'bottom' | 'leftFixedArea' |\n  'leftFloatArea' | 'stages';\n"
  },
  {
    "path": "packages/types/src/shell-model-factory.ts",
    "content": "import { IPublicModelNode, IPublicModelSettingField } from './shell';\n\nexport interface IShellModelFactory {\n  // TODO: 需要给 innerNode 提供一个 interface 并用在这里\n  createNode(node: any | null | undefined): IPublicModelNode | null;\n  // TODO: 需要给 InnerSettingField 提供一个 interface 并用在这里\n\n  createSettingField(prop: any): IPublicModelSettingField;\n}\n"
  },
  {
    "path": "packages/types/src/utils.ts",
    "content": "\ntype FilterOptional<T> = Pick<\n  T,\n  Exclude<\n    {\n      [K in keyof T]: T extends Record<K, T[K]> ? K : never;\n    }[keyof T],\n    undefined\n  >\n>;\n\ntype FilterNotOptional<T> = Pick<\n  T,\n  Exclude<\n    {\n      [K in keyof T]: T extends Record<K, T[K]> ? never : K;\n    }[keyof T],\n    undefined\n  >\n>;\n\ntype PartialEither<T, K extends keyof any> = { [P in Exclude<keyof FilterOptional<T>, K>]-?: T[P] } &\n  { [P in Exclude<keyof FilterNotOptional<T>, K>]?: T[P] } &\n  { [P in Extract<keyof T, K>]?: undefined };\n\ntype Object = {\n  [name: string]: any;\n};\n\nexport type EitherOr<O extends Object, L extends string, R extends string> =\n  (\n    PartialEither<Pick<O, L | R>, L> |\n    PartialEither<Pick<O, L | R>, R>\n  ) & Omit<O, L | R>;\n"
  },
  {
    "path": "packages/types/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "packages/utils/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\"\n  ]\n}\n"
  },
  {
    "path": "packages/utils/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/utils/jest.config.js",
    "content": "const fs = require('fs');\nconst { join } = require('path');\nconst pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));\n\nconst jestConfig = {\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: false,\n  collectCoverageFrom: [\n    'src/**/*.ts',\n    '!src/**/*.d.ts',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n  setupFilesAfterEnv: ['./jest.setup.js'],\n};\n\n// 只对本仓库内的 pkg 做 mapping\njestConfig.moduleNameMapper = {};\njestConfig.moduleNameMapper[`^@alilc/lowcode\\\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';\n\nmodule.exports = jestConfig;"
  },
  {
    "path": "packages/utils/jest.setup.js",
    "content": "import '@testing-library/jest-dom';\n"
  },
  {
    "path": "packages/utils/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-utils\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Utils for Ali lowCode engine\",\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"scripts\": {\n    \"test\": \"build-scripts test --config build.test.json --jest-coverage\",\n    \"build\": \"build-scripts build\"\n  },\n  \"dependencies\": {\n    \"@alifd/next\": \"^1.19.16\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"lodash\": \"^4.17.21\",\n    \"mobx\": \"^6.3.0\",\n    \"prop-types\": \"^15.8.1\",\n    \"react\": \"^16\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.18\",\n    \"@testing-library/jest-dom\": \"^6.1.4\",\n    \"@testing-library/react\": \"^11.2.7\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\",\n    \"react-dom\": \"^16.14.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/utils\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/utils/src/app-helper.ts",
    "content": "import EventEmitter from 'events';\n\nlet instance: AppHelper | null = null;\n\nEventEmitter.defaultMaxListeners = 100;\n\nexport class AppHelper extends EventEmitter {\n  static getInstance = () => {\n    if (!instance) {\n      instance = new AppHelper();\n    }\n    return instance;\n  };\n\n  [key: string]: any;\n\n  constructor(config?: Record<string, any>) {\n    super();\n    instance = this;\n    Object.assign(this, config);\n  }\n\n  get(key: string) {\n    return this[key];\n  }\n\n  set(key: any, val: any) {\n    if (typeof key === 'string') {\n      this[key] = val;\n    } else if (typeof key === 'object') {\n      Object.keys(key).forEach((item) => {\n        this[item] = key[item];\n      });\n    }\n  }\n\n  batchOn(events: Array<string | symbol>, listener: (...args: any[]) => void) {\n    if (!Array.isArray(events)) return;\n    events.forEach((event) => this.on(event, listener));\n  }\n\n  batchOnce(events: Array<string | symbol>, listener: (...args: any[]) => void) {\n    if (!Array.isArray(events)) return;\n    events.forEach((event) => this.once(event, listener));\n  }\n\n  batchOff(events: Array<string | symbol>, listener: (...args: any[]) => void) {\n    if (!Array.isArray(events)) return;\n    events.forEach((event) => this.off(event, listener));\n  }\n}\n"
  },
  {
    "path": "packages/utils/src/asset.ts",
    "content": "import { AssetType, AssetLevels, AssetLevel } from '@alilc/lowcode-types';\nimport type { AssetItem, Asset, AssetList, AssetBundle, IPublicTypeAssetsJson } from '@alilc/lowcode-types';\nimport { isCSSUrl } from './is-css-url';\nimport { createDefer } from './create-defer';\nimport { load, evaluate } from './script';\n\n// API 向下兼容\nexport { AssetType, AssetLevels, AssetLevel } from '@alilc/lowcode-types';\nexport type { AssetItem, Asset, AssetList, AssetBundle, IPublicTypeAssetsJson } from '@alilc/lowcode-types';\n\nexport function isAssetItem(obj: any): obj is AssetItem {\n  return obj && obj.type;\n}\n\nexport function isAssetBundle(obj: any): obj is AssetBundle {\n  return obj && obj.type === AssetType.Bundle;\n}\n\nexport function assetBundle(\n    assets?: Asset | AssetList | null,\n    level?: AssetLevel,\n  ): AssetBundle | null {\n  if (!assets) {\n    return null;\n  }\n  return {\n    type: AssetType.Bundle,\n    assets,\n    level,\n  };\n}\n\n/*\nurls: \"view.js,view2 <device selector>, view3 <device selector>\",\nurls: [\n  \"view.js\",\n  \"view.js *\",\n  \"view1.js mobile|pc\",\n  \"view2.js <device selector>\"\n] */\nexport function assetItem(type: AssetType, content?: string | null, level?: AssetLevel, id?: string): AssetItem | null {\n  if (!content) {\n    return null;\n  }\n  return {\n    type,\n    content,\n    level,\n    id,\n  };\n}\n\nexport function mergeAssets(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson): IPublicTypeAssetsJson {\n  if (incrementalAssets.packages) {\n    assets.packages = [...(assets.packages || []), ...incrementalAssets.packages];\n  }\n\n  if (incrementalAssets.components) {\n    assets.components = [...(assets.components || []), ...incrementalAssets.components];\n  }\n\n  mergeAssetsComponentList(assets, incrementalAssets, 'componentList');\n  mergeAssetsComponentList(assets, incrementalAssets, 'bizComponentList');\n\n  return assets;\n}\n\nfunction mergeAssetsComponentList(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson, listName: keyof IPublicTypeAssetsJson): void {\n  if (incrementalAssets[listName]) {\n    if (assets[listName]) {\n      // 根据title进行合并\n      incrementalAssets[listName]?.map((item) => {\n        let matchFlag = false;\n        assets[listName]?.map((assetItem) => {\n          if (assetItem.title === item.title) {\n            assetItem.children = assetItem.children.concat(item.children);\n            matchFlag = true;\n          }\n\n          return assetItem;\n        });\n\n        !matchFlag && assets[listName]?.push(item);\n        return item;\n      });\n    }\n  }\n}\n\nexport class StylePoint {\n  private lastContent: string | undefined;\n\n  private lastUrl: string | undefined;\n\n  private placeholder: Element | Text;\n\n  readonly level: number;\n\n  readonly id: string;\n\n  constructor(level: number, id?: string) {\n    this.level = level;\n    if (id) {\n      this.id = id;\n    }\n    let placeholder: any;\n    if (id) {\n      placeholder = document.head.querySelector(`style[data-id=\"${id}\"]`);\n    }\n    if (!placeholder) {\n      placeholder = document.createTextNode('');\n      const meta = document.head.querySelector(`meta[level=\"${level}\"]`);\n      if (meta) {\n        document.head.insertBefore(placeholder, meta);\n      } else {\n        document.head.appendChild(placeholder);\n      }\n    }\n    this.placeholder = placeholder;\n  }\n\n  applyText(content: string) {\n    if (this.lastContent === content) {\n      return;\n    }\n    this.lastContent = content;\n    this.lastUrl = undefined;\n    const element = document.createElement('style');\n    element.setAttribute('type', 'text/css');\n    if (this.id) {\n      element.setAttribute('data-id', this.id);\n    }\n    element.appendChild(document.createTextNode(content));\n    document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null);\n    document.head.removeChild(this.placeholder);\n    this.placeholder = element;\n  }\n\n  applyUrl(url: string) {\n    if (this.lastUrl === url) {\n      return;\n    }\n    this.lastContent = undefined;\n    this.lastUrl = url;\n    const element = document.createElement('link');\n    element.onload = onload;\n    element.onerror = onload;\n\n    const i = createDefer();\n    function onload(e: any) {\n      element.onload = null;\n      element.onerror = null;\n      if (e.type === 'load') {\n        i.resolve();\n      } else {\n        i.reject();\n      }\n    }\n\n    element.href = url;\n    element.rel = 'stylesheet';\n    if (this.id) {\n      element.setAttribute('data-id', this.id);\n    }\n    document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null);\n    document.head.removeChild(this.placeholder);\n    this.placeholder = element;\n    return i.promise();\n  }\n}\n\nfunction parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) {\n  for (const asset of assets) {\n    parseAsset(scripts, styles, asset, level);\n  }\n}\n\nfunction parseAsset(scripts: any, styles: any, asset: Asset | undefined | null, level?: AssetLevel) {\n  if (!asset) {\n    return;\n  }\n  if (Array.isArray(asset)) {\n    return parseAssetList(scripts, styles, asset, level);\n  }\n\n  if (isAssetBundle(asset)) {\n    if (asset.assets) {\n      if (Array.isArray(asset.assets)) {\n        parseAssetList(scripts, styles, asset.assets, asset.level || level);\n      } else {\n        parseAsset(scripts, styles, asset.assets, asset.level || level);\n      }\n      return;\n    }\n    return;\n  }\n\n  if (!isAssetItem(asset)) {\n    asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!;\n  }\n\n  let lv = asset.level || level;\n\n  if (!lv || AssetLevel[lv] == null) {\n    lv = AssetLevel.App;\n  }\n\n  asset.level = lv;\n  if (asset.type === AssetType.CSSUrl || asset.type == AssetType.CSSText) {\n    styles[lv].push(asset);\n  } else {\n    scripts[lv].push(asset);\n  }\n}\n\nexport class AssetLoader {\n  private stylePoints = new Map<string, StylePoint>();\n\n  async load(asset: Asset) {\n    const styles: any = {};\n    const scripts: any = {};\n    AssetLevels.forEach(lv => {\n      styles[lv] = [];\n      scripts[lv] = [];\n    });\n    parseAsset(scripts, styles, asset);\n    const styleQueue: AssetItem[] = styles[AssetLevel.Environment].concat(\n      styles[AssetLevel.Library],\n      styles[AssetLevel.Theme],\n      styles[AssetLevel.Runtime],\n      styles[AssetLevel.App],\n    );\n    const scriptQueue: AssetItem[] = scripts[AssetLevel.Environment].concat(\n      scripts[AssetLevel.Library],\n      scripts[AssetLevel.Theme],\n      scripts[AssetLevel.Runtime],\n      scripts[AssetLevel.App],\n    );\n    await Promise.all(\n      styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)),\n    );\n    await Promise.all(scriptQueue.map(({ content, type, scriptType }) => this.loadScript(content, type === AssetType.JSUrl, scriptType)));\n  }\n\n  private loadStyle(content: string | undefined | null, level: AssetLevel, isUrl?: boolean, id?: string) {\n    if (!content) {\n      return;\n    }\n    let point: StylePoint | undefined;\n    if (id) {\n      point = this.stylePoints.get(id);\n      if (!point) {\n        point = new StylePoint(level, id);\n        this.stylePoints.set(id, point);\n      }\n    } else {\n      point = new StylePoint(level);\n    }\n    return isUrl ? point.applyUrl(content) : point.applyText(content);\n  }\n\n  private loadScript(content: string | undefined | null, isUrl?: boolean, scriptType?: string) {\n    if (!content) {\n      return;\n    }\n    return isUrl ? load(content, scriptType) : evaluate(content, scriptType);\n  }\n\n  // todo 补充类型\n  async loadAsyncLibrary(asyncLibraryMap: Record<string, any>) {\n    const promiseList: any[] = [];\n    const libraryKeyList: any[] = [];\n    const pkgs: any[] = [];\n    for (const key in asyncLibraryMap) {\n      // 需要异步加载\n      if (asyncLibraryMap[key].async) {\n        promiseList.push(window[asyncLibraryMap[key].library]);\n        libraryKeyList.push(asyncLibraryMap[key].library);\n        pkgs.push(asyncLibraryMap[key]);\n      }\n    }\n    await Promise.all(promiseList).then((mods) => {\n      if (mods.length > 0) {\n        mods.map((item, index) => {\n          const { exportMode, exportSourceLibrary, library } = pkgs[index];\n          window[libraryKeyList[index]] =\n            exportMode === 'functionCall' &&\n            (exportSourceLibrary == null || exportSourceLibrary === library)\n              ? item()\n              : item;\n          return item;\n        });\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "packages/utils/src/build-components.ts",
    "content": "import { ComponentType, forwardRef, createElement, FunctionComponent } from 'react';\nimport { IPublicTypeNpmInfo, IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { isESModule } from './is-es-module';\nimport { isReactComponent, acceptsRef, wrapReactClass } from './is-react';\nimport { isObject } from './is-object';\nimport { isLowcodeProjectSchema } from './check-types';\nimport { isComponentSchema } from './check-types/is-component-schema';\n\ntype Component = ComponentType<any> | object;\ninterface LibraryMap {\n  [key: string]: string;\n}\n\nexport function accessLibrary(library: string | Record<string, unknown>) {\n  if (typeof library !== 'string') {\n    return library;\n  }\n\n  return (window as any)[library] || generateHtmlComp(library);\n}\n\nexport function generateHtmlComp(library: string) {\n  if (['a', 'img', 'div', 'span', 'svg'].includes(library)) {\n    return forwardRef((props, ref) => {\n      return createElement(library, { ref, ...props }, props.children);\n    });\n  }\n}\n\nexport function getSubComponent(library: any, paths: string[]) {\n  const l = paths.length;\n  if (l < 1 || !library) {\n    return library;\n  }\n  let i = 0;\n  let component: any;\n  while (i < l) {\n    const key = paths[i]!;\n    let ex: any;\n    try {\n      component = library[key] || component;\n    } catch (e) {\n      ex = e;\n      component = null;\n    }\n    if (i === 0 && component == null && key === 'default') {\n      if (ex) {\n        return l === 1 ? library : null;\n      }\n      component = library;\n    } else if (component == null) {\n      return null;\n    }\n    library = component;\n    i++;\n  }\n  return component;\n}\n\nfunction findComponent(libraryMap: LibraryMap, componentName: string, npm?: IPublicTypeNpmInfo) {\n  if (!npm) {\n    return accessLibrary(componentName);\n  }\n  // libraryName the key access to global\n  // export { exportName } from xxx exportName === global.libraryName.exportName\n  // export exportName from xxx   exportName === global.libraryName.default || global.libraryName\n  // export { exportName as componentName } from package\n  // if exportName == null exportName === componentName;\n  // const componentName = exportName.subName, if exportName empty subName donot use\n  const exportName = npm.exportName || npm.componentName || componentName;\n  const libraryName = libraryMap[npm.package] || exportName;\n  const library = accessLibrary(libraryName);\n  const paths = npm.exportName && npm.subName ? npm.subName.split('.') : [];\n  if (npm.destructuring) {\n    paths.unshift(exportName);\n  } else if (isESModule(library)) {\n    paths.unshift('default');\n  }\n  return getSubComponent(library, paths);\n}\n\n/**\n * 判断是否是一个混合组件，即 components 是一个对象，对象值是 React 组件\n * 示例：\n * {\n *    Button: ReactNode,\n *    Text: ReactNode,\n * }\n */\nfunction isMixinComponent(components: any) {\n  if (!isObject(components)) {\n    return false;\n  }\n\n  return Object.keys(components).some(componentName => isReactComponent(components[componentName]));\n}\n\nexport function buildComponents(libraryMap: LibraryMap,\n  componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema },\n  createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null) {\n  const components: any = {};\n  Object.keys(componentsMap).forEach((componentName) => {\n    let component = componentsMap[componentName];\n    if (component && (isLowcodeProjectSchema(component) || isComponentSchema(component))) {\n      if (isComponentSchema(component)) {\n        components[componentName] = createComponent({\n          version: '',\n          componentsMap: [],\n          componentsTree: [component],\n        });\n      } else {\n        components[componentName] = createComponent(component);\n      }\n    } else if (isReactComponent(component)) {\n      if (!acceptsRef(component)) {\n        component = wrapReactClass(component as FunctionComponent);\n      }\n      components[componentName] = component;\n    } else if (isMixinComponent(component)) {\n      components[componentName] = component;\n    } else {\n      component = findComponent(libraryMap, componentName, component);\n      if (component) {\n        if (!acceptsRef(component) && isReactComponent(component)) {\n          component = wrapReactClass(component as FunctionComponent);\n        }\n        components[componentName] = component;\n      }\n    }\n  });\n  return components;\n}\n\nexport interface UtilsMetadata {\n  name: string;\n  npm: {\n    package: string;\n    version?: string;\n    exportName: string;\n    subName?: string;\n    destructuring?: boolean;\n    main?: string;\n  };\n}\n\ninterface LibrayMap {\n  [key: string]: string;\n}\n\ninterface ProjectUtils {\n  [packageName: string]: any;\n}\nexport function getProjectUtils(librayMap: LibrayMap, utilsMetadata: UtilsMetadata[]): ProjectUtils {\n  const projectUtils: ProjectUtils = {};\n  if (utilsMetadata) {\n    utilsMetadata.forEach(meta => {\n      if (librayMap[meta?.npm?.package]) {\n        const lib = accessLibrary(librayMap[meta?.npm.package]);\n        if (lib?.destructuring) {\n          Object.keys(lib).forEach(name => {\n            if (name === 'destructuring') return;\n            projectUtils[name] = lib[name];\n          });\n        } else if (meta.name) {\n          projectUtils[meta.name] = lib;\n        }\n      }\n    });\n  }\n  return projectUtils;\n}"
  },
  {
    "path": "packages/utils/src/check-prop-types.ts",
    "content": "import * as ReactIs from 'react-is';\nimport { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret';\nimport { default as factoryWithTypeCheckers } from 'prop-types/factoryWithTypeCheckers';\nimport { IPublicTypePropType } from '@alilc/lowcode-types';\nimport { isRequiredPropType } from './check-types/is-required-prop-type';\nimport { Logger } from './logger';\n\nconst PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true);\nconst logger = new Logger({ level: 'warn', bizName: 'utils' });\n\nexport function transformPropTypesRuleToString(rule: IPublicTypePropType | string): string {\n  if (!rule) {\n    return 'PropTypes.any';\n  }\n\n  if (typeof rule === 'string') {\n    return rule.startsWith('PropTypes.') ? rule : `PropTypes.${rule}`;\n  }\n\n  if (isRequiredPropType(rule)) {\n    const { type, isRequired } = rule;\n    return `PropTypes.${type}${isRequired ? '.isRequired' : ''}`;\n  }\n\n  const { type, value } = rule;\n  switch (type) {\n    case 'oneOf':\n      return `PropTypes.oneOf([${value.map((item: any) => `\"${item}\"`).join(',')}])`;\n    case 'oneOfType':\n      return `PropTypes.oneOfType([${value.map((item: any) => transformPropTypesRuleToString(item)).join(', ')}])`;\n    case 'arrayOf':\n    case 'objectOf':\n      return `PropTypes.${type}(${transformPropTypesRuleToString(value)})`;\n    case 'shape':\n    case 'exact':\n      return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`;\n    default:\n      logger.error(`Unknown prop type: ${type}`);\n  }\n\n  return 'PropTypes.any';\n}\n\nexport function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean {\n  let ruleFunction = rule;\n  if (typeof rule === 'object') {\n    // eslint-disable-next-line no-new-func\n    ruleFunction = new Function(`\"use strict\"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2);\n  }\n  if (typeof rule === 'string') {\n    // eslint-disable-next-line no-new-func\n    ruleFunction = new Function(`\"use strict\"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2);\n  }\n  if (!ruleFunction || typeof ruleFunction !== 'function') {\n    logger.warn('checkPropTypes should have a function type rule argument');\n    return true;\n  }\n  const err = ruleFunction(\n    {\n      [name]: value,\n    },\n    name,\n    componentName,\n    'prop',\n    null,\n    ReactPropTypesSecret,\n  );\n  if (err) {\n    logger.warn(err);\n  }\n  return !err;\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/index.ts",
    "content": "// 此模块存放 @alilc/lowcode-types 中类型相关判断工具\nexport * from './is-action-content-object';\nexport * from './is-custom-view';\nexport * from './is-dom-text';\nexport * from './is-dynamic-setter';\nexport * from './is-i18n-data';\nexport * from './is-jsblock';\nexport * from './is-jsexpression';\nexport * from './is-isfunction';\nexport * from './is-jsslot';\nexport * from './is-lowcode-component-type';\nexport * from './is-node-schema';\nexport * from './is-procode-component-type';\nexport * from './is-project-schema';\nexport * from './is-setter-config';\nexport * from './is-title-config';\nexport * from './is-drag-node-data-object';\nexport * from './is-drag-node-object';\nexport * from './is-drag-any-object';\nexport * from './is-location-children-detail';\nexport * from './is-node';\nexport * from './is-location-data';\nexport * from './is-setting-field';\nexport * from './is-lowcode-component-type';\nexport * from './is-lowcode-project-schema';\nexport * from './is-component-schema';\nexport * from './is-basic-prop-type';\nexport * from './is-required-prop-type';"
  },
  {
    "path": "packages/utils/src/check-types/is-action-content-object.ts",
    "content": "import { IPublicTypeActionContentObject } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject {\n  return isObject(obj);\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-basic-prop-type.ts",
    "content": "import { IPublicTypeBasicType, IPublicTypePropType } from '@alilc/lowcode-types';\n\nexport function isBasicPropType(propType: IPublicTypePropType): propType is IPublicTypeBasicType {\n  if (!propType) {\n    return false;\n  }\n  return typeof propType === 'string';\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-component-schema.ts",
    "content": "import { IPublicTypeComponentSchema } from \"@alilc/lowcode-types\";\n\nexport function isComponentSchema(schema: any): schema is IPublicTypeComponentSchema {\n  if (typeof schema === 'object') {\n    return schema.componentName === 'Component';\n  }\n  return false\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-custom-view.ts",
    "content": "import { isValidElement } from 'react';\nimport { isReactComponent } from '../is-react';\nimport { IPublicTypeCustomView } from '@alilc/lowcode-types';\n\nexport function isCustomView(obj: any): obj is IPublicTypeCustomView {\n  if (!obj) {\n    return false;\n  }\n  return isValidElement(obj) || isReactComponent(obj);\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-dom-text.ts",
    "content": "export function isDOMText(data: any): data is string {\n  return typeof data === 'string';\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-drag-any-object.ts",
    "content": "import { IPublicEnumDragObjectType } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isDragAnyObject(obj: any): boolean {\n  if (!isObject(obj)) {\n    return false;\n  }\n  return obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node;\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-drag-node-data-object.ts",
    "content": "import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject {\n  if (!isObject(obj)) {\n    return false;\n  }\n  return obj.type === IPublicEnumDragObjectType.NodeData;\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-drag-node-object.ts",
    "content": "import { IPublicEnumDragObjectType, IPublicModelNode, IPublicTypeDragNodeObject } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isDragNodeObject<Node = IPublicModelNode>(obj: any): obj is IPublicTypeDragNodeObject<Node> {\n  if (!isObject(obj)) {\n    return false;\n  }\n  return obj.type === IPublicEnumDragObjectType.Node;\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-dynamic-setter.ts",
    "content": "import { isFunction } from '../is-function';\nimport { isReactClass } from '../is-react';\nimport { IPublicTypeDynamicSetter } from '@alilc/lowcode-types';\n\nexport function isDynamicSetter(obj: any): obj is IPublicTypeDynamicSetter {\n  if (!isFunction(obj)) {\n    return false;\n  }\n  return !isReactClass(obj);\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-function.ts",
    "content": "export function isFunction(obj: any): obj is Function {\n  return obj && typeof obj === 'function';\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-i18n-data.ts",
    "content": "import { IPublicTypeI18nData } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isI18nData(obj: any): obj is IPublicTypeI18nData {\n  if (!isObject(obj)) {\n    return false;\n  }\n  return obj.type === 'i18n';\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-isfunction.ts",
    "content": "import { IPublicTypeJSFunction } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\ninterface InnerJsFunction {\n  type: 'JSExpression';\n  source: string;\n  value: string;\n  extType: 'function';\n}\n\n/**\n *  内部版本 的 { type: 'JSExpression', source: '', value: '', extType: 'function' } 能力上等同于 JSFunction\n */\nexport function isInnerJsFunction(data: any): data is InnerJsFunction {\n  if (!isObject(data)) {\n    return false;\n  }\n  return data.type === 'JSExpression' && data.extType === 'function';\n}\n\nexport function isJSFunction(data: any): data is IPublicTypeJSFunction {\n  if (!isObject(data)) {\n    return false;\n  }\n  return data.type === 'JSFunction' || isInnerJsFunction(data);\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-jsblock.ts",
    "content": "import { IPublicTypeJSBlock } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isJSBlock(data: any): data is IPublicTypeJSBlock {\n  if (!isObject(data)) {\n    return false;\n  }\n  return data.type === 'JSBlock';\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-jsexpression.ts",
    "content": "import { IPublicTypeJSExpression } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\n/**\n * 为了避免把 { type: 'JSExpression', extType: 'function' } 误判为表达式，故增加如下逻辑。\n *\n * 引擎中关于函数的表达：\n *  开源版本：{ type: 'JSFunction', source: '', value: '' }\n *  内部版本：{ type: 'JSExpression', source: '', value: '', extType: 'function' }\n *  能力是对标的，不过开源的 react-renderer 只认识第一种，而内部只识别第二种（包括 Java 代码、RE）。\n * @param data\n * @returns\n */\nexport function isJSExpression(data: any): data is IPublicTypeJSExpression {\n  if (!isObject(data)) {\n    return false;\n  }\n  return data.type === 'JSExpression' && data.extType !== 'function';\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-jsslot.ts",
    "content": "import { IPublicTypeJSSlot } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isJSSlot(data: any): data is IPublicTypeJSSlot {\n  if (!isObject(data)) {\n    return false;\n  }\n  return data.type === 'JSSlot';\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-location-children-detail.ts",
    "content": "import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isLocationChildrenDetail(obj: any): obj is IPublicTypeLocationChildrenDetail {\n  if (!isObject(obj)) {\n    return false;\n  }\n  return obj.type === IPublicTypeLocationDetailType.Children;\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-location-data.ts",
    "content": "import { IPublicTypeLocationData } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isLocationData(obj: any): obj is IPublicTypeLocationData {\n  if (!isObject(obj)) {\n    return false;\n  }\n  return 'target' in obj && 'detail' in obj;\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-lowcode-component-type.ts",
    "content": "import { isProCodeComponentType } from './is-procode-component-type';\nimport { IPublicTypeComponentMap, IPublicTypeLowCodeComponent } from '@alilc/lowcode-types';\n\n\nexport function isLowCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeLowCodeComponent {\n  return !isProCodeComponentType(desc);\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-lowcode-project-schema.ts",
    "content": "import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { isComponentSchema } from './is-component-schema';\nimport { isObject } from '../is-object';\n\nexport function isLowcodeProjectSchema(data: any): data is IPublicTypeProjectSchema<IPublicTypeComponentSchema> {\n  if (!isObject(data)) {\n    return false;\n  }\n\n  if (!('componentsTree' in data) || data.componentsTree.length === 0) {\n    return false;\n  }\n\n  return isComponentSchema(data.componentsTree[0]);\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-node-schema.ts",
    "content": "import { IPublicTypeNodeSchema } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isNodeSchema(data: any): data is IPublicTypeNodeSchema {\n  if (!isObject(data)) {\n    return false;\n  }\n  return 'componentName' in data && !data.isNode;\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-node.ts",
    "content": "import { IPublicModelNode } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isNode<Node = IPublicModelNode>(node: any): node is Node {\n  if (!isObject(node)) {\n    return false;\n  }\n  return node.isNode;\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-object.ts",
    "content": "export function isObject(obj: any): boolean {\n  return obj && typeof obj === 'object';\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-procode-component-type.ts",
    "content": "import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent {\n  if (!isObject(desc)) {\n    return false;\n  }\n\n  return 'package' in desc;\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-project-schema.ts",
    "content": "import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isProjectSchema(data: any): data is IPublicTypeProjectSchema {\n  if (!isObject(data)) {\n    return false;\n  }\n  return 'componentsTree' in data;\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-required-prop-type.ts",
    "content": "import { IPublicTypePropType, IPublicTypeRequiredType } from '@alilc/lowcode-types';\n\nexport function isRequiredPropType(propType: IPublicTypePropType): propType is IPublicTypeRequiredType {\n  if (!propType) {\n    return false;\n  }\n  return typeof propType === 'object' && propType.type && ['array', 'bool', 'func', 'number', 'object', 'string', 'node', 'element', 'any'].includes(propType.type);\n}"
  },
  {
    "path": "packages/utils/src/check-types/is-setter-config.ts",
    "content": "import { IPublicTypeSetterConfig } from '@alilc/lowcode-types';\nimport { isCustomView } from './is-custom-view';\nimport { isObject } from '../is-object';\n\nexport function isSetterConfig(obj: any): obj is IPublicTypeSetterConfig {\n  if (!isObject(obj)) {\n    return false;\n  }\n  return 'componentName' in obj && !isCustomView(obj);\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-setting-field.ts",
    "content": "import { IPublicModelSettingField } from '@alilc/lowcode-types';\nimport { isObject } from '../is-object';\n\nexport function isSettingField(obj: any): obj is IPublicModelSettingField {\n  if (!isObject(obj)) {\n    return false;\n  }\n\n  return 'isSettingField' in obj && obj.isSettingField;\n}\n"
  },
  {
    "path": "packages/utils/src/check-types/is-title-config.ts",
    "content": "import { IPublicTypeTitleConfig } from '@alilc/lowcode-types';\nimport { isI18nData } from './is-i18n-data';\nimport { isPlainObject } from '../is-plain-object';\n\nexport function isTitleConfig(obj: any): obj is IPublicTypeTitleConfig {\n  return isPlainObject(obj) && !isI18nData(obj);\n}\n"
  },
  {
    "path": "packages/utils/src/clone-deep.ts",
    "content": "import { isPlainObject } from './is-plain-object';\n\nexport function cloneDeep(src: any): any {\n  const type = typeof src;\n\n  let data: any;\n  if (src === null || src === undefined) {\n    data = src;\n  } else if (Array.isArray(src)) {\n    data = src.map(item => cloneDeep(item));\n  } else if (type === 'object' && isPlainObject(src)) {\n    data = {};\n    for (const key in src) {\n      // eslint-disable-next-line no-prototype-builtins\n      if (src.hasOwnProperty(key)) {\n        data[key] = cloneDeep(src[key]);\n      }\n    }\n  } else {\n    data = src;\n  }\n\n  return data;\n}\n"
  },
  {
    "path": "packages/utils/src/clone-enumerable-property.ts",
    "content": "const excludePropertyNames = [\n  '$$typeof',\n  'render',\n  'defaultProps',\n  'props',\n  'length',\n  'prototype',\n  'name',\n  'caller',\n  'callee',\n  'arguments',\n];\n\nexport function cloneEnumerableProperty(target: any, origin: any, excludes = excludePropertyNames) {\n  const compExtraPropertyNames = Object.keys(origin).filter(d => !excludes.includes(d));\n\n  compExtraPropertyNames.forEach((d: string) => {\n    (target as any)[d] = origin[d];\n  });\n\n  return target;\n}\n"
  },
  {
    "path": "packages/utils/src/context-menu.scss",
    "content": ".engine-context-menu-tree-wrap {\n  position: relative;\n  padding: 4px 10px 4px 32px;\n}\n\n.engine-context-menu-tree-children {\n  margin-left: 8px;\n  line-height: 24px;\n}\n\n.engine-context-menu-item {\n  .engine-context-menu-text {\n    color: var(--color-context-menu-text, var(--color-text));\n    display: flex;\n    align-items: center;\n\n    .lc-help-tip {\n      margin-left: 4px;\n      opacity: 0.8;\n    }\n  }\n\n  &.disabled {\n    &:hover .engine-context-menu-text, .engine-context-menu-text {\n      color: var(--color-context-menu-text-disabled, var(--color-text-disabled));\n    }\n  }\n\n  &:hover {\n    .engine-context-menu-text {\n      color: var(--color-context-menu-text-hover, var(--color-title));\n    }\n  }\n}\n\n.engine-context-menu-title {\n  color: var(--color-context-menu-text, var(--color-text));\n  cursor: pointer;\n\n  &:hover {\n    background-color: var(--color-block-background-light);\n    color: var(--color-title);\n  }\n}\n\n.engine-context-menu-tree-selecte-icon {\n  position: absolute;\n  left: 10px;\n  color: var(--color-icon-active);\n}"
  },
  {
    "path": "packages/utils/src/context-menu.tsx",
    "content": "import { Menu, Icon } from '@alifd/next';\nimport { IPublicEnumContextMenuType, IPublicModelNode, IPublicModelPluginContext, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '@alilc/lowcode-types';\nimport { Logger } from '@alilc/lowcode-utils';\nimport classNames from 'classnames';\nimport React from 'react';\nimport './context-menu.scss';\n\nconst logger = new Logger({ level: 'warn', bizName: 'utils' });\nconst { Item, Divider, PopupItem } = Menu;\n\nconst MAX_LEVEL = 2;\n\ninterface IOptions {\n  nodes?: IPublicModelNode[] | null;\n  destroy?: Function;\n  pluginContext: IPublicModelPluginContext;\n}\n\nconst Tree = (props: {\n  node?: IPublicModelNode | null;\n  children?: React.ReactNode;\n  options: IOptions;\n}) => {\n  const { node } = props;\n\n  if (!node) {\n    return (\n      <div className=\"engine-context-menu-tree-wrap\">{ props.children }</div>\n    );\n  }\n\n  const { common } = props.options.pluginContext || {};\n  const { intl } = common?.utils || {};\n  const indent = node.zLevel * 8 + 32;\n  const style = {\n    paddingLeft: indent,\n    marginLeft: -indent,\n    marginRight: -10,\n    paddingRight: 10,\n  };\n\n  return (\n    <Tree {...props} node={node.parent} >\n      <div\n        className=\"engine-context-menu-title\"\n        onClick={() => {\n          props.options.destroy?.();\n          node.select();\n        }}\n        style={style}\n      >\n        {props.options.nodes?.[0].id === node.id ? (<Icon className=\"engine-context-menu-tree-selecte-icon\" size=\"small\" type=\"success\" />) : null}\n        {intl(node.title)}\n      </div>\n      <div\n        className=\"engine-context-menu-tree-children\"\n      >\n        { props.children }\n      </div>\n    </Tree>\n  );\n};\n\nlet destroyFn: Function | undefined;\n\nexport function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: IOptions): React.ReactNode[] {\n  const { common, commonUI } = options.pluginContext || {};\n  const { intl = (title: any) => title } = common?.utils || {};\n  const { HelpTip } = commonUI || {};\n\n  const children: React.ReactNode[] = [];\n  menus.forEach((menu, index) => {\n    if (menu.type === IPublicEnumContextMenuType.SEPARATOR) {\n      children.push(<Divider key={menu.name || index} />);\n      return;\n    }\n\n    if (menu.type === IPublicEnumContextMenuType.MENU_ITEM) {\n      if (menu.items && menu.items.length) {\n        children.push((\n          <PopupItem\n            className={classNames('engine-context-menu-item', {\n              disabled: menu.disabled,\n            })}\n            key={menu.name}\n            label={<div className=\"engine-context-menu-text\">{intl(menu.title)}</div>}\n          >\n            <Menu className=\"next-context engine-context-menu\">\n              { parseContextMenuAsReactNode(menu.items, options) }\n            </Menu>\n          </PopupItem>\n        ));\n      } else {\n        children.push((\n          <Item\n            className={classNames('engine-context-menu-item', {\n              disabled: menu.disabled,\n            })}\n            disabled={menu.disabled}\n            onClick={() => {\n              menu.action?.();\n            }}\n            key={menu.name}\n          >\n            <div className=\"engine-context-menu-text\">\n              { menu.title ? intl(menu.title) : null }\n              { menu.help ? <HelpTip size=\"xs\" help={menu.help} direction=\"right\" /> : null }\n            </div>\n          </Item>\n        ));\n      }\n    }\n\n    if (menu.type === IPublicEnumContextMenuType.NODE_TREE) {\n      children.push((\n        <Tree node={options.nodes?.[0]} options={options} />\n      ));\n    }\n  });\n\n  return children;\n}\n\nexport function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: IOptions & {\n  event?: MouseEvent;\n}, level = 1): IPublicTypeContextMenuItem[] {\n  destroyFn?.();\n\n  const { nodes, destroy } = options;\n  if (level > MAX_LEVEL) {\n    logger.warn('context menu level is too deep, please check your context menu config');\n    return [];\n  }\n\n  return menus\n    .filter(menu => !menu.condition || (menu.condition && menu.condition(nodes || [])))\n    .map((menu) => {\n      const {\n        name,\n        title,\n        type = IPublicEnumContextMenuType.MENU_ITEM,\n        help,\n      } = menu;\n\n      const result: IPublicTypeContextMenuItem = {\n        name,\n        title,\n        type,\n        help,\n        action: () => {\n          destroy?.();\n          menu.action?.(nodes || [], options.event);\n        },\n        disabled: menu.disabled && menu.disabled(nodes || []) || false,\n      };\n\n      if ('items' in menu && menu.items) {\n        result.items = parseContextMenuProperties(\n          typeof menu.items === 'function' ? menu.items(nodes || []) : menu.items,\n          options,\n          level + 1,\n        );\n      }\n\n      return result;\n    })\n    .reduce((menus: IPublicTypeContextMenuItem[], currentMenu: IPublicTypeContextMenuItem) => {\n      if (!currentMenu.name) {\n        return menus.concat([currentMenu]);\n      }\n\n      const index = menus.find(item => item.name === currentMenu.name);\n      if (!index) {\n        return menus.concat([currentMenu]);\n      } else {\n        return menus;\n      }\n    }, []);\n}\n\nlet cachedMenuItemHeight: string | undefined;\n\nfunction getMenuItemHeight() {\n  if (cachedMenuItemHeight) {\n    return cachedMenuItemHeight;\n  }\n  const root = document.documentElement;\n  const styles = getComputedStyle(root);\n  const menuItemHeight = styles.getPropertyValue('--context-menu-item-height').trim();\n  cachedMenuItemHeight = menuItemHeight;\n\n  return menuItemHeight;\n}\n\nexport function createContextMenu(children: React.ReactNode[], {\n  event,\n  offset = [0, 0],\n}: {\n  event: MouseEvent | React.MouseEvent;\n  offset?: [number, number];\n}) {\n  event.preventDefault();\n  event.stopPropagation();\n\n  const viewportWidth = window.innerWidth;\n  const viewportHeight = window.innerHeight;\n  const dividerCount = React.Children.count(children.filter(child => React.isValidElement(child) && child.type === Divider));\n  const popupItemCount = React.Children.count(children.filter(child => React.isValidElement(child) && (child.type === PopupItem || child.type === Item)));\n  const menuHeight = popupItemCount * parseInt(getMenuItemHeight(), 10) + dividerCount * 8 + 16;\n  const menuWidthLimit = 200;\n  let x = event.clientX + offset[0];\n  let y = event.clientY + offset[1];\n  if (x + menuWidthLimit > viewportWidth) {\n    x = x - menuWidthLimit;\n  }\n  if (y + menuHeight > viewportHeight) {\n    y = y - menuHeight;\n  }\n\n  const menuInstance = Menu.create({\n    target: document.body,\n    offset: [x, y],\n    children,\n    className: 'engine-context-menu',\n  });\n\n  destroyFn = (menuInstance as any).destroy;\n\n  return destroyFn;\n}"
  },
  {
    "path": "packages/utils/src/create-content.ts",
    "content": "import { ReactNode, ComponentType, isValidElement, cloneElement, createElement } from 'react';\nimport { isReactComponent } from './is-react';\n\nexport function createContent(\n    content: ReactNode | ComponentType<any>,\n    props?: Record<string, unknown>,\n  ): ReactNode {\n  if (isValidElement(content)) {\n    return props ? cloneElement(content, props) : content;\n  }\n  if (isReactComponent(content)) {\n    return createElement(content, props);\n  }\n\n  return content;\n}\n"
  },
  {
    "path": "packages/utils/src/create-defer.ts",
    "content": "export interface Defer<T = any> {\n  resolve(value?: T | PromiseLike<T>): void;\n  reject(reason?: any): void;\n  promise(): Promise<T>;\n}\n\nexport function createDefer<T = any>(): Defer<T> {\n  const r: any = {};\n  const promise = new Promise<T>((resolve, reject) => {\n    r.resolve = resolve;\n    r.reject = reject;\n  });\n\n  r.promise = () => promise;\n\n  return r;\n}\n"
  },
  {
    "path": "packages/utils/src/create-icon.tsx",
    "content": "import { isValidElement, ReactNode, createElement, cloneElement } from 'react';\nimport { Icon } from '@alifd/next';\nimport { IPublicTypeIconType } from '@alilc/lowcode-types';\nimport { isReactComponent } from './is-react';\nimport { isESModule } from './is-es-module';\n\nconst URL_RE = /^(https?:)\\/\\//i;\n\nexport function createIcon(\n    icon?: IPublicTypeIconType | null,\n    props?: Record<string, unknown>,\n  ): ReactNode {\n  if (!icon) {\n    return null;\n  }\n  if (isESModule(icon)) {\n    icon = icon.default;\n  }\n  if (typeof icon === 'string') {\n    if (URL_RE.test(icon)) {\n      return createElement('img', {\n        src: icon,\n        class: props?.className,\n        ...props,\n      });\n    }\n    return <Icon type={icon} {...props} />;\n  }\n  if (isValidElement(icon)) {\n    return cloneElement(icon, { ...props });\n  }\n  if (isReactComponent(icon)) {\n    return createElement(icon, {\n      class: props?.className,\n      ...props,\n    });\n  }\n\n  return <Icon {...icon} {...props} />;\n}\n"
  },
  {
    "path": "packages/utils/src/css-helper.ts",
    "content": "/**\n * just for legao\n * @author: jiushen\n */\n// 需要通过 Env 来判断是否需要\n\nimport { some } from 'lodash';\n\nconst pseudoMap = ['hover', 'focus', 'active', 'visited'];\n\nconst RE_CAMEL = /[A-Z]/g;\nconst RE_HYPHEN = /[-\\s]+(.)?/g;\nconst PROPS_REG = /([^:]*):\\s?(.*)/i;\n\n// 给 css 分组\nfunction groupingCss(css: string) {\n  let stackLength = 0;\n  let startIndex = 0;\n  const group: string[] = [];\n  css.split('').forEach((char, index) => {\n    if (char === '{') {\n      stackLength++;\n    }\n    if (char === '}') {\n      if (stackLength === 1) {\n        group.push(css.substring(startIndex, index + 1));\n        startIndex = index + 1;\n      }\n      stackLength--;\n    }\n  });\n  return group;\n}\n\nfunction isString(str: any): str is string {\n  return {}.toString.call(str) === '[object String]';\n}\n\nfunction hyphenate(str: string): string {\n  return str.replace(RE_CAMEL, w => `-${w}`).toLowerCase();\n}\n\nfunction camelize(str: string): string {\n  return str.replace(RE_HYPHEN, (m, w) => (w ? w.toUpperCase() : ''));\n}\n\n/**\n * convert\n * {background-color: \"red\"}\n * to\n * background-color: red;\n */\nfunction runtimeToCss(runtime: Record<string, string>) {\n  const css: string[] = [];\n  Object.keys(runtime).forEach((key) => {\n    css.push(`  ${key}: ${runtime[key]};`);\n  });\n  return css.join('\\n');\n}\n\nfunction toNativeStyle(runtime: Record<string, string> | undefined) {\n  if (!runtime) {\n    return {};\n  }\n  if (runtime.default) {\n    const normalized: Record<string, string> = {};\n    Object.keys(runtime).forEach((pseudo) => {\n      if (pseudo === 'extra') {\n        normalized[pseudo] = runtime[pseudo];\n        return;\n      }\n      normalized[pseudo] = toNativeStyle(runtime[pseudo]);\n    });\n    return normalized;\n  }\n\n  const normalized = {};\n  Object.keys(runtime).forEach((key) => {\n    normalized[camelize(key)] = runtime[key];\n  });\n  return normalized;\n}\n\nfunction normalizeStyle(style) {\n  if (!style) {\n    return {};\n  }\n  if (style.default) {\n    const normalized = {};\n    Object.keys(style).forEach((pseudo) => {\n      if (pseudo === 'extra') {\n        normalized[pseudo] = style[pseudo];\n        return;\n      }\n      normalized[pseudo] = normalizeStyle(style[pseudo]);\n    });\n    return normalized;\n  }\n\n  const normalized: Record<string, string | Record<string, string>> = {};\n  Object.keys(style).forEach((key) => {\n    normalized[hyphenate(key)] = style[key];\n  });\n  return normalized;\n}\n\nfunction toCss(runtime) {\n  if (!runtime) {\n    return (\n      `:root {\n\n}`);\n  }\n\n  if (runtime.default) {\n    const css: string[] = [];\n    Object.keys(runtime).forEach((pseudo) => {\n      if (pseudo === 'extra') {\n        Array.isArray(runtime.extra) && css.push(runtime.extra.join('\\n'));\n        return;\n      }\n      // 只需要对这四种做兼容\n      const prefix = pseudoMap.indexOf(pseudo) > -1 ? ':' : '';\n      css.push(\n        `:root${pseudo === 'default' ? '' : `${prefix}${pseudo}`} {\n${runtimeToCss(normalizeStyle(runtime[pseudo]))}\n}\\n`,\n);\n    });\n    return css.join('\\n');\n  }\n\n  return (\n    `:root {\n${runtimeToCss(normalizeStyle(runtime))}\n}\n`\n  );\n}\n\nfunction cssToRuntime(css: string) {\n  if (!css) {\n    return {};\n  }\n  const runtime: {\n    extra?: string[];\n    default?: Record<string, string>;\n  } = {};\n  const groups = groupingCss(css);\n  groups.forEach((cssItem) => {\n    if (!cssItem.startsWith(':root')) {\n      runtime.extra = runtime.extra || [];\n      runtime.extra.push(cssItem.trim());\n    } else {\n      const res = /:root:?(.*)?{(.*)/ig.exec(cssItem.replace(/[\\r\\n]+/ig, '').trim());\n      if (res) {\n        let pseudo: string | undefined;\n\n        if (res[1] && res[1].trim() && some(pseudoMap, pse => res[1].indexOf(pse) === 0)) {\n          pseudo = res[1].trim();\n        } else if (res[1] && res[1].trim()) {\n          pseudo = res[1];\n        }\n\n        const s: Record<string, string> = {};\n        res[2].split(';').reduce<string[]>((prev, next) => {\n          if (next.indexOf('base64') > -1) {\n            prev[prev.length - 1] += `;${next}`;\n          } else {\n            prev.push(next);\n          }\n          return prev;\n        }, []).forEach((item) => {\n          if (item) {\n            if (PROPS_REG.test(item)) {\n              const props = item.match(PROPS_REG);\n              const key = props?.[1];\n              const value = props?.[2];\n              if (key && value) {\n                s[key.trim()] = value.trim();\n              }\n            }\n          }\n        });\n\n        runtime[pseudo || 'default'] = s;\n      }\n    }\n  });\n  return runtime;\n}\n\nfunction cssToStyle(css) {\n  try {\n    if (isString(css)) {\n      return toNativeStyle(cssToRuntime(css).default);\n    }\n    if (css.default) {\n      return toNativeStyle(normalizeStyle(css.default));\n    }\n    return toNativeStyle(normalizeStyle(css));\n  } catch (e) {\n    // do nothing\n  }\n  return {};\n}\n\nexport {\n  hyphenate,\n  camelize,\n  toNativeStyle,\n  normalizeStyle,\n  toCss,\n  cssToRuntime,\n  cssToStyle,\n};\n"
  },
  {
    "path": "packages/utils/src/cursor.css",
    "content": "html.lc-cursor-dragging,\nhtml.lc-cursor-dragging * {\n  cursor: move !important;\n}\n\nhtml.lc-cursor-x-resizing,\nhtml.lc-cursor-x-resizing * {\n  cursor: col-resize;\n}\n\nhtml.lc-cursor-y-resizing,\nhtml.lc-cursor-y-resizing * {\n  cursor: row-resize;\n}\n\nhtml.lc-cursor-copy,\nhtml.lc-cursor-copy * {\n  cursor: copy !important;\n}\n"
  },
  {
    "path": "packages/utils/src/cursor.ts",
    "content": "import './cursor.css';\n\nexport class Cursor {\n  private states = new Set<string>();\n\n  setDragging(flag: boolean) {\n    if (flag) {\n      this.addState('dragging');\n    } else {\n      this.removeState('dragging');\n    }\n  }\n\n  setXResizing(flag: boolean) {\n    if (flag) {\n      this.addState('x-resizing');\n    } else {\n      this.removeState('x-resizing');\n    }\n  }\n\n  setYResizing(flag: boolean) {\n    if (flag) {\n      this.addState('y-resizing');\n    } else {\n      this.removeState('y-resizing');\n    }\n  }\n\n  setCopy(flag: boolean) {\n    if (flag) {\n      this.addState('copy');\n    } else {\n      this.removeState('copy');\n    }\n  }\n\n  isCopy() {\n    return this.states.has('copy');\n  }\n\n  release() {\n    for (const state of this.states) {\n      this.removeState(state);\n    }\n  }\n\n  addState(state: string) {\n    if (!this.states.has(state)) {\n      this.states.add(state);\n      document.documentElement.classList.add(`lc-cursor-${state}`);\n    }\n  }\n\n  private removeState(state: string) {\n    if (this.states.has(state)) {\n      this.states.delete(state);\n      document.documentElement.classList.remove(`lc-cursor-${state}`);\n    }\n  }\n}\n\nexport const cursor = new Cursor();\n"
  },
  {
    "path": "packages/utils/src/env.ts",
    "content": "export function isInSimulator() {\n  return Boolean((window as any).__is_simulator_env__);\n}\n"
  },
  {
    "path": "packages/utils/src/get-prototype-of.ts",
    "content": "export function getPrototypeOf(target: any) {\n  if (typeof Object.getPrototypeOf !== 'undefined') {\n    return Object.getPrototypeOf(target);\n  }\n\n  // eslint-disable-next-line no-proto\n  return target.__proto__;\n}\n"
  },
  {
    "path": "packages/utils/src/has-own-property.ts",
    "content": "const prototypeHasOwnProperty = Object.prototype.hasOwnProperty;\nexport function hasOwnProperty(obj: any, key: string | number | symbol): boolean {\n  return obj && prototypeHasOwnProperty.call(obj, key);\n}\n"
  },
  {
    "path": "packages/utils/src/index.ts",
    "content": "export * from './asset';\nexport * from './clone-deep';\nexport * from './create-content';\nexport * from './create-icon';\nexport * from './cursor';\nexport * from './get-prototype-of';\nexport * from './has-own-property';\nexport * from './is-css-url';\nexport * from './is-element';\nexport * from './is-es-module';\nexport * from './is-form-event';\nexport * from './is-function';\nexport * from './is-object';\nexport * from './is-plain-object';\nexport * from './is-react';\nexport * from './navtive-selection';\nexport * from './set-prototype-of';\nexport * from './shallow-equal';\nexport * from './svg-icon';\nexport * from './unique-id';\nexport * from './build-components';\nexport * from './app-helper';\nexport * from './misc';\nexport * from './schema';\nexport * from './node-helper';\nexport * from './clone-enumerable-property';\nexport * from './logger';\nexport * from './is-shaken';\nexport * from './is-plugin-event-name';\nexport * as css from './css-helper';\nexport { transactionManager } from './transaction-manager';\nexport * from './check-types';\nexport * from './workspace';\nexport * from './context-menu';\nexport { checkPropTypes } from './check-prop-types';"
  },
  {
    "path": "packages/utils/src/is-css-url.ts",
    "content": "export function isCSSUrl(url: string): boolean {\n  return /\\.css(\\?.*)?$/.test(url);\n}\n"
  },
  {
    "path": "packages/utils/src/is-element.ts",
    "content": "export function isElement(node: any): node is Element {\n  if (!node) return false;\n  return node.nodeType === Node.ELEMENT_NODE;\n}\n"
  },
  {
    "path": "packages/utils/src/is-es-module.ts",
    "content": "export type ESModule = {\n  __esModule: true;\n  default: any;\n};\nexport function isESModule(obj: any): obj is ESModule {\n  return obj && obj.__esModule;\n}\n"
  },
  {
    "path": "packages/utils/src/is-form-event.ts",
    "content": "export function isFormEvent(e: KeyboardEvent | MouseEvent) {\n  const t = e.target as HTMLFormElement;\n  if (!t) {\n    return false;\n  }\n\n  if (t.form || /^(INPUT|SELECT|TEXTAREA)$/.test(t.tagName)) {\n    return true;\n  }\n  if (t instanceof HTMLElement && /write/.test(window.getComputedStyle(t).getPropertyValue('-webkit-user-modify'))) {\n    return true;\n  }\n  return false;\n}\n"
  },
  {
    "path": "packages/utils/src/is-function.ts",
    "content": "export function isFunction(fn: any): boolean {\n  return typeof fn === 'function';\n}\n"
  },
  {
    "path": "packages/utils/src/is-object.ts",
    "content": "export function isObject(value: any): value is Record<string, any> {\n  return value !== null && typeof value === 'object';\n}\n\nexport function isI18NObject(value: any): boolean {\n  return isObject(value) && value.type === 'i18n';\n}\n"
  },
  {
    "path": "packages/utils/src/is-plain-object.ts",
    "content": "import { isObject } from './is-object';\n\nexport function isPlainObject(value: any): value is any {\n  if (!isObject(value)) {\n    return false;\n  }\n  const proto = Object.getPrototypeOf(value);\n  return proto === Object.prototype || proto === null || Object.getPrototypeOf(proto) === null;\n}\n"
  },
  {
    "path": "packages/utils/src/is-plugin-event-name.ts",
    "content": "export function isPluginEventName(eventName: string): boolean {\n  if (!eventName) {\n    return false;\n  }\n\n  const eventSegments = eventName.split(':');\n  return (eventSegments.length > 1 && eventSegments[0].length > 0);\n}\n"
  },
  {
    "path": "packages/utils/src/is-react.ts",
    "content": "import { ComponentClass, Component, FunctionComponent, ComponentType, createElement } from 'react';\nimport { cloneEnumerableProperty } from './clone-enumerable-property';\n\nconst hasSymbol = typeof Symbol === 'function' && Symbol.for;\nexport const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;\nexport const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;\n\nexport function isReactClass(obj: any): obj is ComponentClass<any> {\n  if (!obj) {\n    return false;\n  }\n  if (obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component)) {\n    return true;\n  }\n  return false;\n}\n\nexport function acceptsRef(obj: any): boolean {\n  if (!obj) {\n    return false;\n  }\n  if (obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj)) {\n    return true;\n  }\n\n  return false;\n}\n\nexport function isForwardRefType(obj: any): boolean {\n  if (!obj || !obj?.$$typeof) {\n    return false;\n  }\n  return obj?.$$typeof === REACT_FORWARD_REF_TYPE;\n}\n\nexport function isMemoType(obj: any): boolean {\n  if (!obj || !obj?.$$typeof) {\n    return false;\n  }\n  return obj.$$typeof === REACT_MEMO_TYPE;\n}\n\nexport function isForwardOrMemoForward(obj: any): boolean {\n  if (!obj || !obj?.$$typeof) {\n    return false;\n  }\n  return (\n    // React.forwardRef(..)\n    isForwardRefType(obj) ||\n    // React.memo(React.forwardRef(..))\n    (isMemoType(obj) && isForwardRefType(obj.type))\n  );\n}\n\nexport function isReactComponent(obj: any): obj is ComponentType<any> {\n  if (!obj) {\n    return false;\n  }\n\n  return Boolean(isReactClass(obj) || typeof obj === 'function' || isForwardRefType(obj) || isMemoType(obj));\n}\n\nexport function wrapReactClass(view: FunctionComponent) {\n  let ViewComponentClass = class extends Component {\n    render() {\n      const { children, ...other } = this.props;\n      return createElement(view, other, children);\n    }\n  } as any;\n  ViewComponentClass = cloneEnumerableProperty(ViewComponentClass, view);\n  ViewComponentClass.displayName = view.displayName;\n  return ViewComponentClass;\n}\n"
  },
  {
    "path": "packages/utils/src/is-shaken.ts",
    "content": "const SHAKE_DISTANCE = 4;\n/**\n * mouse shake check\n */\nexport function isShaken(e1: MouseEvent | DragEvent, e2: MouseEvent | DragEvent): boolean {\n  if ((e1 as any).shaken) {\n    return true;\n  }\n  if (e1.target !== e2.target) {\n    return true;\n  }\n  return (\n    Math.pow(e1.clientY - e2.clientY, 2) + Math.pow(e1.clientX - e2.clientX, 2) > SHAKE_DISTANCE\n  );\n}"
  },
  {
    "path": "packages/utils/src/logger.ts",
    "content": "/* eslint-disable no-console */\n/* eslint-disable no-param-reassign */\nimport { isObject } from './is-object';\n\nexport type Level = 'debug' | 'log' | 'info' | 'warn' | 'error';\ninterface Options {\n  level: Level;\n  bizName: string;\n}\n\nconst levels: Record<string, number> = {\n  debug: -1,\n  log: 0,\n  info: 0,\n  warn: 1,\n  error: 2,\n};\nconst bizNameColors = [\n  '#daa569',\n  '#00ffff',\n  '#385e0f',\n  '#7fffd4',\n  '#00c957',\n  '#b0e0e6',\n  '#4169e1',\n  '#6a5acd',\n  '#87ceeb',\n  '#ffff00',\n  '#e3cf57',\n  '#ff9912',\n  '#eb8e55',\n  '#ffe384',\n  '#40e0d0',\n  '#a39480',\n  '#d2691e',\n  '#ff7d40',\n  '#f0e68c',\n  '#bc8f8f',\n  '#c76114',\n  '#734a12',\n  '#5e2612',\n  '#0000ff',\n  '#3d59ab',\n  '#1e90ff',\n  '#03a89e',\n  '#33a1c9',\n  '#a020f0',\n  '#a066d3',\n  '#da70d6',\n  '#dda0dd',\n  '#688e23',\n  '#2e8b57',\n];\nconst bodyColors: Record<string, string> = {\n  debug: '#fadb14',\n  log: '#8c8c8c',\n  info: '#52c41a',\n  warn: '#fa8c16',\n  error: '#ff4d4f',\n};\nconst levelMarks: Record<string, string> = {\n  debug: 'debug',\n  log: 'log',\n  info: 'info',\n  warn: 'warn',\n  error: 'error',\n};\nconst outputFunction: Record<string, any> = {\n  debug: console.log,\n  log: console.log,\n  info: console.log,\n  warn: console.warn,\n  error: console.error,\n};\n\nconst bizNameColorConfig: Record<string, string> = {};\n\nconst shouldOutput = (\n    logLevel: string,\n    targetLevel: string = 'warn',\n    bizName: string,\n    targetBizName: string,\n  ): boolean => {\n  const isLevelFit = (levels as any)[targetLevel] <= (levels as any)[logLevel];\n  const isBizNameFit = targetBizName === '*' || bizName.indexOf(targetBizName) > -1;\n  return isLevelFit && isBizNameFit;\n};\n\nconst output = (logLevel: string, bizName: string) => {\n  return (...args: any[]) => {\n    return outputFunction[logLevel]?.apply(console, getLogArgs(args, bizName, logLevel));\n  };\n};\n\nconst getColor = (bizName: string) => {\n  if (!bizNameColorConfig[bizName]) {\n    const color = bizNameColors[Object.keys(bizNameColorConfig).length % bizNameColors.length];\n    bizNameColorConfig[bizName] = color;\n  }\n  return bizNameColorConfig[bizName];\n};\n\nconst getLogArgs = (args: any, bizName: string, logLevel: string) => {\n  const color = getColor(bizName);\n  const bodyColor = bodyColors[logLevel];\n\n  const argsArray = args[0];\n  let prefix = `%c[${bizName}]%c[${levelMarks[logLevel]}]:`;\n  argsArray.forEach((arg: any) => {\n    if (isObject(arg)) {\n      prefix += '%o';\n    } else {\n      prefix += '%s';\n    }\n  });\n  let processedArgs = [prefix, `color: ${color}`, `color: ${bodyColor}`];\n  processedArgs = processedArgs.concat(argsArray);\n  return processedArgs;\n};\nconst parseLogConf = (logConf: string, options: Options): { level: string; bizName: string} => {\n  if (!logConf) {\n    return {\n      level: options.level,\n      bizName: options.bizName,\n    };\n  }\n  if (logConf.indexOf(':') > -1) {\n    const pair = logConf.split(':');\n    return {\n      level: pair[0],\n      bizName: pair[1] || '*',\n    };\n  }\n  return {\n    level: logConf,\n    bizName: '*',\n  };\n};\n\nconst defaultOptions: Options = {\n  level: 'warn',\n  bizName: '*',\n};\n\nclass Logger {\n  bizName: string;\n  targetBizName: string;\n  targetLevel: string;\n  constructor(options: Options) {\n    options = { ...defaultOptions, ...options };\n    const _location = location || {} as any;\n    // __logConf__ 格式为 logLevel[:bizName], bizName is used as: targetBizName like '%bizName%'\n    //   1. __logConf__=log  or __logConf__=warn,  etc.\n    //   2. __logConf__=log:*  or __logConf__=warn:*,  etc.\n    //   2. __logConf__=log:bizName  or __logConf__=warn:partOfBizName,  etc.\n    const logConf = (((/__(?:logConf|logLevel)__=([^#/&]*)/.exec(_location.href)) || [])[1]);\n    const targetOptions = parseLogConf(logConf, options);\n    this.bizName = options.bizName;\n    this.targetBizName = targetOptions.bizName;\n    this.targetLevel = targetOptions.level;\n  }\n  debug(...args: any[]): void {\n    if (!shouldOutput('debug', this.targetLevel, this.bizName, this.targetBizName)) {\n      return;\n    }\n    return output('debug', this.bizName)(args);\n  }\n  log(...args: any[]): void {\n    if (!shouldOutput('log', this.targetLevel, this.bizName, this.targetBizName)) {\n      return;\n    }\n    return output('log', this.bizName)(args);\n  }\n  info(...args: any[]): void {\n    if (!shouldOutput('info', this.targetLevel, this.bizName, this.targetBizName)) {\n      return;\n    }\n    return output('info', this.bizName)(args);\n  }\n  warn(...args: any[]): void {\n    if (!shouldOutput('warn', this.targetLevel, this.bizName, this.targetBizName)) {\n      return;\n    }\n    return output('warn', this.bizName)(args);\n  }\n  error(...args: any[]): void {\n    if (!shouldOutput('error', this.targetLevel, this.bizName, this.targetBizName)) {\n      return;\n    }\n    return output('error', this.bizName)(args);\n  }\n}\n\nexport { Logger };\n\nexport function getLogger(config: { level: Level; bizName: string }): Logger {\n  return new Logger(config);\n}\n"
  },
  {
    "path": "packages/utils/src/misc.ts",
    "content": "\nimport { isI18NObject } from './is-object';\nimport { get } from 'lodash';\nimport { IPublicEnumTransformStage, IPublicModelComponentMeta } from '@alilc/lowcode-types';\nimport { Logger } from './logger';\n\nconst logger = new Logger({ level: 'warn', bizName: 'utils' });\n\ninterface Variable {\n  type: 'variable';\n  variable: string;\n  value: any;\n}\n\nexport function isVariable(obj: any): obj is Variable {\n  if (!obj || typeof obj !== 'object') {\n    return false;\n  }\n  return obj.type === 'variable';\n}\n\nexport function isUseI18NSetter(prototype: any, propName: string) {\n  const configure = prototype?.options?.configure;\n  if (Array.isArray(configure)) {\n    return configure.some(c => {\n      return c.name === propName && c?.setter?.type?.displayName === 'I18nSetter';\n    });\n  }\n  return false;\n}\n\nexport function convertToI18NObject(v: string | any, locale: string = 'zh-CN') {\n  if (isI18NObject(v)) return v;\n  return { type: 'i18n', use: locale, [locale]: v };\n}\n\nexport function isString(v: any): v is string {\n  return typeof v === 'string';\n}\n\nfunction _innerWaitForThing(obj: any, path: string): Promise<any> {\n  const timeGap = 200;\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      const thing = get(obj, path);\n      if (thing) {\n        return resolve(thing);\n      }\n      reject();\n    }, timeGap);\n  }).catch(() => {\n    return _innerWaitForThing(obj, path);\n  });\n}\n\nexport function waitForThing(obj: any, path: string): Promise<any> {\n  const thing = get(obj, path);\n  if (thing) {\n    return Promise.resolve(thing);\n  }\n  return _innerWaitForThing(obj, path);\n}\n\nexport function arrShallowEquals(arr1: any[], arr2: any[]): boolean {\n  if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false;\n  if (arr1.length !== arr2.length) return false;\n  return arr1.every(item => arr2.includes(item));\n}\n\n/**\n * 判断当前 meta 是否从 vc prototype 转换而来\n * @param meta\n */\n export function isFromVC(meta: IPublicModelComponentMeta) {\n  return !!meta?.getMetadata().configure?.advanced;\n}\n\nexport function executePendingFn(fn: () => void, timeout: number = 2000) {\n  return setTimeout(fn, timeout);\n}\n\nconst stageList = [\n  'render',\n  'serilize',\n  'save',\n  'clone',\n  'init',\n  'upgrade',\n];\n\n/**\n * 兼容原来的数字版本的枚举对象\n * @param stage\n * @returns\n */\nexport function compatStage(stage: IPublicEnumTransformStage | number): IPublicEnumTransformStage {\n  if (typeof stage === 'number') {\n    console.warn('stage 直接指定为数字的使用方式已经过时，将在下一版本移除，请直接使用 IPublicEnumTransformStage.Render|Serilize|Save|Clone|Init|Upgrade');\n    return stageList[stage - 1] as IPublicEnumTransformStage;\n  }\n  return stage as IPublicEnumTransformStage;\n}\n\nexport function invariant(check: any, message: string, thing?: any) {\n  if (!check) {\n    throw new Error(`Invariant failed: ${ message }${thing ? ` in '${thing}'` : ''}`);\n  }\n}\n\nexport function deprecate(fail: any, message: string, alterative?: string) {\n  if (fail) {\n    logger.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : ''));\n  }\n}\n\nexport function isRegExp(obj: any): obj is RegExp {\n  if (!obj || typeof obj !== 'object') {\n    return false;\n  }\n  return 'test' in obj && 'exec' in obj && 'compile' in obj;\n}\n\n/**\n * The prop supportVariable SHOULD take precedence over default global supportVariable.\n * @param propSupportVariable prop supportVariable\n * @param globalSupportVariable global supportVariable\n * @returns\n */\nexport function shouldUseVariableSetter(\n  propSupportVariable: boolean | undefined,\n  globalSupportVariable: boolean,\n) {\n  if (propSupportVariable === false) return false;\n  return propSupportVariable || globalSupportVariable;\n}"
  },
  {
    "path": "packages/utils/src/navtive-selection.ts",
    "content": "export let nativeSelectionEnabled = true;\n\nconst preventSelection = (e: Event) => {\n  if (nativeSelectionEnabled) {\n    return null;\n  }\n  e.preventDefault();\n  e.stopPropagation();\n  return false;\n};\ndocument.addEventListener('selectstart', preventSelection, true);\ndocument.addEventListener('dragstart', preventSelection, true);\n\nexport function setNativeSelection(enableFlag: boolean) {\n  nativeSelectionEnabled = enableFlag;\n}\n"
  },
  {
    "path": "packages/utils/src/node-helper.ts",
    "content": "// 仅使用类型\nimport { IPublicModelNode } from '@alilc/lowcode-types';\nimport { MouseEvent } from 'react';\n\nexport const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>(\n  node: Node,\n  until: (n: Node) => boolean,\n  ): Node | undefined => {\n  if (!node) {\n    return undefined;\n  }\n  if (until(node)) {\n    return node;\n  } else {\n    // @ts-ignore\n    return getClosestNode(node.parent, until);\n  }\n};\n\n/**\n * 判断节点是否可被点击\n * @param {Node} node 节点\n * @param {unknown} e 点击事件\n * @returns {boolean} 是否可点击，true表示可点击\n */\nexport function canClickNode<Node extends IPublicModelNode = IPublicModelNode>(node: Node, e: MouseEvent): boolean {\n  const onClickHook = node.componentMeta?.advanced?.callbacks?.onClickHook;\n  const canClick = typeof onClickHook === 'function' ? onClickHook(e, node) : true;\n  return canClick;\n}\n"
  },
  {
    "path": "packages/utils/src/schema.ts",
    "content": "import { ActivityType, IPublicTypeNodeSchema, IPublicTypeRootSchema } from '@alilc/lowcode-types';\nimport { isJSBlock, isJSSlot } from './check-types';\nimport { isVariable } from './misc';\nimport { isPlainObject } from './is-plain-object';\n\nfunction isJsObject(props: any) {\n  if (typeof props === 'object' && props !== null) {\n    return props.type && props.source && props.compiled;\n  }\n}\nfunction isActionRef(props: any): boolean {\n  return props.type && props.type === 'actionRef';\n}\n\n/**\n * 将「乐高版本」协议升级成 JSExpression / JSSlot 等标准协议的结构\n * @param props\n * @returns\n */\nexport function compatibleLegaoSchema(props: any): any {\n  if (!props) {\n    return props;\n  }\n\n  if (Array.isArray(props)) {\n    return props.map(k => compatibleLegaoSchema(k));\n  }\n\n  if (!isPlainObject(props)) {\n    return props;\n  }\n\n  if (isJSBlock(props)) {\n    if (props.value.componentName === 'Slot') {\n      return {\n        type: 'JSSlot',\n        title: (props.value.props as any)?.slotTitle,\n        name: (props.value.props as any)?.slotName,\n        value: compatibleLegaoSchema(props.value.children),\n        params: (props.value.props as any)?.slotParams,\n      };\n    } else {\n      return props.value;\n    }\n  }\n  if (isVariable(props)) {\n    return {\n      type: 'JSExpression',\n      value: props.variable,\n      mock: props.value,\n    };\n  }\n  if (isJsObject(props)) {\n    return {\n      type: 'JSExpression',\n      value: props.compiled,\n      extType: 'function',\n    };\n  }\n  if (isActionRef(props)) {\n    return {\n      type: 'JSExpression',\n      value: `${props.id}.bind(this)`,\n    };\n  }\n  const newProps: any = {};\n  Object.keys(props).forEach((key) => {\n    if (/^__slot__/.test(key) && props[key] === true) {\n      return;\n    }\n    // TODO: 先移除，目前没有业务使用\n    // if (key === 'dataSource') {\n    //   newProps[key] = props[key];\n    //   return;\n    // }\n    newProps[key] = compatibleLegaoSchema(props[key]);\n  });\n  return newProps;\n}\n\nexport function getNodeSchemaById(schema: IPublicTypeNodeSchema, nodeId: string): IPublicTypeNodeSchema | undefined {\n  let found: IPublicTypeNodeSchema | undefined;\n  if (schema.id === nodeId) {\n    return schema;\n  }\n  const { children, props } = schema;\n  // 查找 children\n  if (Array.isArray(children)) {\n    for (const child of children) {\n      found = getNodeSchemaById(child as IPublicTypeNodeSchema, nodeId);\n      if (found) return found;\n    }\n  }\n  if (isPlainObject(props)) {\n    // 查找 props，主要是 slot 类型\n    found = getNodeSchemaFromPropsById(props, nodeId);\n    if (found) return found;\n  }\n}\n\nfunction getNodeSchemaFromPropsById(props: any, nodeId: string): IPublicTypeNodeSchema | undefined {\n  let found: IPublicTypeNodeSchema | undefined;\n  for (const [_key, value] of Object.entries(props)) {\n    if (isJSSlot(value)) {\n      // value 是数组类型 { type: 'JSSlot', value: IPublicTypeNodeSchema[] }\n      if (Array.isArray(value.value)) {\n        for (const child of value.value) {\n          found = getNodeSchemaById(child as IPublicTypeNodeSchema, nodeId);\n          if (found) return found;\n        }\n      }\n      // value 是对象类型 { type: 'JSSlot', value: IPublicTypeNodeSchema }\n      found = getNodeSchemaById(value.value as IPublicTypeNodeSchema, nodeId);\n      if (found) return found;\n    } else if (isPlainObject(value)) {\n      found = getNodeSchemaFromPropsById(value, nodeId);\n      if (found) return found;\n    }\n  }\n}\n\n/**\n * TODO: not sure if this is used anywhere\n * @deprecated\n */\nexport function applyActivities(pivotSchema: IPublicTypeRootSchema, activities: any): IPublicTypeRootSchema {\n  let schema = { ...pivotSchema };\n  if (!Array.isArray(activities)) {\n    activities = [activities];\n  }\n  return activities.reduce((accSchema: IPublicTypeRootSchema, activity: any) => {\n    if (activity.type === ActivityType.MODIFIED) {\n      const found = getNodeSchemaById(accSchema, activity.payload.schema.id);\n      if (!found) return accSchema;\n      Object.assign(found, activity.payload.schema);\n    } else if (activity.type === ActivityType.ADDED) {\n      const { payload } = activity;\n      const { location, schema } = payload;\n      const { parent } = location;\n      const found = getNodeSchemaById(accSchema, parent.nodeId);\n      if (found) {\n        if (Array.isArray(found.children)) {\n          found.children.splice(parent.index, 0, schema);\n        } else if (!found.children) {\n          found.children = [schema];\n        }\n        // TODO: 是 JSExpression / DOMText\n      }\n    } else if (activity.type === ActivityType.DELETED) {\n      const { payload } = activity;\n      const { location } = payload;\n      const { parent } = location;\n      const found = getNodeSchemaById(accSchema, parent.nodeId);\n      if (found && Array.isArray(found.children)) {\n        found.children.splice(parent.index, 1);\n      }\n    }\n    return accSchema;\n  }, schema);\n}\n"
  },
  {
    "path": "packages/utils/src/script.ts",
    "content": "import { createDefer } from './create-defer';\nimport { Logger } from './logger';\n\nconst logger = new Logger({ level: 'warn', bizName: 'utils' });\n\nexport function evaluate(script: string, scriptType?: string) {\n  const scriptEl = document.createElement('script');\n  scriptType && (scriptEl.type = scriptType);\n  scriptEl.text = script;\n  document.head.appendChild(scriptEl);\n  document.head.removeChild(scriptEl);\n}\n\nexport function load(url: string, scriptType?: string) {\n  const node = document.createElement('script');\n\n  // node.setAttribute('crossorigin', 'anonymous');\n\n  node.onload = onload;\n  node.onerror = onload;\n\n  const i = createDefer();\n\n  function onload(e: any) {\n    node.onload = null;\n    node.onerror = null;\n    if (e.type === 'load') {\n      i.resolve();\n    } else {\n      i.reject();\n    }\n    // document.head.removeChild(node);\n    // node = null;\n  }\n\n  node.src = url;\n\n  // `async=false` is required to make sure all js resources execute sequentially.\n  node.async = false;\n\n  scriptType && (node.type = scriptType);\n\n  document.head.appendChild(node);\n\n  return i.promise();\n}\n\nexport function evaluateExpression(expr: string) {\n  // eslint-disable-next-line no-new-func\n  const fn = new Function(expr);\n  return fn();\n}\n\nexport function newFunction(args: string, code: string) {\n  try {\n    // eslint-disable-next-line no-new-func\n    return new Function(args, code);\n  } catch (e) {\n    logger.warn('Caught error, Cant init func');\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/utils/src/set-prototype-of.ts",
    "content": "export function setPrototypeOf(target: any, proto: any) {\n  if (typeof Object.setPrototypeOf !== 'undefined') {\n    Object.setPrototypeOf(target, proto);\n  } else {\n    // eslint-disable-next-line no-proto\n    target.__proto__ = proto;\n  }\n}\n"
  },
  {
    "path": "packages/utils/src/shallow-equal.ts",
    "content": "import { hasOwnProperty } from './has-own-property';\n\nexport function shallowEqual(objA: any, objB: any): boolean {\n  if (objA === objB) {\n    return true;\n  }\n\n  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {\n    return false;\n  }\n\n  const keysA = Object.keys(objA);\n  const keysB = Object.keys(objB);\n\n  if (keysA.length !== keysB.length) {\n    return false;\n  }\n\n  // Test for A's keys different from B.\n  for (let i = 0; i < keysA.length; i++) {\n    if (!hasOwnProperty(objB, keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {\n      return false;\n    }\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "packages/utils/src/svg-icon.tsx",
    "content": "import React, { ReactNode } from 'react';\n\nconst SizePresets: any = {\n  xsmall: 8,\n  small: 12,\n  medium: 16,\n  large: 20,\n  xlarge: 30,\n};\n\nexport interface IconProps {\n  className?: string;\n  fill?: string;\n  size?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | number;\n  children?: ReactNode;\n  style?: Record<string, unknown>;\n}\n\nexport function SVGIcon({\n  fill,\n  size = 'medium',\n  viewBox,\n  style,\n  children,\n  ...props\n}: IconProps & {\n  viewBox: string;\n}) {\n  // eslint-disable-next-line no-prototype-builtins\n  if (SizePresets.hasOwnProperty(size)) {\n    size = SizePresets[size];\n  }\n\n  return (\n    <svg\n      fill=\"currentColor\"\n      preserveAspectRatio=\"xMidYMid meet\"\n      width={size}\n      height={size}\n      viewBox={viewBox}\n      {...props}\n      style={{\n        color: fill,\n        ...style,\n      }}\n    >\n      {children}\n    </svg>\n  );\n}\n"
  },
  {
    "path": "packages/utils/src/transaction-manager.ts",
    "content": "import { IPublicEnumTransitionType } from '@alilc/lowcode-types';\nimport { runInAction } from 'mobx';\nimport EventEmitter from 'events';\n\nclass TransactionManager {\n  emitter = new EventEmitter();\n\n  executeTransaction = (fn: () => void, type: IPublicEnumTransitionType = IPublicEnumTransitionType.REPAINT): void => {\n    this.emitter.emit(`[${type}]startTransaction`);\n    runInAction(fn);\n    this.emitter.emit(`[${type}]endTransaction`);\n  };\n\n  onStartTransaction = (fn: () => void, type: IPublicEnumTransitionType = IPublicEnumTransitionType.REPAINT): () => void => {\n    this.emitter.on(`[${type}]startTransaction`, fn);\n    return () => {\n      this.emitter.off(`[${type}]startTransaction`, fn);\n    };\n  };\n\n  onEndTransaction = (fn: () => void, type: IPublicEnumTransitionType = IPublicEnumTransitionType.REPAINT): () => void => {\n    this.emitter.on(`[${type}]endTransaction`, fn);\n    return () => {\n      this.emitter.off(`[${type}]endTransaction`, fn);\n    };\n  };\n}\n\nexport const transactionManager = new TransactionManager();\n"
  },
  {
    "path": "packages/utils/src/unique-id.ts",
    "content": "let guid = Date.now();\nexport function uniqueId(prefix = '') {\n  return `${prefix}${(guid++).toString(36).toLowerCase()}`;\n}\n"
  },
  {
    "path": "packages/utils/src/workspace.tsx",
    "content": "import React, { useEffect, useState, useCallback } from 'react';\nimport { IPublicModelPluginContext, IPublicEnumPluginRegisterLevel, IPublicModelWindow, IPublicModelEditorView } from '@alilc/lowcode-types';\n\n/**\n * 高阶组件（HOC）：为组件提供 view 插件上下文。\n *\n * @param {React.ComponentType} Component - 需要被封装的组件。\n * @param {string|string[]} viewName - 视图名称或视图名称数组，用于过滤特定的视图插件上下文。\n * @returns {React.ComponentType} 返回封装后的组件。\n *\n * @example\n * // 用法示例（函数组件）:\n * const EnhancedComponent = ProvideViewPluginContext(MyComponent, \"viewName\");\n */\nexport const ProvideViewPluginContext = (Component: any, viewName?: string | string[]) => {\n  // 创建一个新的函数组件，以便在其中使用 Hooks\n  return function WithPluginContext(props: {\n    [key: string]: any;\n\n    pluginContext?: IPublicModelPluginContext;\n  }) {\n    const getPluginContextFun = useCallback((editorWindow?: IPublicModelWindow | null) => {\n      if (!editorWindow?.currentEditorView) {\n        return null;\n      }\n      if (viewName) {\n        const items = editorWindow?.editorViews.filter(d => (d as any).viewName === viewName || (Array.isArray(viewName) && viewName.includes((d as any).viewName)));\n        return items[0];\n      } else {\n        return editorWindow.currentEditorView;\n      }\n    }, []);\n\n    const { workspace } = props.pluginContext || {};\n    const [pluginContext, setPluginContext] = useState<IPublicModelEditorView | null>(getPluginContextFun(workspace?.window));\n\n    useEffect(() => {\n      if (workspace?.window) {\n        const ctx = getPluginContextFun(workspace.window);\n        ctx && setPluginContext(ctx);\n      }\n      return workspace?.onChangeActiveEditorView(() => {\n        const ctx = getPluginContextFun(workspace.window);\n        ctx && setPluginContext(ctx);\n      });\n    }, [workspace, getPluginContextFun]);\n\n    if (props.pluginContext?.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace || !props.pluginContext) {\n      return <Component {...props} />;\n    }\n\n    return <Component {...props} pluginContext={pluginContext} />;\n  };\n};\n"
  },
  {
    "path": "packages/utils/test/src/__snapshots__/is-react.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`wrapReactClass should render the FunctionComponent with props 1`] = `\n<FunctionComponent\n  prop1=\"value1\"\n  prop2=\"value2\"\n>\n  Child Text\n</FunctionComponent>\n`;\n"
  },
  {
    "path": "packages/utils/test/src/__snapshots__/schema.test.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Schema Ut props 1`] = `\nObject {\n  \"props\": Object {\n    \"mobileSlot\": Object {\n      \"name\": undefined,\n      \"params\": undefined,\n      \"title\": undefined,\n      \"type\": \"JSSlot\",\n      \"value\": Array [\n        Object {\n          \"loop\": Object {\n            \"mock\": undefined,\n            \"type\": \"JSExpression\",\n            \"value\": \"props.content\",\n          },\n        },\n      ],\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "packages/utils/test/src/build-components/buildComponents.test.tsx",
    "content": "import React from 'react';\nimport {\n  accessLibrary,\n  generateHtmlComp,\n  getSubComponent,\n  buildComponents,\n  getProjectUtils,\n} from \"../../../src/build-components\";\n\nfunction Button() {};\n\nfunction WrapButton() {};\n\nfunction ButtonGroup() {};\n\nfunction WrapButtonGroup() {};\n\nButtonGroup.Button = Button;\n\nButton.displayName = \"Button\";\nButtonGroup.displayName = \"ButtonGroup\";\nButtonGroup.prototype.isReactComponent = true;\nButton.prototype.isReactComponent = true;\n\njest.mock('../../../src/is-react', () => {\n  const original = jest.requireActual('../../../src/is-react');\n  return {\n    ...original,\n    wrapReactClass(view) {\n      return view;\n    }\n  }\n});\n\ndescribe('accessLibrary', () => {\n  it('should return a library object when given a library object', () => {\n    const libraryObject = { key: 'value' };\n    const result = accessLibrary(libraryObject);\n    expect(result).toEqual(libraryObject);\n  });\n\n  it('should generate an HTML component when given a string library name', () => {\n    const libraryName = 'div';\n    const result = accessLibrary(libraryName);\n\n    // You can write more specific assertions to validate the generated component\n    expect(result).toBeDefined();\n  });\n\n  // Add more test cases to cover other scenarios\n});\n\ndescribe('generateHtmlComp', () => {\n  it('should generate an HTML component for valid HTML tags', () => {\n    const htmlTags = ['a', 'img', 'div', 'span', 'svg'];\n    htmlTags.forEach((tag) => {\n      const result = generateHtmlComp(tag);\n\n      // You can write more specific assertions to validate the generated component\n      expect(result).toBeDefined();\n    });\n  });\n\n  it('should return undefined for an invalid HTML tag', () => {\n    const invalidTag = 'invalidtag';\n    const result = generateHtmlComp(invalidTag);\n    expect(result).toBeUndefined();\n  });\n\n  // Add more test cases to cover other scenarios\n});\n\ndescribe('getSubComponent', () => {\n  it('should return the root library if paths are empty', () => {\n    const library = { component: 'RootComponent' };\n    const paths = [];\n    const result = getSubComponent(library, paths);\n    expect(result).toEqual(library);\n  });\n\n  it('should return the specified sub-component', () => {\n    const library = {\n      components: {\n        Button: 'ButtonComponent',\n        Text: 'TextComponent',\n      },\n    };\n    const paths = ['components', 'Button'];\n    const result = getSubComponent(library, paths);\n    expect(result).toEqual('ButtonComponent');\n  });\n\n  it('should handle missing keys in the path', () => {\n    const library = {\n      components: {\n        Button: 'ButtonComponent',\n      },\n    };\n    const paths = ['components', 'Text'];\n    const result = getSubComponent(library, paths);\n    expect(result).toEqual({\n      Button: 'ButtonComponent',\n    });\n  });\n\n  it('should handle exceptions and return null', () => {\n    const library = 'ButtonComponent';\n    const paths = ['components', 'Button'];\n    // Simulate an exception by providing a non-object in place of 'ButtonComponent'\n    const result = getSubComponent(library, paths);\n    expect(result).toBeNull();\n  });\n\n  it('should handle the \"default\" key as the first path element', () => {\n    const library = {\n      default: 'DefaultComponent',\n    };\n    const paths = ['default'];\n    const result = getSubComponent(library, paths);\n    expect(result).toEqual('DefaultComponent');\n  });\n});\n\ndescribe('getProjectUtils', () => {\n  it('should return an empty object when given empty metadata and library map', () => {\n    const libraryMap = {};\n    const utilsMetadata = [];\n    const result = getProjectUtils(libraryMap, utilsMetadata);\n    expect(result).toEqual({});\n  });\n\n  it('should return project utilities based on metadata and library map', () => {\n    const libraryMap = {\n      'package1': 'library1',\n      'package2': 'library2',\n    };\n\n    const utilsMetadata = [\n      {\n        name: 'util1',\n        npm: {\n          package: 'package1',\n        },\n      },\n      {\n        name: 'util2',\n        npm: {\n          package: 'package2',\n        },\n      },\n    ];\n\n    global['library1'] = { name: 'library1' };\n    global['library2'] = { name: 'library2' };\n\n    const result = getProjectUtils(libraryMap, utilsMetadata);\n\n    // Define the expected output based on the mocked accessLibrary\n    const expectedOutput = {\n      'util1': { name: 'library1' },\n      'util2': { name: 'library2' },\n    };\n\n    expect(result).toEqual(expectedOutput);\n\n    global['library1'] = null;\n    global['library1'] = null;\n  });\n\n  it('should handle metadata with destructuring', () => {\n    const libraryMap = {\n      'package1': { destructuring: true, util1: 'library1', util2: 'library2' },\n    };\n\n    const utilsMetadata = [\n      {\n        name: 'util1',\n        npm: {\n          package: 'package1',\n          destructuring: true,\n        },\n      },\n    ];\n\n    const result = getProjectUtils(libraryMap, utilsMetadata);\n\n    // Define the expected output based on the mocked accessLibrary\n    const expectedOutput = {\n      'util1': 'library1',\n      'util2': 'library2',\n    };\n\n    expect(result).toEqual(expectedOutput);\n  });\n});\n\ndescribe('buildComponents', () => {\n  it('should create components from component map with React components', () => {\n    const libraryMap = {};\n    const componentsMap = {\n      Button: () => <button>Button</button>,\n      Text: () => <p>Text</p>,\n    };\n\n    const createComponent = (schema) => {\n      // Mock createComponent function\n      return schema.componentsTree.map((component) => component.component);\n    };\n\n    const result = buildComponents(libraryMap, componentsMap, createComponent);\n\n    expect(result.Button).toBeDefined();\n    expect(result.Text).toBeDefined();\n  });\n\n  it('should create components from component map with component schemas', () => {\n    const libraryMap = {};\n    const componentsMap = {\n      Button: {\n        componentsTree: [\n          {\n            componentName: 'Component'\n          }\n        ]\n      },\n      Text: {\n        componentsTree: [\n          {\n            componentName: 'Component'\n          }\n        ]\n      },\n    };\n\n    const createComponent = (schema) => {\n      // Mock createComponent function\n      return schema.componentsTree.map((component) => component.component);\n    };\n\n    const result = buildComponents(libraryMap, componentsMap, createComponent);\n\n    expect(result.Button).toBeDefined();\n    expect(result.Text).toBeDefined();\n  });\n\n  it('should create components from component map with React components and schemas', () => {\n    const libraryMap = {};\n    const componentsMap = {\n      Button: () => <button>Button</button>,\n      Text: {\n        type: 'ComponentSchema',\n        // Add component schema properties here\n      },\n    };\n\n    const createComponent = (schema) => {\n      // Mock createComponent function\n      return schema.componentsTree.map((component) => component.component);\n    };\n\n    const result = buildComponents(libraryMap, componentsMap, createComponent);\n\n    expect(result.Button).toBeDefined();\n    expect(result.Text).toBeDefined();\n  });\n\n  it('should create components from component map with library mappings', () => {\n    const libraryMap = {\n      'libraryName1': 'library1',\n      'libraryName2': 'library2',\n    };\n    const componentsMap = {\n      Button: {\n        package: 'libraryName1',\n        version: '1.0',\n        exportName: 'ButtonComponent',\n      },\n      Text: {\n        package: 'libraryName2',\n        version: '2.0',\n        exportName: 'TextComponent',\n      },\n    };\n\n    const createComponent = (schema) => {\n      // Mock createComponent function\n      return schema.componentsTree.map((component) => component.component);\n    };\n\n    global['library1'] = () => <button>ButtonComponent</button>;\n    global['library2'] = () => () => <p>TextComponent</p>;\n\n    const result = buildComponents(libraryMap, componentsMap, createComponent);\n\n    expect(result.Button).toBeDefined();\n    expect(result.Text).toBeDefined();\n\n    global['library1'] = null;\n    global['library2'] = null;\n  });\n});\n\ndescribe('build-component', () => {\n  it('basic button', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': {\n            Button,\n          }\n        },\n        {\n          Button: {\n            componentName: 'Button',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'Button',\n            subName: 'Button',\n          }\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n    });\n  });\n\n  it('component is a  __esModule', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': {\n            __esModule: true,\n            default: Button,\n          }\n        },\n        {\n          Button: {\n            componentName: 'Button',\n            package: '@alilc/button',\n          }\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n    });\n  })\n\n  it('basic warp button', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': {\n            WrapButton,\n          }\n        },\n        {\n          WrapButton: {\n            componentName: 'WrapButton',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'WrapButton',\n            subName: 'WrapButton',\n          }\n        },\n        () => {},\n      ))\n    .toEqual({\n      WrapButton,\n    });\n  });\n\n  it('destructuring is false button', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': Button\n        },\n        {\n          Button: {\n            componentName: 'Button',\n            package: '@alilc/button',\n            destructuring: false,\n          }\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n    });\n  });\n\n  it('Button and ButtonGroup', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': {\n            Button,\n            ButtonGroup,\n          }\n        },\n        {\n          Button: {\n            componentName: 'Button',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'Button',\n            subName: 'Button',\n          },\n          ButtonGroup: {\n            componentName: 'ButtonGroup',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'ButtonGroup',\n            subName: 'ButtonGroup',\n          }\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n      ButtonGroup,\n    });\n  });\n\n  it('ButtonGroup and ButtonGroup.Button', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': {\n            ButtonGroup,\n          }\n        },\n        {\n          Button: {\n            componentName: 'Button',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'ButtonGroup',\n            subName: 'ButtonGroup.Button',\n          },\n          ButtonGroup: {\n            componentName: 'ButtonGroup',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'ButtonGroup',\n            subName: 'ButtonGroup',\n          }\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n      ButtonGroup,\n    });\n  });\n\n  it('ButtonGroup.default and ButtonGroup.Button', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': ButtonGroup,\n        },\n        {\n          Button: {\n            componentName: 'Button',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'Button',\n            subName: 'Button',\n          },\n          ButtonGroup: {\n            componentName: 'ButtonGroup',\n            package: '@alilc/button',\n            destructuring: true,\n            exportName: 'default',\n            subName: 'default',\n          }\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n      ButtonGroup,\n    });\n  });\n\n  it('no npm component', () => {\n    expect(\n      buildComponents(\n        {\n          '@alilc/button': Button,\n        },\n        {\n          Button: null,\n        },\n        () => {},\n      ))\n    .toEqual({});\n  });\n\n  it('no npm component and global button', () => {\n    window.Button = Button;\n    expect(\n      buildComponents(\n        {},\n        {\n          Button: null,\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n    });\n    window.Button = null;\n  });\n\n  it('componentsMap value is component funtion', () => {\n    expect(\n      buildComponents(\n        {},\n        {\n          Button,\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button,\n    });\n  });\n\n\n  it('componentsMap value is component', () => {\n    expect(\n      buildComponents(\n        {},\n        {\n          Button: WrapButton,\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button: WrapButton,\n    });\n  });\n\n  it('componentsMap value is mix component', () => {\n    expect(\n      buildComponents(\n        {},\n        {\n          Button: {\n            WrapButton,\n            Button,\n            ButtonGroup,\n          },\n        },\n        () => {},\n      ))\n    .toEqual({\n      Button: {\n        WrapButton,\n        Button,\n        ButtonGroup,\n      },\n    });\n  });\n\n  it('componentsMap value is Lowcode Component', () => {\n    expect(\n      buildComponents(\n        {},\n        {\n          Button: {\n            componentName: 'Component',\n            schema: {},\n          },\n        },\n        (component) => {\n          return component as any;\n        },\n      ))\n    .toEqual({\n      Button: {\n        componentsMap: [],\n        componentsTree: [\n          {\n            componentName: 'Component',\n            schema: {},\n          }\n        ],\n        version: \"\",\n      },\n    });\n  })\n});\n\ndescribe('build div component', () => {\n  it('build div component', () => {\n    const components = buildComponents(\n      {\n        '@alilc/div': 'div'\n      },\n      {\n        div: {\n          componentName: 'div',\n          package: '@alilc/div'\n        }\n      },\n      () => {},\n    );\n\n    expect(components['div']).not.toBeNull();\n  })\n})"
  },
  {
    "path": "packages/utils/test/src/build-components/getProjectUtils.test.ts",
    "content": "import { getProjectUtils } from \"../../../src/build-components\";\n\nconst sampleUtil = () => 'I am a sample util';\nconst sampleUtil2 = () => 'I am a sample util 2';\n\ndescribe('get project utils', () => {\n  it('get utils with destructuring true', () => {\n    expect(getProjectUtils(\n      {\n        '@alilc/utils': {\n          destructuring: true,\n          sampleUtil,\n          sampleUtil2,\n        }\n      },\n      [{\n        name: 'sampleUtils',\n        npm: {\n          package: '@alilc/utils'\n        }\n      }]\n    )).toEqual({\n      sampleUtil,\n      sampleUtil2,\n    })\n  });\n\n  it('get utils with name', () => {\n    expect(getProjectUtils(\n      {\n        '@alilc/utils': sampleUtil\n      },\n      [{\n        name: 'sampleUtil',\n        npm: {\n          package: '@alilc/utils'\n        }\n      }]\n    )).toEqual({\n      sampleUtil,\n    })\n  });\n})"
  },
  {
    "path": "packages/utils/test/src/build-components/getSubComponent.test.ts",
    "content": "import { getSubComponent } from '../../../src/build-components';\n\nfunction Button() {}\n\nfunction ButtonGroup() {}\n\nButtonGroup.Button = Button;\n\nfunction OnlyButtonGroup() {}\n\ndescribe('getSubComponent library is object', () => {\n  it('get Button from Button', () => {\n    expect(getSubComponent({\n      Button,\n    }, ['Button'])).toBe(Button);\n  });\n\n  it('get ButtonGroup.Button from ButtonGroup', () => {\n    expect(getSubComponent({\n      ButtonGroup,\n    }, ['ButtonGroup', 'Button'])).toBe(Button);\n  });\n\n  it('get ButtonGroup from ButtonGroup', () => {\n    expect(getSubComponent({\n      ButtonGroup,\n    }, ['ButtonGroup'])).toBe(ButtonGroup);\n  });\n\n  it('get ButtonGroup.Button from OnlyButtonGroup', () => {\n    expect(getSubComponent({\n      ButtonGroup: OnlyButtonGroup,\n    }, ['ButtonGroup', 'Button'])).toBe(OnlyButtonGroup);\n  });\n});\n\ndescribe('getSubComponent library is null', () => {\n  it('getSubComponent library is null', () => {\n    expect(getSubComponent(null, ['ButtonGroup', 'Button'])).toBeNull();\n  });\n})\n\ndescribe('getSubComponent paths is []', () => {\n  it('getSubComponent paths is []', () => {\n    expect(getSubComponent(Button, [])).toBe(Button);\n  });\n});\n\ndescribe('getSubComponent make error', () => {\n  it('library is string', () => {\n    expect(getSubComponent(true, ['Button'])).toBe(null);\n  });\n\n  it('library is boolean', () => {\n    expect(getSubComponent('I am a string', ['Button'])).toBe(null);\n  });\n\n  it('library is number', () => {\n    expect(getSubComponent(123, ['Button'])).toBe(null);\n  });\n\n  it('library ButtonGroup is null', () => {\n    expect(getSubComponent({\n      ButtonGroup: null,\n    }, ['ButtonGroup', 'Button'])).toBe(null);\n  });\n\n  it('library ButtonGroup.Button is null', () => {\n    expect(getSubComponent({\n      ButtonGroup: null,\n    }, ['ButtonGroup', 'Button', 'SubButton'])).toBe(null);\n  });\n\n  it('path  s is [[]]', () => {\n    expect(getSubComponent({\n      ButtonGroup: null,\n    }, [['ButtonGroup'] as any, 'Button'])).toBe(null);\n  });\n\n  it('ButtonGroup is undefined', () => {\n    expect(getSubComponent({\n      ButtonGroup: undefined,\n    }, ['ButtonGroup', 'Button'])).toBe(null);\n  });\n})"
  },
  {
    "path": "packages/utils/test/src/check-prop-types.test.ts",
    "content": "import { checkPropTypes, transformPropTypesRuleToString } from '../../src/check-prop-types';\nimport PropTypes from 'prop-types';\n\ndescribe('checkPropTypes', () => {\n  it('should validate correctly with valid prop type', () => {\n    expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true);\n    expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true);\n  });\n\n  it('should log a warning and return false with invalid prop type', () => {\n    expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false);\n    expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false);\n  });\n\n  it('should validate correctly with valid object prop type', () => {\n    expect(checkPropTypes({ a: 123 }, 'age', PropTypes.object, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ a: '123' }, 'age', PropTypes.object, 'TestComponent')).toBe(true);\n  });\n\n  it('should validate correctly with valid object string prop type', () => {\n    expect(checkPropTypes({ a: 123 }, 'age', 'object', 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ a: '123' }, 'age', 'object', 'TestComponent')).toBe(true);\n  });\n\n  it('should validate correctly with valid isRequired prop type', () => {\n    const rule = {\n      type: 'string',\n      isRequired: true,\n    };\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.string.isRequired');\n    expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes(undefined, 'type', rule, 'TestComponent')).toBe(false);\n  });\n\n  it('should handle custom rule functions correctly', () => {\n    const customRule = (props, propName) => {\n      if (props[propName] !== 123) {\n        return new Error('Invalid value');\n      }\n    };\n    const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent');\n    expect(result).toBe(true);\n  });\n\n\n  it('should interpret and validate a rule given as a string', () => {\n    const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent');\n    expect(result).toBe(true);\n  });\n\n  it('should interpret and validate a rule given as a string', () => {\n    expect(checkPropTypes(123, 'age', 'number', 'TestComponent')).toBe(true);\n    expect(checkPropTypes('123', 'age', 'string', 'TestComponent')).toBe(true);\n  });\n\n  it('should log a warning for invalid rule type', () => {\n    const result = checkPropTypes(123, 'age', 123, 'TestComponent');\n    expect(result).toBe(true);\n  });\n\n  // oneOf\n  it('should validate correctly with valid oneOf prop type', () => {\n    const rule = {\n      type: 'oneOf',\n      value: ['News', 'Photos'],\n    }\n    expect(transformPropTypesRuleToString(rule)).toBe(`PropTypes.oneOf([\"News\",\"Photos\"])`);\n    expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(false);\n  });\n\n  // oneOfType\n  it('should validate correctly with valid oneOfType prop type', () => {\n    const rule = {\n      type: 'oneOfType',\n      value: ['string', 'number', {\n        type: 'array',\n        isRequired: true,\n      }],\n    };\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array.isRequired])');\n    expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes(123, 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false);\n  });\n\n  it('should validate correctly with valid oneOfType prop type', () => {\n    const rule = {\n      type: 'oneOfType',\n      value: [\n        'bool',\n        {\n          type: 'shape',\n          value: [\n            {\n              name: 'type',\n              propType: {\n                type: 'oneOf',\n                value: ['JSExpression'],\n              }\n            },\n            {\n              name: 'value',\n              propType: 'string',\n            },\n          ],\n        },\n      ],\n    };\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.bool, PropTypes.shape({type: PropTypes.oneOf([\"JSExpression\"]),value: PropTypes.string})])');\n    expect(checkPropTypes(true, 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ type: 'JSExpression', value: '1 + 1 === 2' }, 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ type: 'JSExpression' }, 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ type: 'JSExpression', value: 123 }, 'type', rule, 'TestComponent')).toBe(false);\n  });\n\n  it('should log a warning for invalid type', () => {\n    const rule = {\n      type: 'inval',\n      value: ['News', 'Photos'],\n    }\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.any');\n    expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(true);\n  });\n\n  // arrayOf\n  it('should validate correctly with valid arrayOf prop type', () => {\n    const rule = {\n      type: 'arrayOf',\n      value: {\n        type: 'string',\n        isRequired: true,\n      },\n    };\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.arrayOf(PropTypes.string.isRequired)');\n    expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes(['News', 123], 'type', rule, 'TestComponent')).toBe(false);\n  });\n\n  // objectOf\n  it('should validate correctly with valid objectOf prop type', () => {\n    const rule = {\n      type: 'objectOf',\n      value: {\n        type: 'string',\n        isRequired: true,\n      },\n    };\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.objectOf(PropTypes.string.isRequired)');\n    expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(false);\n  });\n\n  // shape\n  it('should validate correctly with valid shape prop type', () => {\n    const rule = {\n      type: 'shape',\n      value: [\n        {\n          name: 'a',\n          propType: {\n            type: 'string',\n            isRequired: true,\n          },\n        },\n        {\n          name: 'b',\n          propType: {\n            type: 'number',\n            isRequired: true,\n          },\n        },\n      ],\n    };\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})');\n    expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false);\n\n    // isRequired\n    const rule2 = {\n      type: 'shape',\n      value: [\n        {\n          name: 'a',\n          propType: {\n            type: 'string',\n            isRequired: true,\n          },\n        },\n        {\n          name: 'b',\n          propType: {\n            type: 'number',\n            isRequired: false,\n          },\n        },\n      ],\n    };\n    expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number})');\n    expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false);\n  });\n\n  // exact\n  it('should validate correctly with valid exact prop type', () => {\n    const rule = {\n      type: 'exact',\n      value: [\n        {\n          name: 'a',\n          propType: {\n            type: 'string',\n            isRequired: true,\n          },\n        },\n        {\n          name: 'b',\n          propType: {\n            type: 'number',\n            isRequired: true,\n          },\n        },\n      ],\n    };\n    expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})');\n    expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false);\n\n    // isRequired\n    const rule2 = {\n      type: 'exact',\n      value: [\n        {\n          name: 'a',\n          propType: {\n            type: 'string',\n            isRequired: true,\n          },\n        },\n        {\n          name: 'b',\n          propType: {\n            type: 'number',\n            isRequired: false,\n          },\n        },\n      ],\n    };\n    expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number})');\n    expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true);\n    expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false);\n  });\n});"
  },
  {
    "path": "packages/utils/test/src/check-types/is-action-content-object.test.ts",
    "content": "import { isActionContentObject } from '../../../src/check-types/is-action-content-object';\n\ndescribe('isActionContentObject', () => {\n  test('should return true for an object', () => {\n    const obj = { prop: 'value' };\n    expect(isActionContentObject(obj)).toBe(true);\n  });\n\n  test('should return false for a non-object', () => {\n    expect(isActionContentObject('not an object')).toBe(false);\n    expect(isActionContentObject(123)).toBe(false);\n    expect(isActionContentObject(null)).toBe(false);\n    expect(isActionContentObject(undefined)).toBe(false);\n  });\n\n  test('should return false for an empty object', () => {\n    const obj = {};\n    expect(isActionContentObject(obj)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-basic-prop-type.test.ts",
    "content": "import { isBasicPropType } from '../../../src';\n\ndescribe('test isBasicPropType ', () => {\n  it('should work', () => {\n    expect(isBasicPropType(null)).toBeFalsy();\n    expect(isBasicPropType(undefined)).toBeFalsy();\n    expect(isBasicPropType({})).toBeFalsy();\n    expect(isBasicPropType({ type: 'any other type' })).toBeFalsy();\n    expect(isBasicPropType('string')).toBeTruthy();\n  });\n});"
  },
  {
    "path": "packages/utils/test/src/check-types/is-custom-view.test.tsx",
    "content": "import React from 'react';\nimport { isCustomView } from '../../../src/check-types/is-custom-view';\nimport { IPublicTypeCustomView } from '@alilc/lowcode-types';\n\ndescribe('isCustomView', () => {\n  test('should return true when obj is a valid React element', () => {\n    const obj: IPublicTypeCustomView = <div>Hello, World!</div>;\n    expect(isCustomView(obj)).toBe(true);\n  });\n\n  test('should return true when obj is a valid React component', () => {\n    const MyComponent: React.FC = () => <div>Hello, World!</div>;\n    const obj: IPublicTypeCustomView = MyComponent;\n    expect(isCustomView(obj)).toBe(true);\n  });\n\n  test('should return false when obj is null or undefined', () => {\n    expect(isCustomView(null)).toBe(false);\n    expect(isCustomView(undefined)).toBe(false);\n  });\n\n  test('should return false when obj is not a valid React element or component', () => {\n    const obj: IPublicTypeCustomView = 'not a valid object';\n    expect(isCustomView(obj)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-dom-text.test.ts",
    "content": "import { isDOMText } from '../../../src/check-types/is-dom-text';\n\ndescribe('isDOMText', () => {\n  it('should return true when the input is a string', () => {\n    const result = isDOMText('Hello World');\n    expect(result).toBe(true);\n  });\n\n  it('should return false when the input is not a string', () => {\n    const result = isDOMText(123);\n    expect(result).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-drag-any-object.test.ts",
    "content": "import { isDragAnyObject } from '../../../src/check-types/is-drag-any-object';\nimport { IPublicEnumDragObjectType } from '@alilc/lowcode-types';\n\ndescribe('isDragAnyObject', () => {\n  it('should return false if obj is null', () => {\n    const result = isDragAnyObject(null);\n    expect(result).toBe(false);\n  });\n\n  it('should return false if obj is number', () => {\n    const result = isDragAnyObject(2);\n    expect(result).toBe(false);\n  });\n\n  it('should return false if obj.type is NodeData', () => {\n    const obj = { type: IPublicEnumDragObjectType.NodeData };\n    const result = isDragAnyObject(obj);\n    expect(result).toBe(false);\n  });\n\n  it('should return false if obj.type is Node', () => {\n    const obj = { type: IPublicEnumDragObjectType.Node };\n    const result = isDragAnyObject(obj);\n    expect(result).toBe(false);\n  });\n\n  it('should return true if obj.type is anything else', () => {\n    const obj = { type: 'SomeOtherType' };\n    const result = isDragAnyObject(obj);\n    expect(result).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-drag-node-data-object.test.ts",
    "content": "import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types';\nimport { isDragNodeDataObject } from '../../../src/check-types/is-drag-node-data-object';\n\ndescribe('isDragNodeDataObject', () => {\n  test('should return true for valid IPublicTypeDragNodeDataObject', () => {\n    const obj: IPublicTypeDragNodeDataObject = {\n      type: IPublicEnumDragObjectType.NodeData,\n      // 其他属性...\n    };\n\n    expect(isDragNodeDataObject(obj)).toBe(true);\n  });\n\n  test('should return false for invalid IPublicTypeDragNodeDataObject', () => {\n    const obj: any = {\n      type: 'InvalidType',\n      // 其他属性...\n    };\n\n    expect(isDragNodeDataObject(obj)).toBe(false);\n  });\n\n  test('should return false for null or undefined', () => {\n    expect(isDragNodeDataObject(null)).toBe(false);\n    expect(isDragNodeDataObject(undefined)).toBe(false);\n  });\n\n  // 可以添加更多测试用例...\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-drag-node-object.test.ts",
    "content": "import { IPublicEnumDragObjectType } from '@alilc/lowcode-types';\nimport { isDragNodeObject } from '../../../src/check-types/is-drag-node-object';\n\ndescribe('isDragNodeObject', () => {\n  it('should return true if the object is of IPublicTypeDragNodeObject type and has type IPublicEnumDragObjectType.Node', () => {\n    const obj = {\n      type: IPublicEnumDragObjectType.Node,\n      //... other properties\n    };\n\n    expect(isDragNodeObject(obj)).toBe(true);\n  });\n\n  it('should return false if the object is not of IPublicTypeDragNodeObject type', () => {\n    const obj = {\n      type: IPublicEnumDragObjectType.OtherType,\n      //... other properties\n    };\n\n    expect(isDragNodeObject(obj)).toBe(false);\n  });\n\n  it('should return false if the object is of IPublicTypeDragNodeObject type but type is not IPublicEnumDragObjectType.Node', () => {\n    const obj = {\n      type: IPublicEnumDragObjectType.OtherType,\n      //... other properties\n    };\n\n    expect(isDragNodeObject(obj)).toBe(false);\n  });\n\n  it('should return false if the object is null or undefined', () => {\n    expect(isDragNodeObject(null)).toBe(false);\n    expect(isDragNodeObject(undefined)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-dynamic-setter.test.ts",
    "content": "import { Component } from 'react';\nimport { isDynamicSetter } from '../../../src/check-types/is-dynamic-setter';\n\ndescribe('isDynamicSetter', () => {\n  it('returns true if input is a dynamic setter function', () => {\n    const dynamicSetter = (value: any) => {\n      // some implementation\n    };\n\n    expect(isDynamicSetter(dynamicSetter)).toBeTruthy();\n  });\n\n  it('returns false if input is not a dynamic setter function', () => {\n    expect(isDynamicSetter('not a function')).toBeFalsy();\n    expect(isDynamicSetter(null)).toBeFalsy();\n    expect(isDynamicSetter(undefined)).toBeFalsy();\n    expect(isDynamicSetter(2)).toBeFalsy();\n    expect(isDynamicSetter(0)).toBeFalsy();\n  });\n\n  it('returns false if input is a React class', () => {\n    class ReactClass extends Component {\n      // some implementation\n    }\n\n    expect(isDynamicSetter(ReactClass)).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-i18n-data.test.ts",
    "content": "import { isI18nData } from '../../../src/check-types/is-i18n-data';\nimport { IPublicTypeI18nData } from \"@alilc/lowcode-types\";\n\ndescribe('isI18nData', () => {\n  it('should return true for valid i18n data', () => {\n    const i18nData: IPublicTypeI18nData = {\n      type: 'i18n',\n      // add any other required properties here\n    };\n\n    expect(isI18nData(i18nData)).toBe(true);\n  });\n\n  it('should return false for invalid i18n data', () => {\n    const invalidData = {\n      type: 'some-other-type',\n      // add any other properties here\n    };\n\n    expect(isI18nData(invalidData)).toBe(false);\n  });\n\n  it('should return false for undefined or null', () => {\n    expect(isI18nData(undefined)).toBe(false);\n    expect(isI18nData(null)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-isfunction.test.ts",
    "content": "import { isInnerJsFunction, isJSFunction } from '../../../src/check-types/is-isfunction';\n\ndescribe('isInnerJsFunction', () => {\n  test('should return true for valid input', () => {\n    const data = {\n      type: 'JSExpression',\n      source: '',\n      value: '',\n      extType: 'function'\n    };\n\n    expect(isInnerJsFunction(data)).toBe(true);\n  });\n\n  test('should return false for invalid input', () => {\n    const data = {\n      type: 'JSExpression',\n      source: '',\n      value: '',\n      extType: 'object'\n    };\n\n    expect(isInnerJsFunction(data)).toBe(false);\n    expect(isInnerJsFunction(null)).toBe(false);\n    expect(isInnerJsFunction(undefined)).toBe(false);\n    expect(isInnerJsFunction(1)).toBe(false);\n    expect(isInnerJsFunction(0)).toBe(false);\n    expect(isInnerJsFunction('string')).toBe(false);\n    expect(isInnerJsFunction('')).toBe(false);\n  });\n});\n\ndescribe('isJSFunction', () => {\n  test('should return true for valid input', () => {\n    const data = {\n      type: 'JSFunction',\n    };\n\n    expect(isJSFunction(data)).toBe(true);\n  });\n\n  test('should return true for inner js function', () => {\n    const data = {\n      type: 'JSExpression',\n      source: '',\n      value: '',\n      extType: 'function'\n    };\n\n    expect(isJSFunction(data)).toBe(true);\n  });\n\n  test('should return false for invalid input', () => {\n    expect(isJSFunction(null)).toBe(false);\n    expect(isJSFunction(undefined)).toBe(false);\n    expect(isJSFunction('string')).toBe(false);\n    expect(isJSFunction('')).toBe(false);\n    expect(isJSFunction(0)).toBe(false);\n    expect(isJSFunction(2)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-jsblock.test.ts",
    "content": "import { isJSBlock } from '../../../src/check-types/is-jsblock';\n\ndescribe('isJSBlock', () => {\n  it('should return false if data is null or undefined', () => {\n    expect(isJSBlock(null)).toBe(false);\n    expect(isJSBlock(undefined)).toBe(false);\n  });\n\n  it('should return false if data is not an object', () => {\n    expect(isJSBlock('JSBlock')).toBe(false);\n    expect(isJSBlock(123)).toBe(false);\n    expect(isJSBlock(true)).toBe(false);\n  });\n\n  it('should return false if data.type is not \"JSBlock\"', () => {\n    expect(isJSBlock({ type: 'InvalidType' })).toBe(false);\n  });\n\n  it('should return true if data is an object and data.type is \"JSBlock\"', () => {\n    expect(isJSBlock({ type: 'JSBlock' })).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-jsexpression.test.ts",
    "content": "import { isJSExpression } from '../../../src/check-types/is-jsexpression';\n\ndescribe('isJSExpression', () => {\n  it('should return true if the input is a valid JSExpression object', () => {\n    const validJSExpression = {\n      type: 'JSExpression',\n      extType: 'variable',\n    };\n\n    const result = isJSExpression(validJSExpression);\n\n    expect(result).toBe(true);\n  });\n\n  it('should return false if the input is not a valid JSExpression object', () => {\n    const invalidJSExpression = {\n      type: 'JSExpression',\n      extType: 'function',\n    };\n\n    const result = isJSExpression(invalidJSExpression);\n\n    expect(result).toBe(false);\n  });\n\n  it('should return false if the input is null', () => {\n    const result = isJSExpression(null);\n\n    expect(result).toBe(false);\n  });\n\n  it('should return false if the input is undefined', () => {\n    const result = isJSExpression(undefined);\n\n    expect(result).toBe(false);\n  });\n\n  // 添加其他需要的测试\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-jsslot.test.ts",
    "content": "import { isJSSlot } from '../../../src/check-types/is-jsslot';\nimport { IPublicTypeJSSlot } from '@alilc/lowcode-types';\n\ndescribe('isJSSlot', () => {\n  it('should return true when input is of type IPublicTypeJSSlot', () => {\n    const input: IPublicTypeJSSlot = {\n      type: 'JSSlot',\n      // other properties of IPublicTypeJSSlot\n    };\n\n    const result = isJSSlot(input);\n\n    expect(result).toBe(true);\n  });\n\n  it('should return false when input is not of type IPublicTypeJSSlot', () => {\n    const input = {\n      type: 'OtherType',\n      // other properties\n    };\n\n    const result = isJSSlot(input);\n\n    expect(result).toBe(false);\n  });\n\n  it('should return false when input is null or undefined', () => {\n    const input1 = null;\n    const input2 = undefined;\n\n    const result1 = isJSSlot(input1);\n    const result2 = isJSSlot(input2);\n\n    expect(result1).toBe(false);\n    expect(result2).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-location-children-detail.test.ts",
    "content": "import { isLocationChildrenDetail } from '../../../src/check-types/is-location-children-detail';\nimport { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types';\n\ndescribe('isLocationChildrenDetail', () => {\n  it('should return true when obj is IPublicTypeLocationChildrenDetail', () => {\n    const obj: IPublicTypeLocationChildrenDetail = {\n      type: IPublicTypeLocationDetailType.Children,\n      // 添加其他必要的属性\n    };\n\n    expect(isLocationChildrenDetail(obj)).toBe(true);\n  });\n\n  it('should return false when obj is not IPublicTypeLocationChildrenDetail', () => {\n    const obj = {\n      type: 'other',\n      // 添加其他必要的属性\n    };\n\n    expect(isLocationChildrenDetail(obj)).toBe(false);\n    expect(isLocationChildrenDetail(null)).toBe(false);\n    expect(isLocationChildrenDetail(undefined)).toBe(false);\n    expect(isLocationChildrenDetail('string')).toBe(false);\n    expect(isLocationChildrenDetail(0)).toBe(false);\n    expect(isLocationChildrenDetail(2)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-location-data.test.ts",
    "content": "import { isLocationData } from '../../../src/check-types/is-location-data';\nimport { IPublicTypeLocationData } from '@alilc/lowcode-types';\n\ndescribe('isLocationData', () => {\n  it('should return true when obj is valid location data', () => {\n    const obj: IPublicTypeLocationData = {\n      target: 'some target',\n      detail: 'some detail',\n    };\n\n    const result = isLocationData(obj);\n\n    expect(result).toBe(true);\n  });\n\n  it('should return false when obj is missing target or detail', () => {\n    const obj1 = {\n      target: 'some target',\n      // missing detail\n    };\n\n    const obj2 = {\n      // missing target\n      detail: 'some detail',\n    };\n\n    const result1 = isLocationData(obj1);\n    const result2 = isLocationData(obj2);\n\n    expect(result1).toBe(false);\n    expect(result2).toBe(false);\n  });\n\n  it('should return false when obj is null or undefined', () => {\n    const obj1 = null;\n    const obj2 = undefined;\n\n    const result1 = isLocationData(obj1);\n    const result2 = isLocationData(obj2);\n\n    expect(result1).toBe(false);\n    expect(result2).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-lowcode-component-type.test.ts",
    "content": "import { isLowCodeComponentType } from '../../../src/check-types/is-lowcode-component-type';\nimport { IPublicTypeLowCodeComponent, IPublicTypeProCodeComponent } from '@alilc/lowcode-types';\n\ndescribe('isLowCodeComponentType', () => {\n  test('should return true for a low code component type', () => {\n    const desc: IPublicTypeLowCodeComponent = {\n      // create a valid low code component description\n    };\n\n    expect(isLowCodeComponentType(desc)).toBe(true);\n  });\n\n  test('should return false for a pro code component type', () => {\n    const desc: IPublicTypeProCodeComponent = {\n      // create a valid pro code component description\n      package: 'pro-code'\n    };\n\n    expect(isLowCodeComponentType(desc)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts",
    "content": "import { isLowcodeProjectSchema } from \"../../../src/check-types/is-lowcode-project-schema\";\n\ndescribe(\"isLowcodeProjectSchema\", () => {\n  it(\"should return false when data is null\", () => {\n    const result = isLowcodeProjectSchema(null);\n    expect(result).toBe(false);\n  });\n\n  it(\"should return false when data is undefined\", () => {\n    const result = isLowcodeProjectSchema(undefined);\n    expect(result).toBe(false);\n  });\n\n  it(\"should return false when data is not an object\", () => {\n    const result = isLowcodeProjectSchema(\"not an object\");\n    expect(result).toBe(false);\n  });\n\n  it(\"should return false when componentsTree is missing\", () => {\n    const data = { someKey: \"someValue\" };\n    const result = isLowcodeProjectSchema(data);\n    expect(result).toBe(false);\n  });\n\n  it(\"should return false when componentsTree is an empty array\", () => {\n    const data = { componentsTree: [] };\n    const result = isLowcodeProjectSchema(data);\n    expect(result).toBe(false);\n  });\n\n  it(\"should return false when the first element of componentsTree is not a component schema\", () => {\n    const data = { componentsTree: [{}] };\n    const result = isLowcodeProjectSchema(data);\n    expect(result).toBe(false);\n  });\n\n  it(\"should return true when all conditions are met\", () => {\n    const data = { componentsTree: [{ prop: \"value\", componentName: 'Component' }] };\n    const result = isLowcodeProjectSchema(data);\n    expect(result).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-node-schema.test.ts",
    "content": "import { isNodeSchema } from '../../../src/check-types/is-node-schema';\n\ndescribe('isNodeSchema', () => {\n  // 测试正常情况\n  it('should return true for valid IPublicTypeNodeSchema', () => {\n    const validData = {\n      componentName: 'Component',\n      isNode: false,\n    };\n    expect(isNodeSchema(validData)).toBe(true);\n  });\n\n  // 测试 null 或 undefined\n  it('should return false for null or undefined', () => {\n    expect(isNodeSchema(null)).toBe(false);\n    expect(isNodeSchema(undefined)).toBe(false);\n  });\n\n  // 测试没有componentName属性的情况\n  it('should return false if componentName is missing', () => {\n    const invalidData = {\n      isNode: false,\n    };\n    expect(isNodeSchema(invalidData)).toBe(false);\n  });\n\n  // 测试isNode为true的情况\n  it('should return false if isNode is true', () => {\n    const invalidData = {\n      componentName: 'Component',\n      isNode: true,\n    };\n    expect(isNodeSchema(invalidData)).toBe(false);\n  });\n\n  // 测试其他数据类型的情况\n  it('should return false for other data types', () => {\n    expect(isNodeSchema('string')).toBe(false);\n    expect(isNodeSchema(123)).toBe(false);\n    expect(isNodeSchema([])).toBe(false);\n    expect(isNodeSchema({})).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-node.test.ts",
    "content": "import { isNode } from '../../../src/check-types/is-node';\n\ndescribe('isNode', () => {\n  it('should return true for a valid node', () => {\n    const node = { isNode: true };\n    expect(isNode(node)).toBeTruthy();\n  });\n\n  it('should return false for an invalid node', () => {\n    const node = { isNode: false };\n    expect(isNode(node)).toBeFalsy();\n  });\n\n  it('should return false for an undefined node', () => {\n    expect(isNode(undefined)).toBeFalsy();\n  });\n\n  // Add more test cases if needed\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-procode-component-type.test.ts",
    "content": "import { isProCodeComponentType } from '../../../src/check-types/is-procode-component-type';\n\ndescribe('isProCodeComponentType', () => {\n  it('should return true if the given desc object contains \"package\" property', () => {\n    const desc = { package: 'packageName' };\n    expect(isProCodeComponentType(desc)).toBe(true);\n  });\n\n  it('should return false if the given desc object does not contain \"package\" property', () => {\n    const desc = { name: 'componentName' };\n    expect(isProCodeComponentType(desc)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-project-schema.test.ts",
    "content": "import { IPublicTypeProjectSchema } from \"@alilc/lowcode-types\";\nimport { isProjectSchema } from \"../../../src/check-types/is-project-schema\";\n\ndescribe(\"isProjectSchema\", () => {\n  it(\"should return true if data has componentsTree property\", () => {\n    const data: IPublicTypeProjectSchema = {\n      // ...\n      componentsTree: {\n        // ...\n      },\n    };\n    expect(isProjectSchema(data)).toBe(true);\n  });\n\n  it(\"should return false if data does not have componentsTree property\", () => {\n    const data = {\n      // ...\n    };\n    expect(isProjectSchema(data)).toBe(false);\n  });\n\n  it(\"should return false if data is null or undefined\", () => {\n    expect(isProjectSchema(null)).toBe(false);\n    expect(isProjectSchema(undefined)).toBe(false);\n  });\n\n  // 更多的测试用例...\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-required-prop-type.test.ts",
    "content": "import { isRequiredPropType } from '../../../src';\n\ndescribe('test isRequiredType', () => {\n  it('should work', () => {\n    expect(isRequiredPropType(null)).toBeFalsy();\n    expect(isRequiredPropType(undefined)).toBeFalsy();\n    expect(isRequiredPropType({})).toBeFalsy();\n    expect(isRequiredPropType({ type: 'any other type' })).toBeFalsy();\n    expect(isRequiredPropType('string')).toBeFalsy();\n    expect(isRequiredPropType({ type: 'string' })).toBeTruthy();\n    expect(isRequiredPropType({ type: 'string', isRequired: true })).toBeTruthy();\n  });\n})\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-setter-config.test.ts",
    "content": "import { isSetterConfig } from '../../../src/check-types/is-setter-config';\n\ndescribe('isSetterConfig', () => {\n  test('should return true for valid setter config', () => {\n    const config = {\n      componentName: 'MyComponent',\n      // Add other required properties here\n    };\n\n    expect(isSetterConfig(config)).toBe(true);\n  });\n\n  test('should return false for invalid setter config', () => {\n    const config = {\n      // Missing componentName property\n    };\n\n    expect(isSetterConfig(config)).toBe(false);\n    expect(isSetterConfig(null)).toBe(false);\n    expect(isSetterConfig(undefined)).toBe(false);\n    expect(isSetterConfig(0)).toBe(false);\n    expect(isSetterConfig(2)).toBe(false);\n  });\n\n  // Add more test cases for different scenarios you want to cover\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-setting-field.test.ts",
    "content": "import { isSettingField } from \"../../../src/check-types/is-setting-field\";\n\ndescribe(\"isSettingField\", () => {\n  it(\"should return true for an object that has isSettingField property\", () => {\n    const obj = { isSettingField: true };\n    expect(isSettingField(obj)).toBe(true);\n  });\n\n  it(\"should return false for an object that does not have isSettingField property\", () => {\n    const obj = { foo: \"bar\" };\n    expect(isSettingField(obj)).toBe(false);\n  });\n\n  it(\"should return false for a falsy value\", () => {\n    const obj = null;\n    expect(isSettingField(obj)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/check-types/is-title-config.test.ts",
    "content": "import { isTitleConfig } from '../../../src/check-types/is-title-config';\n\ndescribe('isTitleConfig', () => {\n  it('should return true for valid config object', () => {\n    const config = { title: 'My Title' };\n    expect(isTitleConfig(config)).toBe(true);\n  });\n\n  it('should return false for invalid config object', () => {\n    const config = { title: 'My Title', type: 'i18n' , i18nData: {} };\n    expect(isTitleConfig(config)).toBe(false);\n  });\n\n  it('should return false for non-object input', () => {\n    const config = 'invalid';\n    expect(isTitleConfig(config)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/clone-deep.test.ts",
    "content": "import { cloneDeep } from '../../src/clone-deep';\n\ndescribe('cloneDeep', () => {\n  it('should clone null', () => {\n    const src = null;\n    expect(cloneDeep(src)).toBeNull();\n  });\n\n  it('should clone undefined', () => {\n    const src = undefined;\n    expect(cloneDeep(src)).toBeUndefined();\n  });\n\n  it('should clone an array', () => {\n    const src = [1, 2, 3, 4];\n    expect(cloneDeep(src)).toEqual(src);\n  });\n\n  it('should clone an object', () => {\n    const src = { name: 'John', age: 25 };\n    expect(cloneDeep(src)).toEqual(src);\n  });\n\n  it('should deep clone nested objects', () => {\n    const src = { person: { name: 'John', age: 25 } };\n    const cloned = cloneDeep(src);\n    expect(cloned).toEqual(src);\n    expect(cloned.person).not.toBe(src.person);\n  });\n});"
  },
  {
    "path": "packages/utils/test/src/clone-enumerable-property.test.ts",
    "content": "import { cloneEnumerableProperty } from '../../src/clone-enumerable-property';\n\ndescribe('cloneEnumerableProperty', () => {\n  test('should clone enumerable properties from origin to target', () => {\n    // Arrange\n    const target = {};\n    const origin = { prop1: 1, prop2: 'hello', prop3: true };\n\n    // Act\n    const result = cloneEnumerableProperty(target, origin);\n\n    // Assert\n    expect(result).toBe(target);\n    expect(result).toEqual(origin);\n  });\n\n  test('should exclude properties specified in excludePropertyNames', () => {\n    // Arrange\n    const target = {};\n    const origin = { prop1: 1, prop2: 'hello', prop3: true };\n    const excludePropertyNames = ['prop2'];\n\n    // Act\n    const result = cloneEnumerableProperty(target, origin, excludePropertyNames);\n\n    // Assert\n    expect(result).toBe(target);\n    expect(result).toEqual({ prop1: 1, prop3: true });\n  });\n});"
  },
  {
    "path": "packages/utils/test/src/create-content.test.tsx",
    "content": "import React from 'react';\nimport { createContent } from '../../src/create-content';\n\nconst MyComponent = () => {\n  return <div>MyComponent</div>\n}\ndescribe('createContent', () => {\n  test('should return the same content if it is a valid React element', () => {\n    const content = <div>Hello</div>;\n    const result = createContent(content);\n\n    expect(result).toEqual(content);\n  });\n\n  test('should clone the element with props if props are provided', () => {\n    const content = <div></div>;\n    const props = { className: 'my-class' };\n    const result = createContent(content, props);\n\n    expect(result.props).toEqual(props);\n  });\n\n  test('should create an element with props if the content is a React component', () => {\n    const content = MyComponent;\n    const props = { className: 'my-class' };\n    const result = createContent(content, props);\n\n    expect(result.type).toEqual(content);\n    expect(result.props).toEqual(props);\n  });\n\n  test('should return the content if it is not a React element or a React component', () => {\n    const content = 'Hello';\n    const result = createContent(content);\n\n    expect(result).toEqual(content);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/create-defer.test.ts",
    "content": "import { createDefer } from '../../src/create-defer';\n\ndescribe('createDefer', () => {\n  it('should resolve with given value', async () => {\n    const defer = createDefer<number>();\n    defer.resolve(42);\n    const result = await defer.promise();\n    expect(result).toBe(42);\n  });\n\n  it('should reject with given reason', async () => {\n    const defer = createDefer<number>();\n    defer.reject('error');\n    await expect(defer.promise()).rejects.toEqual('error');\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/is-object.test.ts",
    "content": "import { isObject, isI18NObject } from '../../src/is-object';\n\ndescribe('isObject', () => {\n  it('should return true for an object', () => {\n    const obj = { key: 'value' };\n    const result = isObject(obj);\n    expect(result).toBe(true);\n  });\n\n  it('should return false for null', () => {\n    const result = isObject(null);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for a non-object value', () => {\n    const value = 42; // Not an object\n    const result = isObject(value);\n    expect(result).toBe(false);\n  });\n});\n\ndescribe('isI18NObject', () => {\n  it('should return true for an I18N object', () => {\n    const i18nObject = { type: 'i18n', data: 'some data' };\n    const result = isI18NObject(i18nObject);\n    expect(result).toBe(true);\n  });\n\n  it('should return false for a non-I18N object', () => {\n    const nonI18nObject = { type: 'other', data: 'some data' };\n    const result = isI18NObject(nonI18nObject);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for null', () => {\n    const result = isI18NObject(null);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for a non-object value', () => {\n    const value = 42; // Not an object\n    const result = isI18NObject(value);\n    expect(result).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/is-react.test.tsx",
    "content": "import React, { Component, createElement } from \"react\";\nimport {\n  isReactComponent,\n  wrapReactClass,\n  isForwardOrMemoForward,\n  isMemoType,\n  isForwardRefType,\n  acceptsRef,\n  isReactClass,\n  REACT_MEMO_TYPE,\n  REACT_FORWARD_REF_TYPE,\n } from \"../../src/is-react\";\n\nclass reactDemo extends React.Component {\n\n}\n\nconst reactMemo = React.memo(reactDemo);\n\nconst reactForwardRef = React.forwardRef((props, ref): any => {\n  return '';\n});\n\ndescribe('is-react-ut', () => {\n  it('isReactComponent', () => {\n    expect(isReactComponent(null)).toBeFalsy();\n    expect(isReactComponent(() => {})).toBeTruthy();\n    expect(isReactComponent({\n      $$typeof: Symbol.for('react.memo')\n    })).toBeTruthy();\n    expect(isReactComponent({\n      $$typeof: Symbol.for('react.forward_ref')\n    })).toBeTruthy();\n    expect(isReactComponent(reactDemo)).toBeTruthy();\n    expect(isReactComponent(reactMemo)).toBeTruthy();\n    expect(isReactComponent(reactForwardRef)).toBeTruthy();\n\n  });\n\n  it('wrapReactClass', () => {\n    const wrap = wrapReactClass(() => {});\n    expect(isReactComponent(wrap)).toBeTruthy();\n\n    const fun = () => {};\n    fun.displayName = 'mock';\n    expect(wrapReactClass(fun).displayName).toBe('mock');\n  })\n})\n\ndescribe('wrapReactClass', () => {\n  it('should wrap a FunctionComponent', () => {\n    // Create a mock FunctionComponent\n    const MockComponent: React.FunctionComponent = (props) => {\n      return <div>{props.children}</div>;\n    };\n\n    // Wrap the FunctionComponent using wrapReactClass\n    const WrappedComponent = wrapReactClass(MockComponent);\n    const instance = new WrappedComponent();\n\n    // Check if the WrappedComponent extends Component\n    expect(instance instanceof React.Component).toBe(true);\n  });\n\n  it('should render the FunctionComponent with props', () => {\n    // Create a mock FunctionComponent\n    const MockComponent: React.FunctionComponent = (props) => {\n      return <div>{props.children}</div>;\n    };\n\n    MockComponent.displayName = 'FunctionComponent';\n\n    // Wrap the FunctionComponent using wrapReactClass\n    const WrappedComponent = wrapReactClass(MockComponent);\n\n    // Create some test props\n    const testProps = { prop1: 'value1', prop2: 'value2' };\n\n    // Render the WrappedComponent with test props\n    const rendered = createElement(WrappedComponent, testProps, 'Child Text');\n\n    // Check if the WrappedComponent renders the FunctionComponent with props\n    expect(rendered).toMatchSnapshot();\n  });\n});\n\ndescribe('isReactComponent', () => {\n  it('should identify a class component as a React component', () => {\n    class ClassComponent extends React.Component {\n      render() {\n        return <div>Class Component</div>;\n      }\n    }\n\n    expect(isReactComponent(ClassComponent)).toBe(true);\n  });\n\n  it('should identify a functional component as a React component', () => {\n    const FunctionalComponent = () => {\n      return <div>Functional Component</div>;\n    };\n\n    expect(isReactComponent(FunctionalComponent)).toBe(true);\n  });\n\n  it('should identify a forward ref component as a React component', () => {\n    const ForwardRefComponent = React.forwardRef((props, ref) => {\n      return <div ref={ref}>Forward Ref Component</div>;\n    });\n\n    expect(isReactComponent(ForwardRefComponent)).toBe(true);\n  });\n\n  it('should identify a memo component as a React component', () => {\n    const MemoComponent = React.memo(() => {\n      return <div>Memo Component</div>;\n    });\n\n    expect(isReactComponent(MemoComponent)).toBe(true);\n  });\n\n  it('should return false for non-React components', () => {\n    const plainObject = { prop: 'value' };\n    const notAComponent = 'Not a component';\n\n    expect(isReactComponent(plainObject)).toBe(false);\n    expect(isReactComponent(notAComponent)).toBe(false);\n  });\n\n  it('should return false for null or undefined', () => {\n    const nullValue = null;\n    const undefinedValue = undefined;\n\n    expect(isReactComponent(nullValue)).toBe(false);\n    expect(isReactComponent(undefinedValue)).toBe(false);\n  });\n});\n\ndescribe('isForwardOrMemoForward', () => {\n  it('should return true for a forwardRef component', () => {\n    const forwardRefComponent = React.forwardRef(() => {\n      return <div>ForwardRef Component</div>;\n    });\n\n    expect(isForwardOrMemoForward(forwardRefComponent)).toBe(true);\n  });\n\n  it('should return true for a memoized forwardRef component', () => {\n    const forwardRefComponent = React.forwardRef(() => {\n      return <div>ForwardRef Component</div>;\n    });\n\n    const memoizedComponent = React.memo(forwardRefComponent);\n\n    expect(isForwardOrMemoForward(memoizedComponent)).toBe(true);\n  });\n\n  it('should return false for a memoized component that is not a forwardRef', () => {\n    const memoizedComponent = React.memo(() => {\n      return <div>Memoized Component</div>;\n    });\n\n    expect(isForwardOrMemoForward(memoizedComponent)).toBe(false);\n  });\n\n  it('should return false for a plain object', () => {\n    const plainObject = { prop: 'value' };\n\n    expect(isForwardOrMemoForward(plainObject)).toBe(false);\n  });\n\n  it('should return false for null or undefined', () => {\n    const nullValue = null;\n    const undefinedValue = undefined;\n\n    expect(isForwardOrMemoForward(nullValue)).toBe(false);\n    expect(isForwardOrMemoForward(undefinedValue)).toBe(false);\n  });\n});\n\ndescribe('isMemoType', () => {\n  it('should return true for an object with $$typeof matching REACT_MEMO_TYPE', () => {\n    const memoTypeObject = { $$typeof: REACT_MEMO_TYPE };\n\n    expect(isMemoType(memoTypeObject)).toBe(true);\n  });\n\n  it('should return false for an object with $$typeof not matching REACT_MEMO_TYPE', () => {\n    const otherTypeObject = { $$typeof: Symbol.for('other.type') };\n\n    expect(isMemoType(otherTypeObject)).toBe(false);\n  });\n\n  it('should return false for an object with no $$typeof property', () => {\n    const noTypeObject = { key: 'value' };\n\n    expect(isMemoType(noTypeObject)).toBe(false);\n  });\n\n  it('should return false for null or undefined', () => {\n    const nullValue = null;\n    const undefinedValue = undefined;\n\n    expect(isMemoType(nullValue)).toBe(false);\n    expect(isMemoType(undefinedValue)).toBe(false);\n  });\n});\n\ndescribe('isForwardRefType', () => {\n  it('should return true for an object with $$typeof matching REACT_FORWARD_REF_TYPE', () => {\n    const forwardRefTypeObject = { $$typeof: REACT_FORWARD_REF_TYPE };\n\n    expect(isForwardRefType(forwardRefTypeObject)).toBe(true);\n  });\n\n  it('should return false for an object with $$typeof not matching REACT_FORWARD_REF_TYPE', () => {\n    const otherTypeObject = { $$typeof: Symbol.for('other.type') };\n\n    expect(isForwardRefType(otherTypeObject)).toBe(false);\n  });\n\n  it('should return false for an object with no $$typeof property', () => {\n    const noTypeObject = { key: 'value' };\n\n    expect(isForwardRefType(noTypeObject)).toBe(false);\n  });\n\n  it('should return false for null or undefined', () => {\n    const nullValue = null;\n    const undefinedValue = undefined;\n\n    expect(isForwardRefType(nullValue)).toBe(false);\n    expect(isForwardRefType(undefinedValue)).toBe(false);\n  });\n});\n\ndescribe('acceptsRef', () => {\n  it('should return true for an object with isReactComponent in its prototype', () => {\n    const objWithIsReactComponent = {\n      prototype: {\n        isReactComponent: true,\n      },\n    };\n\n    expect(acceptsRef(objWithIsReactComponent)).toBe(true);\n  });\n\n  it('should return true for an object that is forwardRef or memoized forwardRef', () => {\n    const forwardRefObject = React.forwardRef(() => {\n      return null;\n    });\n\n    const memoizedForwardRefObject = React.memo(forwardRefObject);\n\n    expect(acceptsRef(forwardRefObject)).toBe(true);\n    expect(acceptsRef(memoizedForwardRefObject)).toBe(true);\n  });\n\n  it('should return false for an object without isReactComponent in its prototype', () => {\n    const objWithoutIsReactComponent = {\n      prototype: {\n        someOtherProperty: true,\n      },\n    };\n\n    expect(acceptsRef(objWithoutIsReactComponent)).toBe(false);\n  });\n\n  it('should return false for null or undefined', () => {\n    const nullValue = null;\n    const undefinedValue = undefined;\n\n    expect(acceptsRef(nullValue)).toBe(false);\n    expect(acceptsRef(undefinedValue)).toBe(false);\n  });\n});\n\ndescribe('isReactClass', () => {\n  it('should return true for an object with isReactComponent in its prototype', () => {\n    class ReactClassComponent extends Component {\n      render() {\n        return null;\n      }\n    }\n\n    expect(isReactClass(ReactClassComponent)).toBe(true);\n  });\n\n  it('should return true for an object with Component in its prototype chain', () => {\n    class CustomComponent extends Component {\n      render() {\n        return null;\n      }\n    }\n\n    expect(isReactClass(CustomComponent)).toBe(true);\n  });\n\n  it('should return false for an object without isReactComponent in its prototype', () => {\n    class NonReactComponent {\n      render() {\n        return null;\n      }\n    }\n\n    expect(isReactClass(NonReactComponent)).toBe(false);\n  });\n\n  it('should return false for null or undefined', () => {\n    const nullValue = null;\n    const undefinedValue = undefined;\n\n    expect(isReactClass(nullValue)).toBe(false);\n    expect(isReactClass(undefinedValue)).toBe(false);\n  });\n});"
  },
  {
    "path": "packages/utils/test/src/is-shaken.test.ts",
    "content": "import { isShaken } from '../../src/is-shaken';\n\ndescribe('isShaken', () => {\n  it('should return true if e1 has shaken property', () => {\n    const e1: any = { shaken: true };\n    const e2: MouseEvent | DragEvent = { target: null } as MouseEvent | DragEvent;\n\n    expect(isShaken(e1, e2)).toBe(true);\n  });\n\n  it('should return true if e1.target and e2.target are different', () => {\n    const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;\n    const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;\n\n    expect(isShaken(e1, e2)).toBe(true);\n  });\n\n  it('should return false if e1 and e2 targets are the same and distance is less than SHAKE_DISTANCE', () => {\n    const target = {};\n    const e1: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent;\n    const e2: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent;\n\n    // Assuming SHAKE_DISTANCE is 100\n    e1.clientY = 50;\n    e2.clientY = 50;\n\n    e1.clientX = 60;\n    e2.clientX = 60;\n\n    expect(isShaken(e1, e2)).toBe(false);\n  });\n\n  it('should return true if e1 and e2 targets are the same and distance is greater than SHAKE_DISTANCE', () => {\n    const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;\n    const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent;\n\n    // Assuming SHAKE_DISTANCE is 100\n    e1.clientY = 50;\n    e1.clientX = 50;\n    e2.clientY = 200;\n    e2.clientX = 200;\n\n    expect(isShaken(e1, e2)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/misc.test.ts",
    "content": "import {\n  isVariable,\n  isUseI18NSetter,\n  convertToI18NObject,\n  isString,\n  waitForThing,\n  arrShallowEquals,\n  isFromVC,\n  executePendingFn,\n  compatStage,\n  invariant,\n  isRegExp,\n  shouldUseVariableSetter,\n} from '../../src/misc';\nimport { IPublicModelComponentMeta } from '@alilc/lowcode-types';\n\ndescribe('isVariable', () => {\n  it('should return true for a variable object', () => {\n    const variable = { type: 'variable', variable: 'foo', value: 'bar' };\n    const result = isVariable(variable);\n    expect(result).toBe(true);\n  });\n\n  it('should return false for non-variable objects', () => {\n    const obj = { type: 'object' };\n    const result = isVariable(obj);\n    expect(result).toBe(false);\n  });\n});\n\ndescribe('isUseI18NSetter', () => {\n  it('should return true for a property with I18nSetter', () => {\n    const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'I18nSetter' } } }] } };\n    const propName = 'propName';\n    const result = isUseI18NSetter(prototype, propName);\n    expect(result).toBe(true);\n  });\n\n  it('should return false for a property without I18nSetter', () => {\n    const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'OtherSetter' } } }] } };\n    const propName = 'propName';\n    const result = isUseI18NSetter(prototype, propName);\n    expect(result).toBe(false);\n  });\n});\n\ndescribe('convertToI18NObject', () => {\n  it('should return the input if it is already an I18N object', () => {\n    const i18nObject = { type: 'i18n', use: 'en', en: 'Hello' };\n    const result = convertToI18NObject(i18nObject);\n    expect(result).toEqual(i18nObject);\n  });\n\n  it('should convert a string to an I18N object', () => {\n    const inputString = 'Hello';\n    const result = convertToI18NObject(inputString);\n    const expectedOutput = { type: 'i18n', use: 'zh-CN', 'zh-CN': inputString };\n    expect(result).toEqual(expectedOutput);\n  });\n});\n\ndescribe('isString', () => {\n  it('should return true for a string', () => {\n    const stringValue = 'Hello, world!';\n    const result = isString(stringValue);\n    expect(result).toBe(true);\n  });\n\n  it('should return true for an empty string', () => {\n    const emptyString = '';\n    const result = isString(emptyString);\n    expect(result).toBe(true);\n  });\n\n  it('should return false for a number', () => {\n    const numberValue = 42; // Not a string\n    const result = isString(numberValue);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for an object', () => {\n    const objectValue = { key: 'value' }; // Not a string\n    const result = isString(objectValue);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for null', () => {\n    const result = isString(null);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for undefined', () => {\n    const undefinedValue = undefined;\n    const result = isString(undefinedValue);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for a boolean', () => {\n    const booleanValue = true; // Not a string\n    const result = isString(booleanValue);\n    expect(result).toBe(false);\n  });\n});\n\ndescribe('waitForThing', () => {\n  it('should resolve immediately if the thing is available', async () => {\n    const obj = { prop: 'value' };\n    const path = 'prop';\n    const result = await waitForThing(obj, path);\n    expect(result).toBe('value');\n  });\n\n  it('should resolve after a delay if the thing becomes available', async () => {\n    const obj = { prop: undefined };\n    const path = 'prop';\n    const delay = 100; // Adjust the delay as needed\n    setTimeout(() => {\n      obj.prop = 'value';\n    }, delay);\n\n    const result = await waitForThing(obj, path);\n    expect(result).toBe('value');\n  });\n});\n\ndescribe('arrShallowEquals', () => {\n  it('should return true for two empty arrays', () => {\n    const arr1 = [];\n    const arr2 = [];\n    const result = arrShallowEquals(arr1, arr2);\n    expect(result).toBe(true);\n  });\n\n  it('should return true for two arrays with the same elements in the same order', () => {\n    const arr1 = [1, 2, 3];\n    const arr2 = [1, 2, 3];\n    const result = arrShallowEquals(arr1, arr2);\n    expect(result).toBe(true);\n  });\n\n  it('should return true for two arrays with the same elements in a different order', () => {\n    const arr1 = [1, 2, 3];\n    const arr2 = [3, 2, 1];\n    const result = arrShallowEquals(arr1, arr2);\n    expect(result).toBe(true);\n  });\n\n  it('should return false for two arrays with different lengths', () => {\n    const arr1 = [1, 2, 3];\n    const arr2 = [1, 2];\n    const result = arrShallowEquals(arr1, arr2);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for one array and a non-array', () => {\n    const arr1 = [1, 2, 3];\n    const nonArray = 'not an array';\n    const result = arrShallowEquals(arr1, nonArray);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for two arrays with different elements', () => {\n    const arr1 = [1, 2, 3];\n    const arr2 = [3, 4, 5];\n    const result = arrShallowEquals(arr1, arr2);\n    expect(result).toBe(false);\n  });\n\n  it('should return true for arrays with duplicate elements', () => {\n    const arr1 = [1, 2, 2, 3];\n    const arr2 = [2, 3, 3, 1];\n    const result = arrShallowEquals(arr1, arr2);\n    expect(result).toBe(true);\n  });\n});\n\ndescribe('isFromVC', () => {\n  it('should return true when advanced configuration is present', () => {\n    // Create a mock meta object with advanced configuration\n    const meta: IPublicModelComponentMeta = {\n      getMetadata: () => ({ configure: { advanced: true } }),\n    };\n\n    const result = isFromVC(meta);\n\n    expect(result).toBe(true);\n  });\n\n  it('should return false when advanced configuration is not present', () => {\n    // Create a mock meta object without advanced configuration\n    const meta: IPublicModelComponentMeta = {\n      getMetadata: () => ({ configure: { advanced: false } }),\n    };\n\n    const result = isFromVC(meta);\n\n    expect(result).toBe(false);\n  });\n\n  it('should return false when meta is undefined', () => {\n    const meta: IPublicModelComponentMeta | undefined = undefined;\n\n    const result = isFromVC(meta);\n\n    expect(result).toBe(false);\n  });\n\n  it('should return false when meta does not have configure information', () => {\n    // Create a mock meta object without configure information\n    const meta: IPublicModelComponentMeta = {\n      getMetadata: () => ({}),\n    };\n\n    const result = isFromVC(meta);\n\n    expect(result).toBe(false);\n  });\n\n  it('should return false when configure.advanced is not present', () => {\n    // Create a mock meta object with incomplete configure information\n    const meta: IPublicModelComponentMeta = {\n      getMetadata: () => ({ configure: {} }),\n    };\n\n    const result = isFromVC(meta);\n\n    expect(result).toBe(false);\n  });\n});\n\ndescribe('executePendingFn', () => {\n  it('should execute the provided function after the specified timeout', async () => {\n    // Mock the function to execute\n    const fn = jest.fn();\n\n    // Call executePendingFn with the mocked function and a short timeout\n    executePendingFn(fn, 100);\n\n    // Ensure the function has not been called immediately\n    expect(fn).not.toHaveBeenCalled();\n\n    // Wait for the specified timeout\n    await new Promise(resolve => setTimeout(resolve, 100));\n\n    // Ensure the function has been called after the timeout\n    expect(fn).toHaveBeenCalled();\n  });\n\n  it('should execute the provided function with a default timeout if not specified', async () => {\n    // Mock the function to execute\n    const fn = jest.fn();\n\n    // Call executePendingFn with the mocked function without specifying a timeout\n    executePendingFn(fn);\n\n    // Ensure the function has not been called immediately\n    expect(fn).not.toHaveBeenCalled();\n\n    // Wait for the default timeout (2000 milliseconds)\n    await new Promise(resolve => setTimeout(resolve, 2000));\n\n    // Ensure the function has been called after the default timeout\n    expect(fn).toHaveBeenCalled();\n  });\n});\n\ndescribe('compatStage', () => {\n  it('should convert a number to an enum stage', () => {\n    const result = compatStage(3);\n    expect(result).toBe('save');\n  });\n\n  it('should warn about the deprecated usage', () => {\n    const warnSpy = jest.spyOn(console, 'warn');\n    const result = compatStage(2);\n    expect(result).toBe('serilize');\n    expect(warnSpy).toHaveBeenCalledWith(\n      'stage 直接指定为数字的使用方式已经过时，将在下一版本移除，请直接使用 IPublicEnumTransformStage.Render|Serilize|Save|Clone|Init|Upgrade'\n    );\n    warnSpy.mockRestore();\n  });\n\n  it('should return the enum stage if it is already an enum', () => {\n    const result = compatStage('render');\n    expect(result).toBe('render');\n  });\n});\n\ndescribe('invariant', () => {\n  it('should not throw an error if the check is true', () => {\n    expect(() => invariant(true, 'Test invariant', 'thing')).not.toThrow();\n  });\n\n  it('should throw an error if the check is false', () => {\n    expect(() => invariant(false, 'Test invariant', 'thing')).toThrowError(\n      \"Invariant failed: Test invariant in 'thing'\"\n    );\n  });\n});\n\ndescribe('isRegExp', () => {\n  it('should return true for a valid RegExp', () => {\n    const regex = /test/;\n    const result = isRegExp(regex);\n    expect(result).toBe(true);\n  });\n\n  it('should return false for a non-RegExp object', () => {\n    const nonRegExp = { test: /test/ };\n    const result = isRegExp(nonRegExp);\n    expect(result).toBe(false);\n  });\n\n  it('should return false for null', () => {\n    const result = isRegExp(null);\n    expect(result).toBe(false);\n  });\n});\n\nit('shouldUseVariableSetter', () => {\n  expect(shouldUseVariableSetter(false, true)).toBeFalsy();\n  expect(shouldUseVariableSetter(true, true)).toBeTruthy();\n  expect(shouldUseVariableSetter(true, false)).toBeTruthy();\n  expect(shouldUseVariableSetter(undefined, false)).toBeFalsy();\n  expect(shouldUseVariableSetter(undefined, true)).toBeTruthy();\n});"
  },
  {
    "path": "packages/utils/test/src/navtive-selection.test.ts",
    "content": "import { setNativeSelection, nativeSelectionEnabled } from '../../src/navtive-selection';\n\ndescribe('setNativeSelection', () => {\n  beforeEach(() => {\n    // 在每个测试运行之前重置nativeSelectionEnabled的值\n    setNativeSelection(true);\n  });\n\n  test('should enable native selection', () => {\n    setNativeSelection(true);\n    expect(nativeSelectionEnabled).toBe(true);\n  });\n\n  test('should disable native selection', () => {\n    setNativeSelection(false);\n    expect(nativeSelectionEnabled).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/schema.test.ts",
    "content": "import {\n  compatibleLegaoSchema,\n  getNodeSchemaById,\n  applyActivities,\n} from '../../src/schema';\nimport { ActivityType } from '@alilc/lowcode-types';\n\ndescribe('compatibleLegaoSchema', () => {\n  it('should handle null input', () => {\n    const result = compatibleLegaoSchema(null);\n    expect(result).toBeNull();\n  });\n\n  it('should convert Legao schema to JSExpression', () => {\n    // Create your test input\n    const legaoSchema = {\n      type: 'LegaoType',\n      source: 'LegaoSource',\n      compiled: 'LegaoCompiled',\n    };\n    const result = compatibleLegaoSchema(legaoSchema);\n\n    // Define the expected output\n    const expectedOutput = {\n      type: 'JSExpression',\n      value: 'LegaoCompiled',\n      extType: 'function',\n    };\n\n    // Assert that the result matches the expected output\n    expect(result).toEqual(expectedOutput);\n  });\n\n  // Add more test cases for other scenarios\n});\n\ndescribe('getNodeSchemaById', () => {\n  it('should find a node in the schema', () => {\n    // Create your test schema and node ID\n    const testSchema = {\n      id: 'root',\n      children: [\n        {\n          id: 'child1',\n          children: [\n            {\n              id: 'child1.1',\n            },\n          ],\n        },\n      ],\n    };\n    const nodeId = 'child1.1';\n\n    const result = getNodeSchemaById(testSchema, nodeId);\n\n    // Define the expected output\n    const expectedOutput = {\n      id: 'child1.1',\n    };\n\n    // Assert that the result matches the expected output\n    expect(result).toEqual(expectedOutput);\n  });\n\n  // Add more test cases for other scenarios\n});\n\ndescribe('applyActivities', () => {\n  it('should apply ADD activity', () => {\n    // Create your test schema and activities\n    const testSchema = {\n      id: 'root',\n      children: [\n        {\n          id: 'child1',\n          children: [\n            {\n              id: 'child1.1',\n            },\n          ],\n        },\n      ],\n    };\n    const activities = [\n      {\n        type: ActivityType.ADDED,\n        payload: {\n          location: {\n            parent: {\n              nodeId: 'child1',\n              index: 0,\n            },\n          },\n          schema: {\n            id: 'newChild',\n          },\n        },\n      },\n    ];\n\n    const result = applyActivities(testSchema, activities);\n\n    // Define the expected output\n    const expectedOutput = {\n      id: 'root',\n      children: [\n        {\n          id: 'child1',\n          children: [\n            {\n              id: 'newChild',\n            },\n            {\n              id: 'child1.1',\n            },\n          ],\n        },\n      ],\n    };\n\n    // Assert that the result matches the expected output\n    expect(result).toEqual(expectedOutput);\n  });\n\n  // Add more test cases for other activity types and scenarios\n});\n\n\ndescribe('Schema Ut', () => {\n  it('props', () => {\n    const schema = {\n      props: {\n        mobileSlot: {\n          type: \"JSBlock\",\n          value: {\n            componentName: \"Slot\",\n            children: [\n              {\n                loop: {\n                  variable: \"props.content\",\n                  type: \"variable\"\n                },\n              }\n            ],\n          }\n        },\n      },\n  };\n\n    const result = compatibleLegaoSchema(schema);\n    expect(result).toMatchSnapshot();\n    expect(result.props.mobileSlot.value[0].loop.type).toBe('JSExpression');\n  });\n})"
  },
  {
    "path": "packages/utils/test/src/script.test.ts",
    "content": "import {\n  evaluate,\n  evaluateExpression,\n  newFunction,\n} from '../../src/script';\n\ndescribe('evaluate', () => {\n  test('should evaluate the given script', () => {\n    const script = 'console.log(\"Hello, world!\");';\n    global.console = { log: jest.fn() };\n\n    evaluate(script);\n\n    expect(global.console.log).toHaveBeenCalledWith('Hello, world!');\n  });\n});\n\ndescribe('evaluateExpression', () => {\n  test('should evaluate the given expression', () => {\n    const expr = 'return 1 + 2';\n\n    const result = evaluateExpression(expr);\n\n    expect(result).toBe(3);\n  });\n});\n\ndescribe('newFunction', () => {\n  test('should create a new function with the given arguments and code', () => {\n    const args = 'a, b';\n    const code = 'return a + b';\n\n    const result = newFunction(args, code);\n\n    expect(result).toBeInstanceOf(Function);\n    expect(result(1, 2)).toBe(3);\n  });\n\n  test('should return null if an error occurs', () => {\n    const args = 'a, b';\n    const code = 'return a +;'; // Invalid code\n\n    const result = newFunction(args, code);\n\n    expect(result).toBeNull();\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/svg-icon.test.tsx",
    "content": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport { SVGIcon, IconProps } from '../../src/svg-icon';\n\ndescribe('SVGIcon', () => {\n  it('should render SVG element with correct size', () => {\n    const iconProps: IconProps = {\n      size: 'small',\n      viewBox: '0 0 24 24',\n    };\n\n    const { container } = render(<SVGIcon {...iconProps} />);\n\n    const svgElement = container.querySelector('svg');\n\n    expect(svgElement).toHaveAttribute('width', '12');\n    expect(svgElement).toHaveAttribute('height', '12');\n  });\n\n  it('should render SVG element with custom size', () => {\n    const iconProps: IconProps = {\n      size: 24,\n      viewBox: '0 0 24 24',\n    };\n\n    const { container } = render(<SVGIcon {...iconProps} />);\n\n    const svgElement = container.querySelector('svg');\n\n    expect(svgElement).toHaveAttribute('width', '24');\n    expect(svgElement).toHaveAttribute('height', '24');\n  });\n\n  // Add more tests for other scenarios if needed\n});\n"
  },
  {
    "path": "packages/utils/test/src/transaction-manager.test.ts",
    "content": "import { transactionManager } from '../../src/transaction-manager';\nimport { IPublicEnumTransitionType } from '@alilc/lowcode-types';\n\nconst type = IPublicEnumTransitionType.REPAINT;\n\ndescribe('TransactionManager', () => {\n  let fn1: jest.Mock;\n  let fn2: jest.Mock;\n\n  beforeEach(() => {\n    fn1 = jest.fn();\n    fn2 = jest.fn();\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  test('executeTransaction should emit startTransaction and endTransaction events', () => {\n    const startTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit');\n    const endTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit');\n\n    transactionManager.executeTransaction(() => {\n      // Perform some action within the transaction\n    });\n\n    expect(startTransactionSpy).toHaveBeenCalledWith(`[${type}]startTransaction`);\n    expect(endTransactionSpy).toHaveBeenCalledWith(`[${type}]endTransaction`);\n  });\n\n  test('onStartTransaction should register the provided function for startTransaction event', () => {\n    const offSpy = jest.spyOn(transactionManager.emitter, 'off');\n\n    const offFunction = transactionManager.onStartTransaction(fn1);\n\n    expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(1);\n    expect(offSpy).not.toHaveBeenCalled();\n\n    offFunction();\n\n    expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(0);\n    expect(offSpy).toHaveBeenCalledWith(`[${type}]startTransaction`, fn1);\n  });\n\n  test('onEndTransaction should register the provided function for endTransaction event', () => {\n    const offSpy = jest.spyOn(transactionManager.emitter, 'off');\n\n    const offFunction = transactionManager.onEndTransaction(fn2);\n\n    expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(1);\n    expect(offSpy).not.toHaveBeenCalled();\n\n    offFunction();\n\n    expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(0);\n    expect(offSpy).toHaveBeenCalledWith(`[${type}]endTransaction`, fn2);\n  });\n});\n"
  },
  {
    "path": "packages/utils/test/src/unique-id.test.ts",
    "content": "import { uniqueId } from '../../src/unique-id';\n\ntest('uniqueId should return a unique id with prefix', () => {\n  const id = uniqueId('test');\n  expect(id.startsWith('test')).toBeTruthy();\n});\n\ntest('uniqueId should return a unique id without prefix', () => {\n  const id = uniqueId();\n  expect(id).not.toBeFalsy();\n});\n"
  },
  {
    "path": "packages/utils/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "packages/workspace/build.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\"\n  ]\n}\n"
  },
  {
    "path": "packages/workspace/build.test.json",
    "content": "{\n  \"plugins\": [\n    \"@alilc/build-plugin-lce\",\n    \"@alilc/lowcode-test-mate/plugin/index.ts\"\n  ]\n}\n"
  },
  {
    "path": "packages/workspace/jest.config.js",
    "content": "module.exports = {\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],\n  collectCoverage: true,\n  collectCoverageFrom: [\n    'src/**/*.{ts,tsx}',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n  ],\n};\n"
  },
  {
    "path": "packages/workspace/package.json",
    "content": "{\n  \"name\": \"@alilc/lowcode-workspace\",\n  \"version\": \"1.3.2\",\n  \"description\": \"Shell Layer for AliLowCodeEngine\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"files\": [\n    \"lib\",\n    \"es\"\n  ],\n  \"scripts\": {\n    \"build\": \"build-scripts build\",\n    \"test\": \"build-scripts test --config build.test.json\",\n    \"test:cov\": \"build-scripts test --config build.test.json --jest-coverage\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@alilc/lowcode-designer\": \"1.3.2\",\n    \"@alilc/lowcode-editor-core\": \"1.3.2\",\n    \"@alilc/lowcode-editor-skeleton\": \"1.3.2\",\n    \"@alilc/lowcode-types\": \"1.3.2\",\n    \"@alilc/lowcode-utils\": \"1.3.2\",\n    \"classnames\": \"^2.2.6\",\n    \"enzyme\": \"^3.11.0\",\n    \"enzyme-adapter-react-16\": \"^1.15.5\",\n    \"react\": \"^16\",\n    \"react-dom\": \"^16.7.0\"\n  },\n  \"devDependencies\": {\n    \"@alib/build-scripts\": \"^0.1.29\",\n    \"@testing-library/react\": \"^11.2.2\",\n    \"@types/classnames\": \"^2.2.7\",\n    \"@types/jest\": \"^26.0.16\",\n    \"@types/lodash\": \"^4.14.165\",\n    \"@types/medium-editor\": \"^5.0.3\",\n    \"@types/node\": \"^13.7.1\",\n    \"@types/react\": \"^16\",\n    \"@types/react-dom\": \"^16\",\n    \"jest\": \"^26.6.3\",\n    \"lodash\": \"^4.17.20\",\n    \"moment\": \"^2.29.1\",\n    \"typescript\": \"^4.0.3\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"repository\": {\n    \"type\": \"http\",\n    \"url\": \"https://github.com/alibaba/lowcode-engine/tree/main/packages/workspace\"\n  },\n  \"gitHead\": \"2669f179e6f899d395ce1942d0fe04f9c5ed48a6\",\n  \"bugs\": \"https://github.com/alibaba/lowcode-engine/issues\",\n  \"homepage\": \"https://github.com/alibaba/lowcode-engine/#readme\"\n}\n"
  },
  {
    "path": "packages/workspace/src/context/base-context.ts",
    "content": "import {\n  Editor,\n  engineConfig, Setters as InnerSetters,\n  Hotkey as InnerHotkey,\n  commonEvent,\n  IEngineConfig,\n  IHotKey,\n  Command as InnerCommand,\n} from '@alilc/lowcode-editor-core';\nimport {\n  Designer,\n  ILowCodePluginContextApiAssembler,\n  LowCodePluginManager,\n  ILowCodePluginContextPrivate,\n  IProject,\n  IDesigner,\n  ILowCodePluginManager,\n} from '@alilc/lowcode-designer';\nimport {\n  ISkeleton,\n  Skeleton as InnerSkeleton,\n} from '@alilc/lowcode-editor-skeleton';\nimport {\n  Hotkey,\n  Plugins,\n  Project,\n  Skeleton,\n  Setters,\n  Material,\n  Event,\n  Common,\n  Logger,\n  Workspace,\n  Window,\n  Canvas,\n  CommonUI,\n  Command,\n} from '@alilc/lowcode-shell';\nimport {\n  IPluginPreferenceMananger,\n  IPublicApiCanvas,\n  IPublicApiCommon,\n  IPublicApiEvent,\n  IPublicApiHotkey,\n  IPublicApiMaterial,\n  IPublicApiPlugins,\n  IPublicApiProject,\n  IPublicApiSetters,\n  IPublicApiSkeleton,\n  IPublicEnumPluginRegisterLevel,\n  IPublicModelPluginContext,\n  IPublicTypePluginMeta,\n} from '@alilc/lowcode-types';\nimport { getLogger, Logger as InnerLogger } from '@alilc/lowcode-utils';\nimport { IWorkspace } from '../workspace';\nimport { IEditorWindow } from '../window';\n\nexport interface IBasicContext extends Omit<IPublicModelPluginContext, 'workspace'> {\n  skeleton: IPublicApiSkeleton;\n  plugins: IPublicApiPlugins;\n  project: IPublicApiProject;\n  setters: IPublicApiSetters;\n  material: IPublicApiMaterial;\n  common: IPublicApiCommon;\n  config: IEngineConfig;\n  event: IPublicApiEvent;\n  logger: InnerLogger;\n  hotkey: IPublicApiHotkey;\n  innerProject: IProject;\n  editor: Editor;\n  designer: IDesigner;\n  registerInnerPlugins: () => Promise<void>;\n  innerSetters: InnerSetters;\n  innerSkeleton: ISkeleton;\n  innerHotkey: IHotKey;\n  innerPlugins: ILowCodePluginManager;\n  canvas: IPublicApiCanvas;\n  pluginEvent: IPublicApiEvent;\n  preference: IPluginPreferenceMananger;\n  workspace: IWorkspace;\n}\n\nexport class BasicContext implements IBasicContext {\n  skeleton: IPublicApiSkeleton;\n  plugins: IPublicApiPlugins;\n  project: IPublicApiProject;\n  setters: IPublicApiSetters;\n  material: IPublicApiMaterial;\n  common: IPublicApiCommon;\n  config: IEngineConfig;\n  event: IPublicApiEvent;\n  logger: InnerLogger;\n  hotkey: IPublicApiHotkey;\n  innerProject: IProject;\n  editor: Editor;\n  designer: IDesigner;\n  registerInnerPlugins: () => Promise<void>;\n  innerSetters: InnerSetters;\n  innerSkeleton: ISkeleton;\n  innerHotkey: IHotKey;\n  innerPlugins: ILowCodePluginManager;\n  canvas: IPublicApiCanvas;\n  pluginEvent: IPublicApiEvent;\n  preference: IPluginPreferenceMananger;\n  workspace: IWorkspace;\n\n  constructor(innerWorkspace: IWorkspace, viewName: string, readonly registerLevel: IPublicEnumPluginRegisterLevel, public editorWindow?: IEditorWindow) {\n    const editor = new Editor(viewName, true);\n\n    const innerSkeleton = new InnerSkeleton(editor, viewName);\n    editor.set('skeleton' as any, innerSkeleton);\n\n    const designer: Designer = new Designer({\n      editor,\n      viewName,\n      shellModelFactory: innerWorkspace?.shellModelFactory,\n    });\n    editor.set('designer' as any, designer);\n\n    const { project: innerProject } = designer;\n    const workspace = new Workspace(innerWorkspace);\n    const innerHotkey = new InnerHotkey(viewName);\n    const hotkey = new Hotkey(innerHotkey, true);\n    const innerSetters = new InnerSetters(viewName);\n    const setters = new Setters(innerSetters, true);\n    const material = new Material(editor, true);\n    const project = new Project(innerProject, true);\n    const config = engineConfig;\n    const event = new Event(commonEvent, { prefix: 'common' });\n    const logger = getLogger({ level: 'warn', bizName: 'common' });\n    const skeleton = new Skeleton(innerSkeleton, 'any', true);\n    const canvas = new Canvas(editor, true);\n    const commonUI = new CommonUI(editor);\n    const innerCommand = new InnerCommand();\n    editor.set('setters', setters);\n    editor.set('project', project);\n    editor.set('material', material);\n    editor.set('hotkey', hotkey);\n    editor.set('innerHotkey', innerHotkey);\n    this.innerSetters = innerSetters;\n    this.innerSkeleton = innerSkeleton;\n    this.skeleton = skeleton;\n    this.innerProject = innerProject;\n    this.project = project;\n    this.setters = setters;\n    this.material = material;\n    this.config = config;\n    this.event = event;\n    this.logger = logger;\n    this.hotkey = hotkey;\n    this.innerHotkey = innerHotkey;\n    this.editor = editor;\n    this.designer = designer;\n    this.canvas = canvas;\n    const common = new Common(editor, innerSkeleton);\n    this.common = common;\n    let plugins: IPublicApiPlugins;\n\n    const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {\n      assembleApis: (context: ILowCodePluginContextPrivate, pluginName: string, meta: IPublicTypePluginMeta) => {\n        context.workspace = workspace;\n        context.hotkey = hotkey;\n        context.project = project;\n        context.skeleton = new Skeleton(innerSkeleton, pluginName, true);\n        context.setters = setters;\n        context.material = material;\n        const eventPrefix = meta?.eventPrefix || 'common';\n        const commandScope = meta?.commandScope;\n        context.event = new Event(commonEvent, { prefix: eventPrefix });\n        context.config = config;\n        context.common = common;\n        context.plugins = plugins;\n        context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` });\n        context.canvas = canvas;\n        context.commonUI = commonUI;\n        if (editorWindow) {\n          context.editorWindow = new Window(editorWindow);\n        }\n        context.command = new Command(innerCommand, context as IPublicModelPluginContext, {\n          commandScope,\n        });\n        context.registerLevel = registerLevel;\n        context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace;\n        editor.set('pluginContext', context);\n      },\n    };\n\n    const innerPlugins = new LowCodePluginManager(pluginContextApiAssembler, viewName);\n    this.innerPlugins = innerPlugins;\n    plugins = new Plugins(innerPlugins, true).toProxy();\n    editor.set('plugins' as any, plugins);\n    editor.set('innerPlugins' as any, innerPlugins);\n    this.plugins = plugins;\n\n    // 注册一批内置插件\n    this.registerInnerPlugins = async function registerPlugins() {\n      await innerWorkspace?.registryInnerPlugin(designer, editor, plugins);\n    };\n  }\n}"
  },
  {
    "path": "packages/workspace/src/context/view-context.ts",
    "content": "import { computed, makeObservable, obx } from '@alilc/lowcode-editor-core';\nimport { IPublicEditorViewConfig, IPublicEnumPluginRegisterLevel, IPublicTypeEditorView } from '@alilc/lowcode-types';\nimport { flow } from 'mobx';\nimport { IWorkspace } from '../workspace';\nimport { BasicContext, IBasicContext } from './base-context';\nimport { IEditorWindow } from '../window';\nimport { getWebviewPlugin } from '../inner-plugins/webview';\n\nexport interface IViewContext extends IBasicContext {\n  editorWindow: IEditorWindow;\n\n  viewName: string;\n\n  viewType: 'editor' | 'webview';\n}\n\nexport class Context extends BasicContext implements IViewContext {\n  viewName = 'editor-view';\n\n  instance: IPublicEditorViewConfig;\n\n  viewType: 'editor' | 'webview';\n\n  @obx _activate = false;\n\n  @obx isInit: boolean = false;\n\n  init = flow(function* (this: Context) {\n    if (this.viewType === 'webview') {\n      const url = yield this.instance?.url?.();\n      yield this.plugins.register(getWebviewPlugin(url, this.viewName));\n    } else {\n      yield this.registerInnerPlugins();\n    }\n    yield this.instance?.init?.();\n    yield this.innerPlugins.init();\n    this.isInit = true;\n  });\n\n  constructor(public workspace: IWorkspace, public editorWindow: IEditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) {\n    super(workspace, editorView.viewName, IPublicEnumPluginRegisterLevel.EditorView, editorWindow);\n    this.viewType = editorView.viewType || 'editor';\n    this.viewName = editorView.viewName;\n    this.instance = editorView(this.innerPlugins._getLowCodePluginContext({\n      pluginName: 'any',\n    }), options);\n    makeObservable(this);\n  }\n\n  @computed get active() {\n    return this._activate;\n  }\n\n  onSimulatorRendererReady = (): Promise<void> => {\n    return new Promise((resolve) => {\n      this.project.onSimulatorRendererReady(() => {\n        resolve();\n      });\n    });\n  };\n\n  setActivate = (_activate: boolean) => {\n    this._activate = _activate;\n    this.innerHotkey.activate(this._activate);\n  };\n\n  async save() {\n    return await this.instance?.save?.();\n  }\n}"
  },
  {
    "path": "packages/workspace/src/index.ts",
    "content": "export { Workspace } from './workspace';\nexport type { IWorkspace } from './workspace';\nexport * from './window';\nexport * from './layouts/workbench';\nexport { Resource } from './resource';\nexport type { IResource } from './resource';\nexport type { IViewContext } from './context/view-context';\n"
  },
  {
    "path": "packages/workspace/src/inner-plugins/webview.tsx",
    "content": "import { IPublicModelPluginContext } from '@alilc/lowcode-types';\n\nexport function DesignerView(props: {\n  url: string;\n  viewName?: string;\n}) {\n  return (\n    <div className=\"lc-designer lowcode-plugin-designer\">\n      <div className=\"lc-project\">\n        <div className=\"lc-simulator-shell\">\n          <iframe\n            name={`webview-view-${props.viewName}`}\n            className=\"lc-simulator-content-frame\"\n            style={{\n              height: '100%',\n              width: '100%',\n            }}\n            src={props.url}\n          />\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport function getWebviewPlugin(url: string, viewName: string) {\n  function webviewPlugin(ctx: IPublicModelPluginContext) {\n    const { skeleton } = ctx;\n    return {\n      init() {\n        skeleton.add({\n          area: 'mainArea',\n          name: 'designer',\n          type: 'Widget',\n          content: DesignerView,\n          contentProps: {\n            ctx,\n            url,\n            viewName,\n          },\n        });\n      },\n    };\n  }\n\n  webviewPlugin.pluginName = '___webview_plugin___';\n\n  return webviewPlugin;\n}\n"
  },
  {
    "path": "packages/workspace/src/layouts/workbench.tsx",
    "content": "import { Component } from 'react';\nimport { TipContainer, engineConfig, observer } from '@alilc/lowcode-editor-core';\nimport { WindowView } from '../view/window-view';\nimport classNames from 'classnames';\nimport { SkeletonContext } from '../skeleton-context';\nimport { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';\nimport { Workspace } from '../workspace';\nimport { BottomArea, LeftArea, LeftFixedPane, LeftFloatPane, MainArea, SubTopArea, TopArea } from '@alilc/lowcode-editor-skeleton';\n\n@observer\nexport class Workbench extends Component<{\n  workspace: Workspace;\n  config?: EditorConfig;\n  components?: PluginClassSet;\n  className?: string;\n  topAreaItemClassName?: string;\n}, {\n  workspaceEmptyComponent: any;\n  theme?: string;\n}> {\n  constructor(props: any) {\n    super(props);\n    const { config, components, workspace } = this.props;\n    const { skeleton } = workspace;\n    skeleton.buildFromConfig(config, components);\n    engineConfig.onGot('theme', (theme) => {\n      this.setState({\n        theme,\n      });\n    });\n    engineConfig.onGot('workspaceEmptyComponent', (workspaceEmptyComponent) => {\n      this.setState({\n        workspaceEmptyComponent,\n      });\n    });\n    this.state = {\n      workspaceEmptyComponent: engineConfig.get('workspaceEmptyComponent'),\n      theme: engineConfig.get('theme'),\n    };\n  }\n\n  render() {\n    const { workspace, className, topAreaItemClassName } = this.props;\n    const { skeleton } = workspace;\n    const { workspaceEmptyComponent: WorkspaceEmptyComponent, theme } = this.state;\n\n    return (\n      <div className={classNames('lc-workspace-workbench', className, theme)}>\n        <SkeletonContext.Provider value={skeleton}>\n          <TopArea className=\"lc-workspace-top-area\" area={skeleton.topArea} itemClassName={topAreaItemClassName} />\n          <div className=\"lc-workspace-workbench-body\">\n            <LeftArea className=\"lc-workspace-left-area lc-left-area\" area={skeleton.leftArea} />\n            <LeftFloatPane area={skeleton.leftFloatArea} />\n            <LeftFixedPane area={skeleton.leftFixedArea} />\n            <div className=\"lc-workspace-workbench-center\">\n              <div className=\"lc-workspace-workbench-center-content\">\n                <SubTopArea area={skeleton.subTopArea} itemClassName={topAreaItemClassName} />\n                <div className=\"lc-workspace-workbench-window\">\n                  {\n                    workspace.windows.map(d => (\n                      <WindowView\n                        active={d.id === workspace.window?.id}\n                        window={d}\n                        key={d.id}\n                      />\n                    ))\n                  }\n\n                  {\n                    !workspace.windows.length && WorkspaceEmptyComponent ? <WorkspaceEmptyComponent /> : null\n                  }\n                </div>\n              </div>\n              <MainArea area={skeleton.mainArea} />\n              <BottomArea area={skeleton.bottomArea} />\n            </div>\n            {/* <RightArea area={skeleton.rightArea} /> */}\n          </div>\n          <TipContainer />\n        </SkeletonContext.Provider>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/workspace/src/less-variables.less",
    "content": "/*\n * 基础的 DPL 定义使用了 kuma base 的定义，参考：\n * https://github.com/uxcore/kuma-base/tree/master/variables\n */\n\n/**\n * ===========================================================\n * ==================== Font Family ==========================\n * ===========================================================\n */\n\n/*\n * @font-family: \"STHeiti\", \"Microsoft Yahei\", \"Lucida Grande\", \"Lucida Sans Unicode\", Helvetica, Arial, Verdana, sans-serif;\n */\n\n@font-family: 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial, sans-serif;\n@font-family-code: Monaco, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial,\n  sans-serif;\n\n/**\n * ===========================================================\n * ===================== Color DPL ===========================\n * ===========================================================\n  */\n\n@brand-color-1: rgba(0, 108, 255, 1);\n@brand-color-2: rgba(25, 122, 255, 1);\n@brand-color-3: rgba(0, 96, 229, 1);\n\n@brand-color-1-3: rgba(0, 108, 255, 0.6);\n@brand-color-1-4: rgba(0, 108, 255, 0.4);\n@brand-color-1-5: rgba(0, 108, 255, 0.3);\n@brand-color-1-6: rgba(0, 108, 255, 0.2);\n@brand-color-1-7: rgba(0, 108, 255, 0.1);\n\n@brand-color: @brand-color-1;\n\n@white-alpha-1: rgb(255, 255, 255); // W-1\n@white-alpha-2: rgba(255, 255, 255, 0.8); // W-2 A80\n@white-alpha-3: rgba(255, 255, 255, 0.6); // W-3 A60\n@white-alpha-4: rgba(255, 255, 255, 0.4); // W-4 A40\n@white-alpha-5: rgba(255, 255, 255, 0.3); // W-5 A30\n@white-alpha-6: rgba(255, 255, 255, 0.2); // W-6 A20\n@white-alpha-7: rgba(255, 255, 255, 0.1); // W-7 A10\n@white-alpha-8: rgba(255, 255, 255, 0.06); // W-8 A6\n\n@dark-alpha-1: rgba(0, 0, 0, 1); // D-1 A100\n@dark-alpha-2: rgba(0, 0, 0, 0.8); // D-2 A80\n@dark-alpha-3: rgba(0, 0, 0, 0.6); // D-3 A60\n@dark-alpha-4: rgba(0, 0, 0, 0.4); // D-4 A40\n@dark-alpha-5: rgba(0, 0, 0, 0.3); // D-5 A30\n@dark-alpha-6: rgba(0, 0, 0, 0.2); // D-6 A20\n@dark-alpha-7: rgba(0, 0, 0, 0.1); // D-7 A10\n@dark-alpha-8: rgba(0, 0, 0, 0.06); // D-8 A6\n@dark-alpha-9: rgba(0, 0, 0, 0.04); // D-9 A4\n\n@normal-alpha-1: rgba(31, 56, 88, 1); // N-1 A100\n@normal-alpha-2: rgba(31, 56, 88, 0.8); // N-2 A80\n@normal-alpha-3: rgba(31, 56, 88, 0.6); // N-3 A60\n@normal-alpha-4: rgba(31, 56, 88, 0.4); // N-4 A40\n@normal-alpha-5: rgba(31, 56, 88, 0.3); // N-5 A30\n@normal-alpha-6: rgba(31, 56, 88, 0.2); // N-6 A20\n@normal-alpha-7: rgba(31, 56, 88, 0.1); // N-7 A10\n@normal-alpha-8: rgba(31, 56, 88, 0.06); // N-8 A6\n@normal-alpha-9: rgba(31, 56, 88, 0.04); // N-9 A4\n\n@normal-3: #77879c;\n@normal-4: #a3aebd;\n@normal-5: #bac3cc;\n@normal-6: #d1d7de;\n\n@gray-dark: #333; // N2_4\n@gray: #666; // N2_3\n@gray-light: #999; // N2_2\n@gray-lighter: #ccc; // N2_1\n\n@brand-secondary: #2c2f33; // B2_3\n// 补色\n@brand-complement: #00b3e8; // B3_1\n// 复合\n@brand-comosite: #00c587; // B3_2\n// 浓度\n@brand-deep: #73461d; // B3_3\n\n// F1-1\n@brand-danger: rgb(240, 70, 49);\n// F1-2 (10% white)\n@brand-danger-hover: rgba(240, 70, 49, 0.9);\n// F1-3 (5% black)\n@brand-danger-focus: rgba(240, 70, 49, 0.95);\n\n// F2-1\n@brand-warning: rgb(250, 189, 14);\n// F3-1\n@brand-success: rgb(102, 188, 92);\n// F4-1\n@brand-link: rgb(102, 188, 92);\n// F4-2\n@brand-link-hover: #2e76a6;\n\n// F1-1-7 A10\n@brand-danger-alpha-7: rgba(240, 70, 49, 0.1);\n// F1-1-8 A6\n@brand-danger-alpha-8: rgba(240, 70, 49, 0.8);\n// F2-1-2 A80\n@brand-warning-alpha-2: rgba(250, 189, 14, 0.8);\n// F2-1-7 A10\n@brand-warning-alpha-7: rgba(250, 189, 14, 0.1);\n// F3-1-2 A80\n@brand-success-alpha-2: rgba(102, 188, 92, 0.8);\n// F3-1-7 A10\n@brand-success-alpha-7: rgba(102, 188, 92, 0.1);\n// F4-1-7 A10\n@brand-link-alpha-7: rgba(102, 188, 92, 0.1);\n\n// 文本色\n@text-primary-color: @dark-alpha-3;\n@text-secondary-color: @normal-alpha-3;\n@text-thirdary-color: @dark-alpha-4;\n@text-disabled-color: @normal-alpha-5;\n@text-helper-color: @dark-alpha-4;\n@text-danger-color: @brand-danger;\n@text-ali-color: #ec6c00;\n\n/**\n  * ===========================================================\n  * =================== Shadow Box ============================\n  * ===========================================================\n  */\n\n@box-shadow-1: 0 1px 4px 0 rgba(31, 56, 88, 0.15); // 1 级阴影，物体由原来存在于底面的物体展开，物体和底面关联紧密\n@box-shadow-2: 0 2px 10px 0 rgba(31, 56, 88, 0.15); // 2 级阴影，hover状态，物体层级较高\n@box-shadow-3: 0 4px 15px 0 rgba(31, 56, 88, 0.15); // 3 级阴影，当物体层级高于所有界面元素，弹窗用\n\n/**\n  * ===========================================================\n  * ================= FontSize of Level =======================\n  * ===========================================================\n  */\n\n@fontSize-1: 26px;\n@fontSize-2: 20px;\n@fontSize-3: 16px;\n@fontSize-4: 14px;\n@fontSize-5: 12px;\n\n@fontLineHeight-1: 38px;\n@fontLineHeight-2: 30px;\n@fontLineHeight-3: 26px;\n@fontLineHeight-4: 24px;\n@fontLineHeight-5: 20px;\n\n/**\n  * ===========================================================\n  * ================= FontSize of Level =======================\n  * ===========================================================\n  */\n\n@global-border-radius: 3px;\n@input-border-radius: 3px;\n@popup-border-radius: 6px;\n\n/**\n  * ===========================================================\n  * ===================== Transistion =========================\n  * ===========================================================\n  */\n\n@transition-duration: 0.3s;\n@transition-ease: cubic-bezier(0.23, 1, 0.32, 1);\n@transition-delay: 0s;\n\n/**\n  * ===========================================================\n  * ================ Global Configruations ====================\n  * ===========================================================\n  */\n\n@topPaneHeight: 48px;\n@actionpane-height: 48px;\n@tabPaneWidth: 260px;\n@input-standard-height: 32px;\n@dockpane-width: 48px;\n\n/**\n  * ===========================================================\n  * =================== Deprecated Items ======================\n  * ===========================================================\n  */\n\n@head-bgcolor: @white-alpha-1;\n@pane-bgcolor: @white-alpha-1;\n@pane-dark-bgcolor: @white-alpha-1;\n@pane-bdcolor: @normal-4;\n@blank-bgcolor: @normal-5;\n@title-bgcolor: @white-alpha-1;\n@title-bdcolor: transparent;\n@section-bgcolor: transparent;\n@section-bdcolor: @white-alpha-1;\n@button-bgcolor: @white-alpha-1;\n@button-bdcolor: transparent;\n@button-blue-color: @brand-color;\n@button-blue-hover-color: @brand-color;\n@sub-title-bgcolor: @white-alpha-1;\n@sub-title-bdcolor: transparent;\n@text-color: @text-primary-color;\n@icon-color: @gray;\n@icon-color-active: @gray-light;\n@ghost-bgcolor: @dark-alpha-3;\n@input-bgcolor: transparent;\n@input-bdcolor: @normal-alpha-5;\n@hover-color: #5a99cc;\n@active-color: #5a99cc;\n@disabled-color: #666;\n@setter-popup-bg: rgb(80, 86, 109);\n"
  },
  {
    "path": "packages/workspace/src/resource-type.ts",
    "content": "import { IPublicTypeResourceType } from '@alilc/lowcode-types';\n\nexport interface IResourceType extends Omit<IPublicTypeResourceType, 'resourceName' | 'resourceType'> {\n  name: string;\n\n  type: 'editor' | 'webview';\n\n  resourceTypeModel: IPublicTypeResourceType;\n}\n\nexport class ResourceType implements IResourceType {\n  constructor(readonly resourceTypeModel: IPublicTypeResourceType) {\n  }\n\n  get name() {\n    return this.resourceTypeModel.resourceName;\n  }\n\n  get type() {\n    return this.resourceTypeModel.resourceType;\n  }\n}"
  },
  {
    "path": "packages/workspace/src/resource.ts",
    "content": "import { ISkeleton } from '@alilc/lowcode-editor-skeleton';\nimport { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource, IPublicEnumPluginRegisterLevel } from '@alilc/lowcode-types';\nimport { Logger } from '@alilc/lowcode-utils';\nimport { BasicContext, IBasicContext } from './context/base-context';\nimport { ResourceType, IResourceType } from './resource-type';\nimport { IWorkspace } from './workspace';\n\nconst logger = new Logger({ level: 'warn', bizName: 'workspace:resource' });\n\nexport interface IBaseResource<T> extends IBaseModelResource<T> {\n  readonly resourceType: ResourceType;\n\n  skeleton: ISkeleton;\n\n  description?: string;\n\n  get editorViews(): IPublicTypeEditorView[];\n\n  get defaultViewName(): string | undefined;\n\n  getEditorView(name: string): IPublicTypeEditorView | undefined;\n\n  import(schema: any): Promise<any>;\n\n  save(value: any): Promise<any>;\n\n  url(): Promise<string | undefined>;\n}\n\nexport type IResource = IBaseResource<IResource>;\n\nexport class Resource implements IResource {\n  private context: IBasicContext;\n\n  resourceTypeInstance: IPublicResourceTypeConfig;\n\n  editorViewMap: Map<string, IPublicTypeEditorView> = new Map<string, IPublicTypeEditorView>();\n\n  get name() {\n    return this.resourceType.name;\n  }\n\n  get viewName() {\n    return this.resourceData.viewName || (this.resourceData as any).viewType || this.defaultViewName;\n  }\n\n  get description() {\n    return this.resourceTypeInstance?.description;\n  }\n\n  get icon() {\n    return this.resourceData.icon || this.resourceTypeInstance?.icon;\n  }\n\n  get type() {\n    return this.resourceType.type;\n  }\n\n  get title(): string | undefined {\n    return this.resourceData.title || this.resourceTypeInstance.defaultTitle;\n  }\n\n  get id(): string | undefined {\n    return this.resourceData.id;\n  }\n\n  get options() {\n    return this.resourceData.options;\n  }\n\n  get category() {\n    return this.resourceData?.category;\n  }\n\n  get skeleton() {\n    return this.context.innerSkeleton;\n  }\n\n  children: IResource[];\n\n  get config() {\n    return this.resourceData.config;\n  }\n\n  constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) {\n    this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`, IPublicEnumPluginRegisterLevel.Resource);\n    this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext({\n      pluginName: '',\n    }), this.options);\n    this.init();\n    if (this.resourceTypeInstance.editorViews) {\n      this.resourceTypeInstance.editorViews.forEach((d: any) => {\n        this.editorViewMap.set(d.viewName, d);\n      });\n    }\n    if (!resourceType) {\n      logger.error(`resourceType[${resourceType}] is unValid.`);\n    }\n    this.children = this.resourceData?.children?.map(d => new Resource(d, this.workspace.getResourceType(d.resourceName || this.resourceType.name), this.workspace)) || [];\n  }\n\n  async init() {\n    await this.resourceTypeInstance.init?.();\n    await this.context.innerPlugins.init();\n  }\n\n  async import(schema: any) {\n    return await this.resourceTypeInstance.import?.(schema);\n  }\n\n  async url() {\n    return await this.resourceTypeInstance.url?.();\n  }\n\n  async save(value: any) {\n    return await this.resourceTypeInstance.save?.(value);\n  }\n\n  get editorViews() {\n    return this.resourceTypeInstance.editorViews;\n  }\n\n  get defaultViewName() {\n    return this.resourceTypeInstance.defaultViewName || this.resourceTypeInstance.defaultViewType;\n  }\n\n  getEditorView(name: string) {\n    return this.editorViewMap.get(name);\n  }\n}"
  },
  {
    "path": "packages/workspace/src/skeleton-context.ts",
    "content": "import { createContext } from 'react';\n\nexport const SkeletonContext = createContext<any>({} as any);\n"
  },
  {
    "path": "packages/workspace/src/view/editor-view.tsx",
    "content": "import { BuiltinLoading } from '@alilc/lowcode-designer';\nimport { engineConfig, observer } from '@alilc/lowcode-editor-core';\nimport {\n  Workbench,\n} from '@alilc/lowcode-editor-skeleton';\nimport { PureComponent } from 'react';\nimport { Context } from '../context/view-context';\n\nexport * from '../context/base-context';\n\n@observer\nexport class EditorView extends PureComponent<{\n  editorView: Context;\n  active: boolean;\n}, any> {\n  render() {\n    const { active } = this.props;\n    const editorView = this.props.editorView;\n    const skeleton = editorView.innerSkeleton;\n    if (!editorView.isInit) {\n      const Loading = engineConfig.get('loadingComponent', BuiltinLoading);\n      return <Loading />;\n    }\n\n    return (\n      <Workbench\n        skeleton={skeleton}\n        className={active ? 'active engine-editor-view' : 'engine-editor-view'}\n        topAreaItemClassName=\"engine-actionitem\"\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/workspace/src/view/resource-view.less",
    "content": ".workspace-resource-view {\n  display: flex;\n  position: absolute;\n  flex-direction: column;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n}\n\n.workspace-editor-body {\n  position: relative;\n  height: 100%;\n}"
  },
  {
    "path": "packages/workspace/src/view/resource-view.tsx",
    "content": "import { PureComponent } from 'react';\nimport { EditorView } from './editor-view';\nimport { observer } from '@alilc/lowcode-editor-core';\nimport { IResource } from '../resource';\nimport { IEditorWindow } from '../window';\nimport './resource-view.less';\nimport { TopArea } from '@alilc/lowcode-editor-skeleton';\n\n@observer\nexport class ResourceView extends PureComponent<{\n  window: IEditorWindow;\n  resource: IResource;\n}, any> {\n  render() {\n    const { skeleton } = this.props.resource;\n    const { editorViews } = this.props.window;\n    return (\n      <div className=\"workspace-resource-view\">\n        <TopArea area={skeleton.topArea} itemClassName=\"engine-actionitem\" />\n        <div className=\"workspace-editor-body\">\n          {\n            Array.from(editorViews.values()).map((editorView: any) => {\n              return (\n                <EditorView\n                  key={editorView.name}\n                  active={editorView.active}\n                  editorView={editorView}\n                />\n              );\n            })\n          }\n        </div>\n      </div>\n    );\n  }\n}"
  },
  {
    "path": "packages/workspace/src/view/window-view.tsx",
    "content": "import { PureComponent } from 'react';\nimport { ResourceView } from './resource-view';\nimport { engineConfig, observer } from '@alilc/lowcode-editor-core';\nimport { EditorWindow } from '../window';\nimport { BuiltinLoading } from '@alilc/lowcode-designer';\nimport { DesignerView } from '../inner-plugins/webview';\n\n@observer\nexport class WindowView extends PureComponent<{\n  window: EditorWindow;\n  active: boolean;\n}, any> {\n  render() {\n    const { active } = this.props;\n    const { resource, initReady, url } = this.props.window;\n\n    if (!initReady) {\n      const Loading = engineConfig.get('loadingComponent', BuiltinLoading);\n      return (\n        <div className={`workspace-engine-main ${active ? 'active' : ''}`}>\n          <Loading />\n        </div>\n      );\n    }\n\n    if (resource.type === 'webview' && url) {\n      return <DesignerView url={url} viewName={resource.name} />;\n    }\n\n    return (\n      <div className={`workspace-engine-main ${active ? 'active' : ''}`}>\n        <ResourceView\n          resource={resource}\n          window={this.props.window}\n        />\n      </div>\n    );\n  }\n}"
  },
  {
    "path": "packages/workspace/src/window.ts",
    "content": "import { uniqueId } from '@alilc/lowcode-utils';\nimport { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';\nimport { Context, IViewContext } from './context/view-context';\nimport { IWorkspace } from './workspace';\nimport { IResource } from './resource';\nimport { IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types';\n\ninterface IWindowCOnfig {\n  title: string | undefined;\n  options?: Object;\n  viewName?: string | undefined;\n  sleep?: boolean;\n}\n\nexport interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType' | 'currentEditorView' | 'editorViews'> {\n  readonly resource: IResource;\n\n  editorViews: Map<string, IViewContext>;\n\n  _editorView: IViewContext;\n\n  changeViewName: (name: string, ignoreEmit?: boolean) => void;\n\n  initReady: boolean;\n\n  sleep?: boolean;\n\n  init(): void;\n\n  updateState(state: WINDOW_STATE): void;\n}\n\nexport enum WINDOW_STATE {\n  // 睡眠\n  sleep = 'sleep',\n\n  // 激活\n  active = 'active',\n\n  // 未激活\n  inactive = 'inactive',\n\n  // 销毁\n  destroyed = 'destroyed'\n}\n\nexport class EditorWindow implements IEditorWindow {\n  id: string = uniqueId('window');\n  icon: React.ReactElement | undefined;\n\n  private emitter: IEventBus = createModuleEventBus('Project');\n\n  title: string | undefined;\n\n  url: string | undefined;\n\n  @obx.ref _editorView: Context;\n\n  @obx editorViews: Map<string, Context> = new Map<string, Context>();\n\n  @obx initReady = false;\n\n  sleep: boolean | undefined;\n\n  get editorView() {\n    if (!this._editorView) {\n      return this.editorViews.values().next().value;\n    }\n    return this._editorView;\n  }\n\n  constructor(readonly resource: IResource, readonly workspace: IWorkspace, private config: IWindowCOnfig) {\n    makeObservable(this);\n    this.title = config.title;\n    this.icon = resource.icon;\n    this.sleep = config.sleep;\n    if (config.sleep) {\n      this.updateState(WINDOW_STATE.sleep);\n    }\n  }\n\n  updateState(state: WINDOW_STATE): void {\n    switch (state) {\n      case WINDOW_STATE.active:\n        this._editorView?.setActivate(true);\n        break;\n      case WINDOW_STATE.inactive:\n        this._editorView?.setActivate(false);\n        break;\n      case WINDOW_STATE.destroyed:\n        break;\n    }\n  }\n\n  async importSchema(schema: any) {\n    const newSchema = await this.resource.import(schema);\n\n    if (!newSchema) {\n      return;\n    }\n\n    Object.keys(newSchema).forEach(key => {\n      const view = this.editorViews.get(key);\n      view?.project.importSchema(newSchema[key]);\n    });\n  }\n\n  async save() {\n    const value: any = {};\n    const editorViews = this.resource.editorViews;\n    if (!editorViews) {\n      return;\n    }\n    for (let i = 0; i < editorViews.length; i++) {\n      const name = editorViews[i].viewName;\n      const saveResult = await this.editorViews.get(name)?.save();\n      value[name] = saveResult;\n    }\n    const result = await this.resource.save(value);\n    this.emitter.emit('handle.save');\n\n    return result;\n  }\n\n  onSave(fn: () => void) {\n    this.emitter.on('handle.save', fn);\n\n    return () => {\n      this.emitter.off('handle.save', fn);\n    };\n  }\n\n  async init() {\n    await this.initViewTypes();\n    await this.execViewTypesInit();\n    Promise.all(Array.from(this.editorViews.values()).map((d) => d.onSimulatorRendererReady()))\n      .then(() => {\n        this.workspace.emitWindowRendererReady();\n      });\n    this.url = await this.resource.url();\n    this.setDefaultViewName();\n    this.initReady = true;\n    this.workspace.checkWindowQueue();\n    this.sleep = false;\n    this.updateState(WINDOW_STATE.active);\n  }\n\n  initViewTypes = async () => {\n    const editorViews = this.resource.editorViews;\n    if (!editorViews) {\n      return;\n    }\n    for (let i = 0; i < editorViews.length; i++) {\n      const name = editorViews[i].viewName;\n      await this.initViewType(name);\n      if (!this._editorView) {\n        this.changeViewName(name);\n      }\n    }\n  };\n\n  onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable {\n    this.emitter.on('window.change.view.type', fn);\n\n    return () => {\n      this.emitter.off('window.change.view.type', fn);\n    };\n  }\n\n  execViewTypesInit = async () => {\n    const editorViews = this.resource.editorViews;\n    if (!editorViews) {\n      return;\n    }\n    for (let i = 0; i < editorViews.length; i++) {\n      const name = editorViews[i].viewName;\n      this.changeViewName(name);\n      await this.editorViews.get(name)?.init();\n    }\n  };\n\n  setDefaultViewName = () => {\n    this.changeViewName(this.config.viewName ?? this.resource.defaultViewName!);\n  };\n\n  get resourceType() {\n    return this.resource.resourceType.type;\n  }\n\n  initViewType = async (name: string) => {\n    const viewInfo = this.resource.getEditorView(name);\n    if (this.editorViews.get(name)) {\n      return;\n    }\n    const editorView = new Context(this.workspace, this, viewInfo as any, this.config.options);\n    this.editorViews.set(name, editorView);\n  };\n\n  changeViewName = (name: string, ignoreEmit: boolean = true) => {\n    this._editorView?.setActivate(false);\n    this._editorView = this.editorViews.get(name)!;\n\n    if (!this._editorView) {\n      return;\n    }\n\n    this._editorView.setActivate(true);\n\n    if (!ignoreEmit) {\n      this.emitter.emit('window.change.view.type', name);\n\n      if (this.id === this.workspace.window.id) {\n        this.workspace.emitChangeActiveEditorView();\n      }\n    }\n  };\n\n  get project() {\n    return this.editorView?.project;\n  }\n\n  get innerProject() {\n    return this.editorView?.innerProject;\n  }\n\n  get innerSkeleton() {\n    return this.editorView?.innerSkeleton;\n  }\n\n  get innerSetters() {\n    return this.editorView?.innerSetters;\n  }\n\n  get innerHotkey() {\n    return this.editorView?.innerHotkey;\n  }\n\n  get editor() {\n    return this.editorView?.editor;\n  }\n\n  get designer() {\n    return this.editorView?.designer;\n  }\n\n  get plugins() {\n    return this.editorView?.plugins;\n  }\n\n  get innerPlugins() {\n    return this.editorView?.innerPlugins;\n  }\n}"
  },
  {
    "path": "packages/workspace/src/workspace.ts",
    "content": "import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/lowcode-designer';\nimport { createModuleEventBus, Editor, IEditor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';\nimport { IPublicApiPlugins, IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types';\nimport { BasicContext } from './context/base-context';\nimport { EditorWindow, WINDOW_STATE } from './window';\nimport type { IEditorWindow } from './window';\nimport { IResource, Resource } from './resource';\nimport { IResourceType, ResourceType } from './resource-type';\nimport { ISkeleton } from '@alilc/lowcode-editor-skeleton';\n\nenum EVENT {\n  CHANGE_WINDOW = 'change_window',\n\n  CHANGE_ACTIVE_WINDOW = 'change_active_window',\n\n  WINDOW_RENDER_READY = 'window_render_ready',\n\n  CHANGE_ACTIVE_EDITOR_VIEW = 'change_active_editor_view',\n}\n\nconst CHANGE_EVENT = 'resource.list.change';\n\nexport interface IWorkspace extends Omit<IPublicApiWorkspace<\n  LowCodePluginManager,\n  IEditorWindow\n>, 'resourceList' | 'plugins' | 'openEditorWindow' | 'removeEditorWindow'> {\n  readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>;\n\n  readonly shellModelFactory: IShellModelFactory;\n\n  enableAutoOpenFirstWindow: boolean;\n\n  window: IEditorWindow;\n\n  plugins: ILowCodePluginManager;\n\n  skeleton: ISkeleton;\n\n  resourceTypeMap: Map<string, ResourceType>;\n\n  getResourceList(): IResource[];\n\n  getResourceType(resourceName: string): IResourceType;\n\n  checkWindowQueue(): void;\n\n  emitWindowRendererReady(): void;\n\n  initWindow(): void;\n\n  setActive(active: boolean): void;\n\n  onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable;\n\n  emitChangeActiveEditorView(): void;\n\n  openEditorWindowByResource(resource: IResource, sleep: boolean): Promise<void>;\n\n  /**\n   * @deprecated\n   */\n  removeEditorWindow(resourceName: string, id: string): void;\n\n  removeEditorWindowByResource(resource: IResource): void;\n\n  /**\n   * @deprecated\n   */\n  openEditorWindow(name: string, title: string, options: Object, viewName?: string, sleep?: boolean): Promise<void>;\n}\n\nexport class Workspace implements IWorkspace {\n  context: BasicContext;\n\n  enableAutoOpenFirstWindow: boolean;\n\n  resourceTypeMap: Map<string, ResourceType> = new Map();\n\n  private emitter: IEventBus = createModuleEventBus('workspace');\n\n  private _isActive = false;\n\n  private resourceList: IResource[] = [];\n\n  get skeleton() {\n    return this.context.innerSkeleton;\n  }\n\n  get plugins() {\n    return this.context.innerPlugins;\n  }\n\n  get isActive() {\n    return this._isActive;\n  }\n\n  get defaultResourceType(): ResourceType | null {\n    if (this.resourceTypeMap.size >= 1) {\n      return Array.from(this.resourceTypeMap.values())[0];\n    }\n\n    return null;\n  }\n\n  @obx.ref windows: IEditorWindow[] = [];\n\n  editorWindowMap: Map<string, IEditorWindow> = new Map<string, IEditorWindow>();\n\n  @obx.ref window: IEditorWindow;\n\n  windowQueue: ({\n    name: string;\n    title: string;\n    options: Object;\n    viewName?: string;\n  } | IResource)[] = [];\n\n  constructor(\n    readonly registryInnerPlugin: (designer: IDesigner, editor: IEditor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>,\n    readonly shellModelFactory: any,\n  ) {\n    this.context = new BasicContext(this, '', IPublicEnumPluginRegisterLevel.Workspace);\n    this.context.innerHotkey.activate(true);\n    makeObservable(this);\n  }\n\n  checkWindowQueue() {\n    if (!this.windowQueue || !this.windowQueue.length) {\n      return;\n    }\n\n    const windowInfo = this.windowQueue.shift();\n    if (windowInfo instanceof Resource) {\n      this.openEditorWindowByResource(windowInfo);\n    } else if (windowInfo) {\n      this.openEditorWindow(windowInfo.name, windowInfo.title, windowInfo.options, windowInfo.viewName);\n    }\n  }\n\n  async initWindow() {\n    if (!this.defaultResourceType || this.enableAutoOpenFirstWindow === false) {\n      return;\n    }\n    const resourceName = this.defaultResourceType.name;\n    const resource = new Resource({\n      resourceName,\n      options: {},\n    }, this.defaultResourceType, this);\n    this.window = new EditorWindow(resource, this, {\n      title: resource.title,\n    });\n    await this.window.init();\n    this.editorWindowMap.set(this.window.id, this.window);\n    this.windows = [...this.windows, this.window];\n    this.emitChangeWindow();\n    this.emitChangeActiveWindow();\n  }\n\n  setActive(value: boolean) {\n    this._isActive = value;\n  }\n\n  async registerResourceType(resourceTypeModel: IPublicTypeResourceType): Promise<void> {\n    const resourceType = new ResourceType(resourceTypeModel);\n    this.resourceTypeMap.set(resourceTypeModel.resourceName, resourceType);\n\n    if (!this.window && this.defaultResourceType && this._isActive) {\n      this.initWindow();\n    }\n  }\n\n  getResourceList() {\n    return this.resourceList;\n  }\n\n  setResourceList(resourceList: IPublicResourceList) {\n    this.resourceList = resourceList.map(d => new Resource(d, this.getResourceType(d.resourceName), this));\n    this.emitter.emit(CHANGE_EVENT, resourceList);\n  }\n\n  onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => void {\n    this.emitter.on(CHANGE_EVENT, fn);\n    return () => {\n      this.emitter.off(CHANGE_EVENT, fn);\n    };\n  }\n\n  onWindowRendererReady(fn: () => void): IPublicTypeDisposable {\n    this.emitter.on(EVENT.WINDOW_RENDER_READY, fn);\n    return () => {\n      this.emitter.off(EVENT.WINDOW_RENDER_READY, fn);\n    };\n  }\n\n  emitWindowRendererReady() {\n    this.emitter.emit(EVENT.WINDOW_RENDER_READY);\n  }\n\n  getResourceType(resourceName: string): IResourceType {\n    return this.resourceTypeMap.get(resourceName)!;\n  }\n\n  removeResourceType(resourceName: string) {\n    if (this.resourceTypeMap.has(resourceName)) {\n      this.resourceTypeMap.delete(resourceName);\n    }\n  }\n\n  removeEditorWindowById(id: string) {\n    const index = this.windows.findIndex(d => (d.id === id));\n    this.remove(index);\n  }\n\n  private async remove(index: number) {\n    if (index < 0) {\n      return;\n    }\n    const window = this.windows[index];\n    this.windows.splice(index, 1);\n    this.window?.updateState(WINDOW_STATE.destroyed);\n    if (this.window === window) {\n      this.window = this.windows[index] || this.windows[index + 1] || this.windows[index - 1];\n      if (this.window?.sleep) {\n        await this.window.init();\n      }\n      this.emitChangeActiveWindow();\n    }\n    this.emitChangeWindow();\n    this.window?.updateState(WINDOW_STATE.active);\n  }\n\n  removeEditorWindow(resourceName: string, id: string) {\n    const index = this.windows.findIndex(d => (d.resource?.name === resourceName && (d.title === id || d.resource.id === id)));\n    this.remove(index);\n  }\n\n  removeEditorWindowByResource(resource: IResource) {\n    const index = this.windows.findIndex(d => (d.resource?.id === resource.id));\n    this.remove(index);\n  }\n\n  async openEditorWindowById(id: string) {\n    const window = this.editorWindowMap.get(id);\n    this.window?.updateState(WINDOW_STATE.inactive);\n    if (window) {\n      this.window = window;\n      if (window.sleep) {\n        await window.init();\n      }\n      this.emitChangeActiveWindow();\n    }\n    this.window?.updateState(WINDOW_STATE.active);\n  }\n\n  async openEditorWindowByResource(resource: IResource, sleep: boolean = false): Promise<void> {\n    if (this.window && !this.window.sleep && !this.window?.initReady && !sleep) {\n      this.windowQueue.push(resource);\n      return;\n    }\n\n    this.window?.updateState(WINDOW_STATE.inactive);\n\n    const filterWindows = this.windows.filter(d => (d.resource?.id === resource.id));\n    if (filterWindows && filterWindows.length) {\n      this.window = filterWindows[0];\n      if (!sleep && this.window.sleep) {\n        await this.window.init();\n      } else {\n        this.checkWindowQueue();\n      }\n      this.emitChangeActiveWindow();\n      this.window?.updateState(WINDOW_STATE.active);\n      return;\n    }\n\n    const window = new EditorWindow(resource, this, {\n      title: resource.title,\n      options: resource.options,\n      viewName: resource.viewName,\n      sleep,\n    });\n\n    this.windows = [...this.windows, window];\n    this.editorWindowMap.set(window.id, window);\n    if (sleep) {\n      this.emitChangeWindow();\n      return;\n    }\n    this.window = window;\n    await this.window.init();\n    this.emitChangeWindow();\n    this.emitChangeActiveWindow();\n    this.window?.updateState(WINDOW_STATE.active);\n  }\n\n  async openEditorWindow(name: string, title: string, options: Object, viewName?: string, sleep?: boolean) {\n    if (this.window && !this.window.sleep && !this.window?.initReady && !sleep) {\n      this.windowQueue.push({\n        name, title, options, viewName,\n      });\n      return;\n    }\n    const resourceType = this.resourceTypeMap.get(name);\n    if (!resourceType) {\n      console.error(`${name} resourceType is not available`);\n      return;\n    }\n    this.window?.updateState(WINDOW_STATE.inactive);\n    const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title) || (d.resource.id == title));\n    if (filterWindows && filterWindows.length) {\n      this.window = filterWindows[0];\n      if (!sleep && this.window.sleep) {\n        await this.window.init();\n      } else {\n        this.checkWindowQueue();\n      }\n      this.emitChangeActiveWindow();\n      this.window?.updateState(WINDOW_STATE.active);\n      return;\n    }\n    const resource = new Resource({\n      resourceName: name,\n      title,\n      options,\n      id: title?.toString(),\n    }, resourceType, this);\n    const window = new EditorWindow(resource, this, {\n      title,\n      options,\n      viewName,\n      sleep,\n    });\n    this.windows = [...this.windows, window];\n    this.editorWindowMap.set(window.id, window);\n    if (sleep) {\n      this.emitChangeWindow();\n      return;\n    }\n    this.window = window;\n    await this.window.init();\n    this.emitChangeWindow();\n    this.emitChangeActiveWindow();\n    this.window?.updateState(WINDOW_STATE.active);\n  }\n\n  onChangeWindows(fn: () => void) {\n    this.emitter.on(EVENT.CHANGE_WINDOW, fn);\n    return () => {\n      this.emitter.removeListener(EVENT.CHANGE_WINDOW, fn);\n    };\n  }\n\n  onChangeActiveEditorView(fn: () => void) {\n    this.emitter.on(EVENT.CHANGE_ACTIVE_EDITOR_VIEW, fn);\n    return () => {\n      this.emitter.removeListener(EVENT.CHANGE_ACTIVE_EDITOR_VIEW, fn);\n    };\n  }\n\n  emitChangeActiveEditorView() {\n    this.emitter.emit(EVENT.CHANGE_ACTIVE_EDITOR_VIEW);\n  }\n\n  emitChangeWindow() {\n    this.emitter.emit(EVENT.CHANGE_WINDOW);\n  }\n\n  emitChangeActiveWindow() {\n    this.emitter.emit(EVENT.CHANGE_ACTIVE_WINDOW);\n    this.emitChangeActiveEditorView();\n  }\n\n  onChangeActiveWindow(fn: () => void) {\n    this.emitter.on(EVENT.CHANGE_ACTIVE_WINDOW, fn);\n    return () => {\n      this.emitter.removeListener(EVENT.CHANGE_ACTIVE_WINDOW, fn);\n    };\n  }\n}\n"
  },
  {
    "path": "packages/workspace/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\n    \"./src/\"\n  ]\n}\n"
  },
  {
    "path": "scripts/build.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\n\nlerna run build \\\n  --scope @alilc/lowcode-types \\\n  --scope @alilc/lowcode-utils \\\n  --scope @alilc/lowcode-shell \\\n  --scope @alilc/lowcode-editor-core \\\n  --scope @alilc/lowcode-editor-skeleton \\\n  --scope @alilc/lowcode-designer \\\n  --scope @alilc/lowcode-plugin-designer \\\n  --scope @alilc/lowcode-plugin-command \\\n  --scope @alilc/lowcode-plugin-outline-pane \\\n  --scope @alilc/lowcode-react-renderer \\\n  --scope @alilc/lowcode-react-simulator-renderer \\\n  --scope @alilc/lowcode-renderer-core \\\n  --scope @alilc/lowcode-workspace \\\n  --scope @alilc/lowcode-engine \\\n  --stream\n\nlerna run build:umd \\\n  --scope @alilc/lowcode-engine \\\n  --scope @alilc/lowcode-react-simulator-renderer \\\n  --scope @alilc/lowcode-react-renderer \\\n  --stream\n\ncp ./packages/react-simulator-renderer/dist/js/* ./packages/engine/dist/js/\ncp ./packages/react-simulator-renderer/dist/css/* ./packages/engine/dist/css/\n"
  },
  {
    "path": "scripts/create.sh",
    "content": "#!/usr/bin/env bash\n\nDIR_NAME=$1\n\nif [ -z $DIR_NAME ];then\n  echo 'Usage: ./create.sh <folder-name>'\n  exit 0\nfi\n\nif [ -d packages/$DIR_NAME ];then\n  echo 'Folder is existing!'\n  exit 0\nfi\n\nmkdir packages/$DIR_NAME\n\ncp -r templates/* packages/$DIR_NAME\n\nmv packages/$DIR_NAME/_tsconfig.json packages/$DIR_NAME/tsconfig.json\n\necho 'Add package successfully.'\n"
  },
  {
    "path": "scripts/set-repo.js",
    "content": "#!/usr/bin/env node\n\nconst path = require('path');\nconst fs = require('fs-extra');\n\n(async () => {\n    const root = path.join(__dirname, '../');\n    const workspaces = ['modules', 'packages'];\n    for (const workspace of workspaces) {\n        const pkgDir = path.join(root, workspace);\n        const pkgs = await fs.readdir(pkgDir);\n        for (const pkg of pkgs) {\n            if (pkg.charAt(0) === '.') continue;\n            if (!(await fs.statSync(path.join(pkgDir, pkg))).isDirectory()) continue;\n            await setRepo({\n                workspace,\n                pkgDir,\n                pkg,\n            });\n        }\n    }\n\n    async function setRepo(opts) {\n        const pkgDir = path.join(opts.pkgDir, opts.pkg);\n        const pkgPkgJSONPath = path.join(pkgDir, 'package.json');\n        if (!fs.existsSync(pkgPkgJSONPath)) {\n            console.log(`${opts.pkg} exists`);\n        } else {\n            const pkgPkgJSON = require(pkgPkgJSONPath);\n            fs.writeJSONSync(\n                pkgPkgJSONPath,\n                Object.assign(pkgPkgJSON, {\n                    repository: {\n                        type: 'http',\n                        url: `https://github.com/alibaba/lowcode-engine/tree/main/${opts.workspace}/${opts.pkg}`,\n                    },\n                    bugs: 'https://github.com/alibaba/lowcode-engine/issues',\n                    homepage: 'https://github.com/alibaba/lowcode-engine/#readme',\n                }),\n                { spaces: '  ' },\n            );\n            console.log(`[Write] ${opts.pkg}`);\n        }\n    }\n})();\n"
  },
  {
    "path": "scripts/setup-for-test.sh",
    "content": "#!/usr/bin/env bash\n\nrm -rf node_modules package-lock.json yarn.lock\nlerna clean -y\nfind ./packages -type f -name \"package-lock.json\" -exec rm -f {} \\;\n\nlerna bootstrap\n\nlerna exec --stream \\\n  --scope @alilc/lowcode-editor-core \\\n  --scope @alilc/lowcode-types \\\n  --scope @alilc/lowcode-utils \\\n  -- npm run build\n"
  },
  {
    "path": "scripts/setup-skip-build.sh",
    "content": "#!/usr/bin/env bash\n\nrm -rf node_modules package-lock.json yarn.lock\n\nnpm i lerna@4.0.0\n\nlerna clean -y\nfind ./packages -type f -name \"package-lock.json\" -exec rm -f {} \\;\n\nlerna bootstrap\n"
  },
  {
    "path": "scripts/setup.js",
    "content": "#!/usr/bin/env node\nconst os = require('os');\nconst del = require('del');\nconst gulp = require('gulp');\nconst execa = require('execa');\n\nasync function deleteRootDirLockFile() {\n    await del('package-lock.json');\n    await del('yarn.lock');\n}\n\nasync function clean() {\n    await execa.command('lerna clean -y', { stdio: 'inherit', encoding: 'utf-8' });\n}\n\nasync function deletePackagesDirLockFile() {\n    await del('packages/**/package-lock.json');\n}\n\nasync function bootstrap() {\n    await execa.command('lerna bootstrap --force-local', { stdio: 'inherit', encoding: 'utf-8' });\n}\n\nconst setup = gulp.series(deleteRootDirLockFile, clean, deletePackagesDirLockFile, bootstrap);\n\nos.type() === 'Windows_NT' ? setup() : execa.command('scripts/setup.sh', { stdio: 'inherit', encoding: 'utf-8' });"
  },
  {
    "path": "scripts/setup.sh",
    "content": "#!/usr/bin/env bash\n\nrm -rf package-lock.json yarn.lock\nlerna clean -y\nfind ./packages -type f -name \"package-lock.json\" -exec rm -f {} \\;\n\nlerna bootstrap --force-local\n"
  },
  {
    "path": "scripts/start-server.sh",
    "content": "#!/usr/bin/env bash\n\n# FIXME! do not run build\nlerna exec --scope @ali/lowcode-code-generator -- npm run build\n# lerna exec --scope @ali/lowcode-demo-server -- npm start\n"
  },
  {
    "path": "scripts/start.js",
    "content": "#!/usr/bin/env node\nconst os = require('os');\nconst execa = require('execa');\n\nasync function start() {\n    const [, , pkgName = '@alilc/lowcode-ignitor'] = process.argv;\n    await execa.command(`lerna exec --scope ${pkgName} -- npm start`, { stdio: 'inherit', encoding: 'utf-8' });\n}\n\nos.type() === 'Windows_NT' ? start() : execa.command('scripts/start.sh', { stdio: 'inherit', encoding: 'utf-8' });\n"
  },
  {
    "path": "scripts/start.sh",
    "content": "#!/usr/bin/env bash\n\npkgName=\"@alilc/lowcode-ignitor\"\n\nif [ \"$1\" ]; then\n  pkgName=\"$1\"\nfi\n\nlerna exec --scope $pkgName -- npm start\n"
  },
  {
    "path": "scripts/sync-oss.js",
    "content": "#!/usr/bin/env node\nconst http = require('http');\nconst package = require('../packages/engine/package.json');\nconst { version, name } = package;\nconst options = {\n  method: 'PUT',\n  hostname: 'uipaas-node.alibaba-inc.com',\n  path: '/staticAssets/cdn/packages',\n  headers: {\n    'Content-Type': 'application/json',\n    Cookie: 'locale=en-us',\n  },\n  maxRedirects: 20,\n};\n\nconst onResponse = function (res) {\n  const chunks = [];\n  res.on('data', (chunk) => {\n    chunks.push(chunk);\n  });\n\n  res.on('end', () => {\n    const body = Buffer.concat(chunks);\n    console.table(JSON.stringify(JSON.parse(body.toString()), null, 2));\n  });\n\n  res.on('error', (error) => {\n    console.error(error);\n  });\n};\n\nconst req = http.request(options, onResponse);\n\nconst postData = JSON.stringify({\n  packages: [\n    {\n      packageName: name,\n      version,\n    },\n  ],\n  // 可以发布指定源的 npm 包，默认公网 npm\n  useTnpm: true,\n});\n\nreq.write(postData);\n\nreq.end();\n"
  },
  {
    "path": "scripts/sync.sh",
    "content": "#!/usr/bin/env bash\n\n# sync all packages to alibaba intranet registry\ntnpm sync @alilc/lowcode-types\ntnpm sync @alilc/lowcode-utils\ntnpm sync @alilc/lowcode-shell\ntnpm sync @alilc/lowcode-editor-core\ntnpm sync @alilc/lowcode-editor-skeleton\ntnpm sync @alilc/lowcode-designer\ntnpm sync @alilc/lowcode-plugin-designer\ntnpm sync @alilc/lowcode-plugin-outline-pane\ntnpm sync @alilc/lowcode-renderer-core\ntnpm sync @alilc/lowcode-react-renderer\ntnpm sync @alilc/lowcode-react-simulator-renderer\ntnpm sync @alilc/lowcode-engine\ntnpm sync @alilc/lowcode-workspace\ntnpm sync @alilc/lowcode-plugin-command"
  },
  {
    "path": "scripts/watchdog.js",
    "content": "#!/usr/bin/env node\nconst fs = require('fs');\nconst { join } = require('path');\n\nconst packagesDir = join(__dirname, '../packages');\nconst blacklistPkgNames = ['code-generator', 'material-parser'];\n\nconst dirs = fs.readdirSync(packagesDir);\ndirs\n  .filter(dir => {\n    return !dir.startsWith('.') && !blacklistPkgNames.includes(dir);\n  })\n  .forEach(dir => {\n    const pkgDir = join(packagesDir, dir);\n    const pkg = JSON.parse(fs.readFileSync(join(pkgDir, 'package.json'), 'utf-8'));\n    if (pkg.private) return;\n    const { files } = pkg;\n    files.forEach(file => {\n      const fileDir = join(pkgDir, file);\n      if (!fs.existsSync(fileDir)) {\n        throw new Error(`${fileDir} does not exist, plz run build`);\n      }\n    });\n  });\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"declaration\": true,\n    \"lib\": [\"es2015\", \"dom\"],\n    // Target latest version of ECMAScript.\n    \"target\": \"esnext\",\n    // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.\n    \"module\": \"esnext\",\n    // Search under node_modules for non-relative imports.\n    \"moduleResolution\": \"node\",\n    // Enable strictest settings like strictNullChecks & noImplicitAny.\n    \"strict\": true,\n    \"strictPropertyInitialization\": false,\n    // Allow default imports from modules with no default export. This does not affect code emit, just typechecking.\n    \"allowSyntheticDefaultImports\": true,\n    // Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.\n    \"esModuleInterop\": true,\n    // Specify JSX code generation: 'preserve', 'react-native', or 'react'.\n    \"jsx\": \"preserve\",\n    // Import emit helpers (e.g. __extends, __rest, etc..) from tslib\n    \"importHelpers\": true,\n    // Enables experimental support for ES7 decorators.\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    // Generates corresponding .map file.\n    \"sourceMap\": true,\n    // Disallow inconsistently-cased references to the same file.\n    \"forceConsistentCasingInFileNames\": true,\n    // Allow json import\n    \"resolveJsonModule\": true,\n    // skip type checking of declaration files\n    \"skipLibCheck\": true,\n    \"baseUrl\": \"./packages\",\n    \"useDefineForClassFields\": true,\n    \"paths\": {\n      \"@alilc/lowcode-*\": [\"./*/src\"]\n    },\n    \"outDir\": \"lib\"\n  },\n  \"exclude\": [\"**/tests/*\", \"**/*.test.ts\", \"**/lib\", \"**/es\", \"node_modules\"]\n}\n"
  }
]